mapdisp_window.py 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580
  1. """
  2. @package mapdisp_window.py
  3. @brief GIS map display canvas, buffered window.
  4. Classes:
  5. - MapWindow
  6. - BufferedWindow
  7. (C) 2006-2009 by the GRASS Development Team
  8. This program is free software under the GNU General Public
  9. License (>=v2). Read the file COPYING that comes with GRASS
  10. for details.
  11. @author Michael Barton
  12. @author Jachym Cepicky
  13. @author Martin Landa <landa.martin gmail.com>
  14. """
  15. import os
  16. import time
  17. import math
  18. import wx
  19. import dbm
  20. from debug import Debug
  21. from preferences import globalSettings as UserSettings
  22. from vdigit import GV_LINES as VDigit_Lines_Type
  23. from vdigit import VDigitCategoryDialog
  24. from vdigit import VDigitZBulkDialog
  25. from vdigit import VDigitDuplicatesDialog
  26. class MapWindow(object):
  27. """
  28. Abstract map window class
  29. Parent for BufferedWindow class (2D display mode) and
  30. GLWindow (3D display mode)
  31. """
  32. def __init__(self, parent, id=wx.ID_ANY,
  33. pos=wx.DefaultPosition,
  34. size=wx.DefaultSize,
  35. style=wx.NO_FULL_REPAINT_ON_RESIZE,
  36. Map=None, tree=None, gismgr=None):
  37. self.parent = parent # MapFrame
  38. #
  39. # mouse attributes -- position on the screen, begin and end of
  40. # dragging, and type of drawing
  41. #
  42. self.mouse = {
  43. 'begin': [0, 0], # screen coordinates
  44. 'end' : [0, 0],
  45. 'use' : "pointer",
  46. 'box' : "point"
  47. }
  48. def EraseMap(self):
  49. """
  50. Erase the canvas (virtual method)
  51. """
  52. pass
  53. def UpdateMap(self):
  54. """
  55. Updates the canvas anytime there is a change to the
  56. underlaying images or to the geometry of the canvas.
  57. """
  58. pass
  59. def OnLeftDown(self, event):
  60. pass
  61. def OnLeftUp(self, event):
  62. pass
  63. def OnMouseMotion(self, event):
  64. pass
  65. def OnZoomToMap(self, event):
  66. pass
  67. def OnZoomToRaster(self, event):
  68. pass
  69. def GetSelectedLayer(self, type='layer'):
  70. """
  71. Get selected layer from layer tree
  72. @param type 'item' / 'layer' / 'nviz'
  73. @return layer / map layer properties / nviz properties
  74. @return None on failure
  75. """
  76. # get currently selected map layer
  77. if not self.tree or not self.tree.GetSelection():
  78. return None
  79. item = self.tree.GetSelection()
  80. if not item.IsChecked():
  81. return None
  82. if type == 'item':
  83. return item
  84. try:
  85. if type == 'nviz':
  86. layer = self.tree.GetPyData(item)[0]['nviz']
  87. else:
  88. layer = self.tree.GetPyData(item)[0]['maplayer']
  89. except:
  90. layer = None
  91. return layer
  92. class BufferedWindow(MapWindow, wx.Window):
  93. """
  94. A Buffered window class.
  95. When the drawing needs to change, you app needs to call the
  96. UpdateMap() method. Since the drawing is stored in a bitmap, you
  97. can also save the drawing to file by calling the
  98. SaveToFile(self,file_name,file_type) method.
  99. """
  100. def __init__(self, parent, id,
  101. pos = wx.DefaultPosition,
  102. size = wx.DefaultSize,
  103. style=wx.NO_FULL_REPAINT_ON_RESIZE,
  104. Map=None, tree=None, gismgr=None):
  105. MapWindow.__init__(self, parent, id, pos, size, style,
  106. Map, tree, gismgr)
  107. wx.Window.__init__(self, parent, id, pos, size, style)
  108. self.Map = Map
  109. self.tree = tree
  110. self.gismanager = gismgr
  111. #
  112. # Flags
  113. #
  114. self.resize = False # indicates whether or not a resize event has taken place
  115. self.dragimg = None # initialize variable for map panning
  116. #
  117. # Variable for drawing on DC
  118. #
  119. self.pen = None # pen for drawing zoom boxes, etc.
  120. self.polypen = None # pen for drawing polylines (measurements, profiles, etc)
  121. # List of wx.Point tuples defining a polyline (geographical coordinates)
  122. self.polycoords = []
  123. # ID of rubber band line
  124. self.lineid = None
  125. # ID of poly line resulting from cumulative rubber band lines (e.g. measurement)
  126. self.plineid = None
  127. #
  128. # Event bindings
  129. #
  130. self.Bind(wx.EVT_PAINT, self.OnPaint)
  131. self.Bind(wx.EVT_SIZE, self.OnSize)
  132. self.Bind(wx.EVT_IDLE, self.OnIdle)
  133. self.Bind(wx.EVT_MOTION, self.MouseActions)
  134. self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
  135. self.processMouse = True
  136. #
  137. # Render output objects
  138. #
  139. self.mapfile = None # image file to be rendered
  140. self.img = "" # wx.Image object (self.mapfile)
  141. # used in digitization tool (do not redraw vector map)
  142. self.imgVectorMap = None
  143. # decoration overlays
  144. self.overlays = {}
  145. # images and their PseudoDC ID's for painting and dragging
  146. self.imagedict = {}
  147. self.select = {} # selecting/unselecting decorations for dragging
  148. self.textdict = {} # text, font, and color indexed by id
  149. self.currtxtid = None # PseudoDC id for currently selected text
  150. #
  151. # Zoom objects
  152. #
  153. self.zoomhistory = [] # list of past zoom extents
  154. self.currzoom = 0 # current set of extents in zoom history being used
  155. self.zoomtype = 1 # 1 zoom in, 0 no zoom, -1 zoom out
  156. self.hitradius = 10 # distance for selecting map decorations
  157. self.dialogOffset = 5 # offset for dialog (e.g. DisplayAttributesDialog)
  158. # OnSize called to make sure the buffer is initialized.
  159. # This might result in OnSize getting called twice on some
  160. # platforms at initialization, but little harm done.
  161. ### self.OnSize(None)
  162. # create PseudoDC used for background map, map decorations like scales and legends
  163. self.pdc = wx.PseudoDC()
  164. # used for digitization tool
  165. self.pdcVector = None
  166. # decorations (region box, etc.)
  167. self.pdcDec = wx.PseudoDC()
  168. # pseudoDC for temporal objects (select box, measurement tool, etc.)
  169. self.pdcTmp = wx.PseudoDC()
  170. # redraw all pdc's, pdcTmp layer is redrawn always (speed issue)
  171. self.redrawAll = True
  172. # will store an off screen empty bitmap for saving to file
  173. self._buffer = ''
  174. self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
  175. # vars for handling mouse clicks
  176. self.dragid = -1
  177. self.lastpos = (0, 0)
  178. def Draw(self, pdc, img=None, drawid=None, pdctype='image', coords=[0, 0, 0, 0]):
  179. """
  180. Draws map and overlay decorations
  181. """
  182. if drawid == None:
  183. if pdctype == 'image' and img:
  184. drawid = self.imagedict[img]
  185. elif pdctype == 'clear':
  186. drawid == None
  187. else:
  188. drawid = wx.NewId()
  189. if img and pdctype == 'image':
  190. # self.imagedict[img]['coords'] = coords
  191. self.select[self.imagedict[img]['id']] = False # ?
  192. pdc.BeginDrawing()
  193. if drawid != 99:
  194. bg = wx.TRANSPARENT_BRUSH
  195. else:
  196. bg = wx.Brush(self.GetBackgroundColour())
  197. pdc.SetBackground(bg)
  198. ### pdc.Clear()
  199. Debug.msg (5, "BufferedWindow.Draw(): id=%s, pdctype=%s, coord=%s" % \
  200. (drawid, pdctype, coords))
  201. # set PseudoDC id
  202. if drawid is not None:
  203. pdc.SetId(drawid)
  204. if pdctype == 'clear': # erase the display
  205. bg = wx.WHITE_BRUSH
  206. # bg = wx.Brush(self.GetBackgroundColour())
  207. pdc.SetBackground(bg)
  208. pdc.RemoveAll()
  209. pdc.Clear()
  210. pdc.EndDrawing()
  211. self.Refresh()
  212. return
  213. if pdctype == 'image': # draw selected image
  214. bitmap = wx.BitmapFromImage(img)
  215. w,h = bitmap.GetSize()
  216. pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
  217. pdc.SetIdBounds(drawid, (coords[0],coords[1], w, h))
  218. elif pdctype == 'box': # draw a box on top of the map
  219. if self.pen:
  220. pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
  221. pdc.SetPen(self.pen)
  222. x2 = max(coords[0],coords[2])
  223. x1 = min(coords[0],coords[2])
  224. y2 = max(coords[1],coords[3])
  225. y1 = min(coords[1],coords[3])
  226. rwidth = x2-x1
  227. rheight = y2-y1
  228. rect = wx.Rect(x1,y1,rwidth,rheight)
  229. pdc.DrawRectangleRect(rect)
  230. pdc.SetIdBounds(drawid,rect)
  231. # self.ovlcoords[drawid] = coords
  232. elif pdctype == 'line': # draw a line on top of the map
  233. if self.pen:
  234. pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
  235. pdc.SetPen(self.pen)
  236. pdc.DrawLine(coords[0], coords[1], coords[2], coords[3])
  237. pdc.SetIdBounds(drawid,(coords[0], coords[1], coords[2], coords[3]))
  238. # self.ovlcoords[drawid] = coords
  239. elif pdctype == 'polyline': # draw a polyline on top of the map
  240. if self.polypen:
  241. pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
  242. pdc.SetPen(self.polypen)
  243. pdc.DrawLines(coords)
  244. # get bounding rectangle for polyline
  245. xlist = []
  246. ylist = []
  247. if len(coords) > 0:
  248. for point in coords:
  249. x,y = point
  250. xlist.append(x)
  251. ylist.append(y)
  252. x1=min(xlist)
  253. x2=max(xlist)
  254. y1=min(ylist)
  255. y2=max(ylist)
  256. pdc.SetIdBounds(drawid,(x1,y1,x2,y2))
  257. # self.ovlcoords[drawid] = [x1,y1,x2,y2]
  258. elif pdctype == 'point': # draw point
  259. if self.pen:
  260. pdc.SetPen(self.pen)
  261. pdc.DrawPoint(coords[0], coords[1])
  262. coordsBound = (coords[0] - 5,
  263. coords[1] - 5,
  264. coords[0] + 5,
  265. coords[1] + 5)
  266. pdc.SetIdBounds(drawid, coordsBound)
  267. # self.ovlcoords[drawid] = coords
  268. elif pdctype == 'text': # draw text on top of map
  269. if not img['active']:
  270. return #only draw active text
  271. if img.has_key('rotation'):
  272. rotation = float(img['rotation'])
  273. else:
  274. rotation = 0.0
  275. w, h = self.GetFullTextExtent(img['text'])[0:2]
  276. pdc.SetFont(img['font'])
  277. pdc.SetTextForeground(img['color'])
  278. coords, w, h = self.TextBounds(img)
  279. if rotation == 0:
  280. pdc.DrawText(img['text'], coords[0], coords[1])
  281. else:
  282. pdc.DrawRotatedText(img['text'], coords[0], coords[1], rotation)
  283. pdc.SetIdBounds(drawid, (coords[0], coords[1], w, h))
  284. pdc.EndDrawing()
  285. self.Refresh()
  286. return drawid
  287. def TextBounds(self, textinfo):
  288. """
  289. Return text boundary data
  290. @param textinfo text metadata (text, font, color, rotation)
  291. @param coords reference point
  292. """
  293. if textinfo.has_key('rotation'):
  294. rotation = float(textinfo['rotation'])
  295. else:
  296. rotation = 0.0
  297. coords = textinfo['coords']
  298. Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
  299. (textinfo['text'], rotation))
  300. self.Update()
  301. ### self.Refresh()
  302. self.SetFont(textinfo['font'])
  303. w, h = self.GetTextExtent(textinfo['text'])
  304. if rotation == 0:
  305. coords[2], coords[3] = coords[0] + w, coords[1] + h
  306. return coords, w, h
  307. boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
  308. boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
  309. coords[2] = coords[0] + boxw
  310. coords[3] = coords[1] + boxh
  311. return coords, boxw, boxh
  312. def OnPaint(self, event):
  313. """
  314. Draw PseudoDC's to buffered paint DC
  315. self.pdc for background and decorations
  316. self.pdcVector for vector map which is edited
  317. self.pdcTmp for temporaly drawn objects (self.polycoords)
  318. If self.redrawAll is False on self.pdcTmp content is re-drawn
  319. """
  320. Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
  321. dc = wx.BufferedPaintDC(self, self.buffer)
  322. ### dc.SetBackground(wx.Brush("White"))
  323. dc.Clear()
  324. # use PrepareDC to set position correctly
  325. self.PrepareDC(dc)
  326. # create a clipping rect from our position and size
  327. # and update region
  328. rgn = self.GetUpdateRegion().GetBox()
  329. dc.SetClippingRect(rgn)
  330. switchDraw = False
  331. if self.redrawAll is None:
  332. self.redrawAll = True
  333. switchDraw = True
  334. if self.redrawAll: # redraw pdc and pdcVector
  335. # draw to the dc using the calculated clipping rect
  336. self.pdc.DrawToDCClipped(dc, rgn)
  337. # draw vector map layer
  338. if self.pdcVector:
  339. # decorate with GDDC (transparency)
  340. try:
  341. gcdc = wx.GCDC(dc)
  342. self.pdcVector.DrawToDCClipped(gcdc, rgn)
  343. except NotImplementedError, e:
  344. print >> sys.stderr, e
  345. self.pdcVector.DrawToDCClipped(dc, rgn)
  346. self.bufferLast = None
  347. else: # do not redraw pdc and pdcVector
  348. if self.bufferLast is None:
  349. # draw to the dc
  350. self.pdc.DrawToDC(dc)
  351. if self.pdcVector:
  352. # decorate with GDDC (transparency)
  353. try:
  354. gcdc = wx.GCDC(dc)
  355. self.pdcVector.DrawToDC(gcdc)
  356. except NotImplementedError, e:
  357. print >> sys.stderr, e
  358. self.pdcVector.DrawToDC(dc)
  359. # store buffered image
  360. # self.bufferLast = wx.BitmapFromImage(self.buffer.ConvertToImage())
  361. self.bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
  362. pdcLast = wx.PseudoDC()
  363. pdcLast.DrawBitmap(bmp=self.bufferLast, x=0, y=0)
  364. pdcLast.DrawToDC(dc)
  365. # draw decorations (e.g. region box)
  366. try:
  367. gcdc = wx.GCDC(dc)
  368. self.pdcDec.DrawToDC(gcdc)
  369. except NotImplementedError, e:
  370. print >> sys.stderr, e
  371. self.pdcDec.DrawToDC(dc)
  372. # draw temporary object on the foreground
  373. ### self.pdcTmp.DrawToDCClipped(dc, rgn)
  374. self.pdcTmp.DrawToDC(dc)
  375. if switchDraw:
  376. self.redrawAll = False
  377. def OnSize(self, event):
  378. """
  379. Scale map image so that it is
  380. the same size as the Window
  381. """
  382. Debug.msg(3, "BufferedWindow.OnSize():")
  383. # set size of the input image
  384. self.Map.ChangeMapSize(self.GetClientSize())
  385. # align extent based on center point and display resolution
  386. # this causes that image is not resized when display windows is resized
  387. # self.Map.AlignExtentFromDisplay()
  388. # Make new off screen bitmap: this bitmap will always have the
  389. # current drawing in it, so it can be used to save the image to
  390. # a file, or whatever.
  391. self.buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
  392. # get the image to be rendered
  393. self.img = self.GetImage()
  394. if self.img != None:
  395. self.img.AddHandler(JPEGHandler)
  396. self.img.AddHandler(GIFHandler)
  397. self.img.AddHandler(BMPHandler)
  398. self.img.AddHandler(XPMHandler)
  399. self.img.AddHandler(PNMHandler)
  400. self.img.AddHandler(PCXHandler)
  401. # update map display
  402. if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
  403. self.img = self.img.Scale(self.Map.width, self.Map.height)
  404. if len(self.Map.GetListOfLayers()) > 0:
  405. self.UpdateMap()
  406. # re-render image on idle
  407. self.resize = True
  408. # reposition checkbox in statusbar
  409. self.parent.StatusbarReposition()
  410. # update statusbar
  411. self.parent.StatusbarUpdate()
  412. def OnIdle(self, event):
  413. """
  414. Only re-render a composite map image from GRASS during
  415. idle time instead of multiple times during resizing.
  416. """
  417. if self.resize:
  418. self.UpdateMap(render=True)
  419. event.Skip()
  420. def SaveToFile(self, FileName, FileType):
  421. """
  422. This draws the psuedo DC to a buffer that
  423. can be saved to a file.
  424. """
  425. dc = wx.BufferedPaintDC(self, self.buffer)
  426. self.pdc.DrawToDC(dc)
  427. if self.pdcVector:
  428. self.pdcVector.DrawToDC(dc)
  429. self.buffer.SaveFile(FileName, FileType)
  430. def GetOverlay(self):
  431. """
  432. Converts rendered overlay files to wx.Image
  433. Updates self.imagedict
  434. @return list of images
  435. """
  436. imgs = []
  437. for overlay in self.Map.GetListOfLayers(l_type="overlay", l_active=True):
  438. if os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
  439. img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
  440. self.imagedict[img] = { 'id' : overlay.id,
  441. 'layer' : overlay }
  442. imgs.append(img)
  443. return imgs
  444. def GetImage(self):
  445. """
  446. Converts redered map files to wx.Image
  447. Updates self.imagedict (id=99)
  448. @return wx.Image instance (map composition)
  449. """
  450. imgId = 99
  451. if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
  452. os.path.getsize(self.Map.mapfile):
  453. img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
  454. else:
  455. img = None
  456. self.imagedict[img] = { 'id': imgId }
  457. return img
  458. def UpdateMap(self, render=True, renderVector=True):
  459. """
  460. Updates the canvas anytime there is a change to the
  461. underlaying images or to the geometry of the canvas.
  462. @param render re-render map composition
  463. @param renderVector re-render vector map layer enabled for editing (used for digitizer)
  464. """
  465. start = time.clock()
  466. self.resize = False
  467. # if len(self.Map.GetListOfLayers()) == 0:
  468. # return False
  469. if self.img is None:
  470. render = True
  471. #
  472. # initialize process bar (only on 'render')
  473. #
  474. if render is True or renderVector is True:
  475. self.parent.onRenderGauge.Show()
  476. if self.parent.onRenderGauge.GetRange() > 0:
  477. self.parent.onRenderGauge.SetValue(1)
  478. #
  479. # render background image if needed
  480. #
  481. # update layer dictionary if there has been a change in layers
  482. if self.tree and self.tree.reorder == True:
  483. self.tree.ReorderLayers()
  484. # reset flag for auto-rendering
  485. if self.tree:
  486. self.tree.rerender = False
  487. if render:
  488. # update display size
  489. self.Map.ChangeMapSize(self.GetClientSize())
  490. if self.parent.compResolution.IsChecked():
  491. # use computation region resolution for rendering
  492. windres = True
  493. else:
  494. windres = False
  495. self.mapfile = self.Map.Render(force=True, mapWindow=self.parent,
  496. windres=windres)
  497. else:
  498. self.mapfile = self.Map.Render(force=False, mapWindow=self.parent)
  499. self.img = self.GetImage() # id=99
  500. #
  501. # clear pseudoDcs
  502. #
  503. for pdc in (self.pdc,
  504. self.pdcDec,
  505. self.pdcTmp):
  506. pdc.Clear()
  507. pdc.RemoveAll()
  508. #
  509. # draw background map image to PseudoDC
  510. #
  511. if not self.img:
  512. self.Draw(self.pdc, pdctype='clear')
  513. else:
  514. try:
  515. id = self.imagedict[self.img]['id']
  516. except:
  517. return False
  518. self.Draw(self.pdc, self.img, drawid=id)
  519. #
  520. # render vector map layer
  521. #
  522. digitToolbar = self.parent.toolbars['vdigit']
  523. if renderVector and digitToolbar and \
  524. digitToolbar.GetLayer():
  525. # set region
  526. self.parent.digit.driver.UpdateRegion()
  527. # re-calculate threshold for digitization tool
  528. self.parent.digit.driver.GetThreshold()
  529. # draw map
  530. self.pdcVector.Clear()
  531. self.pdcVector.RemoveAll()
  532. try:
  533. item = self.tree.FindItemByData('maplayer', digitToolbar.GetLayer())
  534. except TypeError:
  535. item = None
  536. if item and self.tree.IsItemChecked(item):
  537. self.parent.digit.driver.DrawMap()
  538. # translate tmp objects (pointer position)
  539. if digitToolbar.GetAction() == 'moveLine':
  540. if hasattr(self, "vdigitMove") and \
  541. self.vdigitMove.has_key('beginDiff'):
  542. # move line
  543. for id in self.vdigitMove['id']:
  544. # print self.pdcTmp.GetIdBounds(id)
  545. self.pdcTmp.TranslateId(id,
  546. self.vdigitMove['beginDiff'][0],
  547. self.vdigitMove['beginDiff'][1])
  548. del self.vdigitMove['beginDiff']
  549. #
  550. # render overlays
  551. #
  552. for img in self.GetOverlay():
  553. # draw any active and defined overlays
  554. if self.imagedict[img]['layer'].IsActive():
  555. id = self.imagedict[img]['id']
  556. self.Draw(self.pdc, img=img, drawid=id,
  557. pdctype=self.overlays[id]['pdcType'], coords=self.overlays[id]['coords'])
  558. for id in self.textdict.keys():
  559. self.Draw(self.pdc, img=self.textdict[id], drawid=id,
  560. pdctype='text', coords=[10, 10, 10, 10])
  561. # optionally draw computational extent box
  562. self.DrawCompRegionExtent()
  563. #
  564. # redraw pdcTmp if needed
  565. #
  566. if len(self.polycoords) > 0:
  567. self.DrawLines(self.pdcTmp)
  568. if self.parent.gismanager.georectifying:
  569. # -> georectifier (redraw GCPs)
  570. if self.parent.toolbars['georect']:
  571. coordtype = 'gcpcoord'
  572. else:
  573. coordtype = 'mapcoord'
  574. self.parent.gismanager.georectifying.DrawGCP(coordtype)
  575. #
  576. # clear measurement
  577. #
  578. if self.mouse["use"] == "measure":
  579. self.ClearLines(pdc=self.pdcTmp)
  580. self.polycoords = []
  581. self.mouse['use'] = 'pointer'
  582. self.mouse['box'] = 'point'
  583. self.mouse['end'] = [0, 0]
  584. self.SetCursor(self.parent.cursors["default"])
  585. stop = time.clock()
  586. #
  587. # hide process bar
  588. #
  589. self.parent.onRenderGauge.Hide()
  590. #
  591. # update statusbar
  592. #
  593. ### self.Map.SetRegion()
  594. self.parent.StatusbarUpdate()
  595. Debug.msg (2, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
  596. (render, renderVector, (stop-start)))
  597. return True
  598. def DrawCompRegionExtent(self):
  599. """
  600. Draw computational region extent in the display
  601. Display region is drawn as a blue box inside the computational region,
  602. computational region inside a display region as a red box).
  603. """
  604. if hasattr(self, "regionCoords"):
  605. compReg = self.Map.GetRegion()
  606. dispReg = self.Map.GetCurrentRegion()
  607. reg = None
  608. if self.IsInRegion(dispReg, compReg):
  609. self.polypen = wx.Pen(colour=wx.Colour(0, 0, 255, 128), width=3, style=wx.SOLID)
  610. reg = dispReg
  611. else:
  612. self.polypen = wx.Pen(colour=wx.Colour(255, 0, 0, 128),
  613. width=3, style=wx.SOLID)
  614. reg = compReg
  615. self.regionCoords = []
  616. self.regionCoords.append((reg['w'], reg['n']))
  617. self.regionCoords.append((reg['e'], reg['n']))
  618. self.regionCoords.append((reg['e'], reg['s']))
  619. self.regionCoords.append((reg['w'], reg['s']))
  620. self.regionCoords.append((reg['w'], reg['n']))
  621. # draw region extent
  622. self.DrawLines(pdc=self.pdcDec, polycoords=self.regionCoords)
  623. def IsInRegion(self, region, refRegion):
  624. """
  625. Test if 'region' is inside of 'refRegion'
  626. @param region input region
  627. @param refRegion reference region (e.g. computational region)
  628. @return True if region is inside of refRegion
  629. @return False
  630. """
  631. if region['s'] >= refRegion['s'] and \
  632. region['n'] <= refRegion['n'] and \
  633. region['w'] >= refRegion['w'] and \
  634. region['e'] <= refRegion['e']:
  635. return True
  636. return False
  637. def EraseMap(self):
  638. """
  639. Erase the canvas
  640. """
  641. self.Draw(self.pdc, pdctype='clear')
  642. if self.pdcVector:
  643. self.Draw(self.pdcVector, pdctype='clear')
  644. self.Draw(self.pdcDec, pdctype='clear')
  645. self.Draw(self.pdcTmp, pdctype='clear')
  646. def DragMap(self, moveto):
  647. """
  648. Drag the entire map image for panning.
  649. """
  650. dc = wx.BufferedDC(wx.ClientDC(self))
  651. dc.SetBackground(wx.Brush("White"))
  652. dc.Clear()
  653. self.dragimg = wx.DragImage(self.buffer)
  654. self.dragimg.BeginDrag((0, 0), self)
  655. self.dragimg.GetImageRect(moveto)
  656. self.dragimg.Move(moveto)
  657. self.dragimg.DoDrawImage(dc, moveto)
  658. self.dragimg.EndDrag()
  659. return True
  660. def DragItem(self, id, event):
  661. """
  662. Drag an overlay decoration item
  663. """
  664. if id == 99 or id == '' or id == None: return
  665. Debug.msg (5, "BufferedWindow.DragItem(): id=%d" % id)
  666. x, y = self.lastpos
  667. dx = event.GetX() - x
  668. dy = event.GetY() - y
  669. self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
  670. r = self.pdc.GetIdBounds(id)
  671. if id > 100: # text dragging
  672. rtop = (r[0],r[1]-r[3],r[2],r[3])
  673. r = r.Union(rtop)
  674. rleft = (r[0]-r[2],r[1],r[2],r[3])
  675. r = r.Union(rleft)
  676. self.pdc.TranslateId(id, dx, dy)
  677. r2 = self.pdc.GetIdBounds(id)
  678. if id > 100: # text
  679. self.textdict[id]['coords'] = r2
  680. r = r.Union(r2)
  681. r.Inflate(4,4)
  682. self.RefreshRect(r, False)
  683. self.lastpos = (event.GetX(), event.GetY())
  684. def MouseDraw(self, pdc=None, begin=None, end=None):
  685. """
  686. Mouse box or line from 'begin' to 'end'
  687. If not given from self.mouse['begin'] to self.mouse['end'].
  688. """
  689. self.redrawAll = False
  690. if not pdc:
  691. return
  692. if begin is None:
  693. begin = self.mouse['begin']
  694. if end is None:
  695. end = self.mouse['end']
  696. Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
  697. (self.mouse['use'], self.mouse['box'],
  698. begin[0], begin[1], end[0], end[1]))
  699. if self.mouse['box'] == "box":
  700. boxid = wx.ID_NEW
  701. mousecoords = [begin[0], begin[1],
  702. end[0], end[1]]
  703. r = pdc.GetIdBounds(boxid)
  704. r.Inflate(4,4)
  705. pdc.ClearId(boxid)
  706. self.RefreshRect(r, False)
  707. pdc.SetId(boxid)
  708. self.Draw(pdc, drawid=boxid, pdctype='box', coords=mousecoords)
  709. elif self.mouse['box'] == "line":
  710. self.lineid = wx.ID_NEW
  711. mousecoords = [begin[0], begin[1], \
  712. end[0], end[1]]
  713. x1=min(begin[0],end[0])
  714. x2=max(begin[0],end[0])
  715. y1=min(begin[1],end[1])
  716. y2=max(begin[1],end[1])
  717. r = wx.Rect(x1,y1,x2-x1,y2-y1)
  718. r.Inflate(4,4)
  719. try:
  720. pdc.ClearId(self.lineid)
  721. except:
  722. pass
  723. self.RefreshRect(r, False)
  724. pdc.SetId(self.lineid)
  725. self.Draw(pdc, drawid=self.lineid, pdctype='line', coords=mousecoords)
  726. def DrawLines(self, pdc=None, polycoords=None):
  727. """
  728. Draw polyline in PseudoDC
  729. Set self.pline to wx.NEW_ID + 1
  730. polycoords - list of polyline vertices, geographical coordinates
  731. (if not given, self.polycoords is used)
  732. """
  733. if not pdc:
  734. pdc = self.pdcTmp
  735. if not polycoords:
  736. polycoords = self.polycoords
  737. if len(polycoords) > 0:
  738. self.plineid = wx.ID_NEW + 1
  739. # convert from EN to XY
  740. coords = []
  741. for p in polycoords:
  742. coords.append(self.Cell2Pixel(p))
  743. self.Draw(pdc, drawid=self.plineid, pdctype='polyline', coords=coords)
  744. Debug.msg (4, "BufferedWindow.DrawLines(): coords=%s, id=%s" % \
  745. (coords, self.plineid))
  746. return self.plineid
  747. return -1
  748. def DrawCross(self, pdc, coords, size, rotation=0,
  749. text=None, textAlign='lr', textOffset=(5, 5)):
  750. """Draw cross in PseudoDC
  751. @todo implement rotation
  752. @param pdc PseudoDC
  753. @param coord center coordinates
  754. @param rotation rotate symbol
  755. @param text draw also text (text, font, color, rotation)
  756. @param textAlign alignment (default 'lower-right')
  757. @textOffset offset for text (from center point)
  758. """
  759. Debug.msg(4, "BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
  760. (pdc, coords, size))
  761. coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
  762. (coords[0], coords[1] - size, coords[0], coords[1] + size))
  763. self.lineid = wx.NewId()
  764. for lineCoords in coordsCross:
  765. self.Draw(pdc, drawid=self.lineid, pdctype='line', coords=lineCoords)
  766. if not text:
  767. return self.lineid
  768. if textAlign == 'ul':
  769. coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
  770. elif textAlign == 'ur':
  771. coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
  772. elif textAlign == 'lr':
  773. coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
  774. else:
  775. coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
  776. self.Draw(pdc, img=text,
  777. pdctype='text', coords=coord)
  778. return self.lineid
  779. def MouseActions(self, event):
  780. """
  781. Mouse motion and button click notifier
  782. """
  783. if not self.processMouse:
  784. return
  785. ### if self.redrawAll is False:
  786. ### self.redrawAll = True
  787. # zoom with mouse wheel
  788. if event.GetWheelRotation() != 0:
  789. self.OnMouseWheel(event)
  790. # left mouse button pressed
  791. elif event.LeftDown():
  792. self.OnLeftDown(event)
  793. # left mouse button released
  794. elif event.LeftUp():
  795. self.OnLeftUp(event)
  796. # dragging
  797. elif event.Dragging():
  798. self.OnDragging(event)
  799. # double click
  800. elif event.ButtonDClick():
  801. self.OnButtonDClick(event)
  802. # middle mouse button pressed
  803. elif event.MiddleDown():
  804. self.OnMiddleDown(event)
  805. # right mouse button pressed
  806. elif event.RightDown():
  807. self.OnRightDown(event)
  808. # right mouse button released
  809. elif event.RightUp():
  810. self.OnRightUp(event)
  811. elif event.Moving():
  812. self.OnMouseMoving(event)
  813. # event.Skip()
  814. def OnMouseWheel(self, event):
  815. """
  816. Mouse wheel moved
  817. """
  818. self.processMouse = False
  819. current = event.GetPositionTuple()[:]
  820. wheel = event.GetWheelRotation()
  821. Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
  822. # zoom 1/2 of the screen, centered to current mouse position (TODO: settings)
  823. begin = (current[0] - self.Map.width / 4,
  824. current[1] - self.Map.height / 4)
  825. end = (current[0] + self.Map.width / 4,
  826. current[1] + self.Map.height / 4)
  827. if wheel > 0:
  828. zoomtype = 1
  829. else:
  830. zoomtype = -1
  831. # zoom
  832. self.Zoom(begin, end, zoomtype)
  833. # redraw map
  834. self.UpdateMap()
  835. ### self.OnPaint(None)
  836. # update statusbar
  837. self.parent.StatusbarUpdate()
  838. self.Refresh()
  839. self.processMouse = True
  840. # event.Skip()
  841. def OnDragging(self, event):
  842. """
  843. Mouse dragging with left button down
  844. """
  845. Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
  846. current = event.GetPositionTuple()[:]
  847. previous = self.mouse['begin']
  848. move = (current[0] - previous[0],
  849. current[1] - previous[1])
  850. digitToolbar = self.parent.toolbars['vdigit']
  851. # dragging or drawing box with left button
  852. if self.mouse['use'] == 'pan':
  853. self.DragMap(move)
  854. # dragging decoration overlay item
  855. elif (self.mouse['use'] == 'pointer' and
  856. not digitToolbar and
  857. self.dragid != None):
  858. self.DragItem(self.dragid, event)
  859. # dragging anything else - rubber band box or line
  860. else:
  861. if (self.mouse['use'] == 'pointer' and
  862. not digitToolbar): return
  863. self.mouse['end'] = event.GetPositionTuple()[:]
  864. digitClass = self.parent.digit
  865. if (event.LeftIsDown() and
  866. not (digitToolbar and
  867. digitToolbar.GetAction() in ("moveLine",) and
  868. digitClass.driver.GetSelected() > 0)):
  869. # draw box only when left mouse button is pressed
  870. self.MouseDraw(pdc=self.pdcTmp)
  871. # event.Skip()
  872. def OnLeftDownVDigitAddLine(self, event):
  873. """
  874. Left mouse button down - vector digitizer add new line
  875. action
  876. """
  877. digitToolbar = self.parent.toolbars['vdigit']
  878. digitClass = self.parent.digit
  879. try:
  880. mapLayer = digitToolbar.GetLayer().GetName()
  881. except:
  882. return
  883. if digitToolbar.GetAction('type') in ["point", "centroid"]:
  884. # add new point
  885. if digitToolbar.GetAction('type') == 'point':
  886. point = True
  887. else:
  888. point = False
  889. east, north = self.Pixel2Cell(self.mouse['begin'])
  890. fid = digitClass.AddPoint(mapLayer, point, east, north)
  891. if fid < 0:
  892. return
  893. self.UpdateMap(render=False) # redraw map
  894. # add new record into atribute table
  895. if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled') is True:
  896. # select attributes based on layer and category
  897. cats = { fid : {
  898. UserSettings.Get(group='vdigit', key="layer", subkey='value') :
  899. (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
  900. }}
  901. posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
  902. self.mouse['end'][1] + self.dialogOffset))
  903. addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=mapLayer,
  904. cats=cats,
  905. pos=posWindow,
  906. action="add")
  907. if addRecordDlg.mapDBInfo and \
  908. addRecordDlg.ShowModal() == wx.ID_OK:
  909. sqlfile = tempfile.NamedTemporaryFile(mode="w")
  910. for sql in addRecordDlg.GetSQLString():
  911. sqlfile.file.write(sql + ";\n")
  912. sqlfile.file.flush()
  913. gcmd.RunCommand('db.execute',
  914. parent = self,
  915. quiet = True,
  916. input = sqlfile.name)
  917. elif digitToolbar.GetAction('type') in ["line", "boundary"]:
  918. # add new point to the line
  919. self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
  920. self.DrawLines(pdc=self.pdcTmp)
  921. def OnLeftDownVDigitEditLine(self, event):
  922. """
  923. Left mouse button down - vector digitizer edit linear feature
  924. - add new vertex.
  925. """
  926. digitToolbar = self.parent.toolbars['vdigit']
  927. digitClass = self.parent.digit
  928. self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
  929. self.vdigitMove['id'].append(wx.NewId())
  930. self.DrawLines(pdc=self.pdcTmp)
  931. def OnLeftDownVDigitMoveLine(self, event):
  932. """
  933. Left mouse button down - vector digitizer move feature/vertex,
  934. edit linear feature
  935. """
  936. digitToolbar = self.parent.toolbars['vdigit']
  937. digitClass = self.parent.digit
  938. self.vdigitMove = {}
  939. # geographic coordinates of initial position (left-down)
  940. self.vdigitMove['begin'] = None
  941. # list of ids to modify
  942. self.vdigitMove['id'] = []
  943. # ids geographic coordinates
  944. self.vdigitMove['coord'] = {}
  945. if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
  946. # set pen
  947. pcolor = UserSettings.Get(group='vdigit', key="symbol",
  948. subkey=["highlight", "color"])
  949. self.pen = self.polypen = wx.Pen(colour=pcolor,
  950. width=2, style=wx.SHORT_DASH)
  951. self.pdcTmp.SetPen(self.polypen)
  952. def OnLeftDownVDigitDisplayCA(self, event):
  953. """
  954. Left mouse button down - vector digitizer display categories
  955. or attributes action
  956. """
  957. digitToolbar = self.parent.toolbars['vdigit']
  958. digitClass = self.parent.digit
  959. try:
  960. mapLayer = digitToolbar.GetLayer().GetName()
  961. except:
  962. return
  963. coords = self.Pixel2Cell(self.mouse['begin'])
  964. # unselect
  965. digitClass.driver.SetSelected([])
  966. # select feature by point
  967. cats = {}
  968. if digitClass.driver.SelectLineByPoint(coords,
  969. digitClass.GetSelectType()) is None:
  970. return
  971. if UserSettings.Get(group='vdigit', key='checkForDupl',
  972. subkey='enabled'):
  973. lines = digitClass.driver.GetSelected()
  974. else:
  975. lines = (digitClass.driver.GetSelected()[0],) # only first found
  976. for line in lines:
  977. cats[line] = digitClass.GetLineCats(line)
  978. posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
  979. self.mouse['end'][1] + self.dialogOffset))
  980. if digitToolbar.GetAction() == "displayAttrs":
  981. # select attributes based on coordinates (all layers)
  982. if self.parent.dialogs['attributes'] is None:
  983. self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=mapLayer,
  984. cats=cats,
  985. action="update")
  986. else:
  987. # upgrade dialog
  988. self.parent.dialogs['attributes'].UpdateDialog(cats=cats)
  989. if self.parent.dialogs['attributes']:
  990. if len(cats.keys()) > 0:
  991. # highlight feature & re-draw map
  992. if not self.parent.dialogs['attributes'].IsShown():
  993. self.parent.dialogs['attributes'].Show()
  994. else:
  995. if self.parent.dialogs['attributes'] and \
  996. self.parent.dialogs['attributes'].IsShown():
  997. self.parent.dialogs['attributes'].Hide()
  998. else: # displayCats
  999. if self.parent.dialogs['category'] is None:
  1000. # open new dialog
  1001. dlg = VDigitCategoryDialog(parent=self,
  1002. map=mapLayer,
  1003. cats=cats,
  1004. pos=posWindow,
  1005. title=_("Update categories"))
  1006. self.parent.dialogs['category'] = dlg
  1007. else:
  1008. # update currently open dialog
  1009. self.parent.dialogs['category'].UpdateDialog(cats=cats)
  1010. if self.parent.dialogs['category']:
  1011. if len(cats.keys()) > 0:
  1012. # highlight feature & re-draw map
  1013. if not self.parent.dialogs['category'].IsShown():
  1014. self.parent.dialogs['category'].Show()
  1015. else:
  1016. if self.parent.dialogs['category'].IsShown():
  1017. self.parent.dialogs['category'].Hide()
  1018. self.UpdateMap(render=False)
  1019. def OnLeftDownVDigitCopyCA(self, event):
  1020. """
  1021. Left mouse button down - vector digitizer copy categories
  1022. or attributes action
  1023. """
  1024. digitToolbar = self.parent.toolbars['vdigit']
  1025. digitClass = self.parent.digit
  1026. if not hasattr(self, "copyCatsList"):
  1027. self.copyCatsList = []
  1028. else:
  1029. self.copyCatsIds = []
  1030. self.mouse['box'] = 'box'
  1031. def OnLeftDownVDigitCopyLine(self, event):
  1032. """
  1033. Left mouse button down - vector digitizer copy lines action
  1034. """
  1035. digitToolbar = self.parent.toolbars['vdigit']
  1036. digitClass = self.parent.digit
  1037. self.copyIds = []
  1038. self.layerTmp = None
  1039. def OnLeftDownVDigitBulkLine(self, event):
  1040. """
  1041. Left mouse button down - vector digitizer label 3d vector
  1042. lines
  1043. """
  1044. digitToolbar = self.parent.toolbars['vdigit']
  1045. digitClass = self.parent.digit
  1046. if len(self.polycoords) > 1: # start new line
  1047. self.polycoords = []
  1048. self.ClearLines(pdc=self.pdcTmp)
  1049. self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
  1050. if len(self.polycoords) == 1:
  1051. begin = self.Pixel2Cell(self.polycoords[-1])
  1052. end = self.Pixel2Cell(self.mouse['end'])
  1053. else:
  1054. end = self.Pixel2Cell(self.polycoords[-1])
  1055. begin = self.Pixel2Cell(self.mouse['begin'])
  1056. self.DrawLines(self.pdcTmp, begin, end)
  1057. def OnLeftDown(self, event):
  1058. """
  1059. Left mouse button pressed
  1060. """
  1061. Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
  1062. self.mouse["use"])
  1063. self.mouse['begin'] = event.GetPositionTuple()[:]
  1064. if self.mouse["use"] in ["measure", "profile"]:
  1065. # measure or profile
  1066. if len(self.polycoords) == 0:
  1067. self.mouse['end'] = self.mouse['begin']
  1068. self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
  1069. self.ClearLines(pdc=self.pdcTmp)
  1070. else:
  1071. self.mouse['begin'] = self.mouse['end']
  1072. elif self.mouse['use'] == 'zoom':
  1073. pass
  1074. #
  1075. # vector digizer
  1076. #
  1077. elif self.mouse["use"] == "pointer" and \
  1078. self.parent.toolbars['vdigit']:
  1079. digitToolbar = self.parent.toolbars['vdigit']
  1080. digitClass = self.parent.digit
  1081. try:
  1082. mapLayer = digitToolbar.GetLayer().GetName()
  1083. except:
  1084. wx.MessageBox(parent=self,
  1085. message=_("No vector map selected for editing."),
  1086. caption=_("Vector digitizer"),
  1087. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  1088. event.Skip()
  1089. return
  1090. if digitToolbar.GetAction() not in ("moveVertex",
  1091. "addVertex",
  1092. "removeVertex",
  1093. "editLine"):
  1094. # set pen
  1095. self.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
  1096. self.polypen = wx.Pen(colour='dark green', width=2, style=wx.SOLID)
  1097. if digitToolbar.GetAction() in ("addVertex",
  1098. "removeVertex",
  1099. "splitLines"):
  1100. # unselect
  1101. digitClass.driver.SetSelected([])
  1102. if digitToolbar.GetAction() == "addLine":
  1103. self.OnLeftDownVDigitAddLine(event)
  1104. elif digitToolbar.GetAction() == "editLine" and \
  1105. hasattr(self, "vdigitMove"):
  1106. self.OnLeftDownVDigitEditLine(event)
  1107. elif digitToolbar.GetAction() in ("moveLine",
  1108. "moveVertex",
  1109. "editLine") and \
  1110. not hasattr(self, "vdigitMove"):
  1111. self.OnLeftDownVDigitMoveLine(event)
  1112. elif digitToolbar.GetAction() in ("displayAttrs"
  1113. "displayCats"):
  1114. self.OnLeftDownVDigitDisplayCA(event)
  1115. elif digitToolbar.GetAction() in ("copyCats",
  1116. "copyAttrs"):
  1117. self.OnLeftDownVDigitCopyCA(event)
  1118. elif digitToolbar.GetAction() == "copyLine":
  1119. self.OnLeftDownCopyLine(event)
  1120. elif digitToolbar.GetAction() == "zbulkLine":
  1121. self.OnLeftDownVDigitBulkLine(event)
  1122. elif self.mouse['use'] == 'pointer':
  1123. # get decoration or text id
  1124. self.idlist = []
  1125. self.dragid = ''
  1126. self.lastpos = self.mouse['begin']
  1127. idlist = self.pdc.FindObjects(x=self.lastpos[0], y=self.lastpos[1],
  1128. radius=self.hitradius)
  1129. if 99 in idlist: idlist.remove(99)
  1130. if idlist != [] :
  1131. self.dragid = idlist[0] #drag whatever is on top
  1132. else:
  1133. pass
  1134. event.Skip()
  1135. def OnLeftUpVDigitVarious(self, event):
  1136. """
  1137. Left mouse button up - vector digitizer various actions
  1138. """
  1139. digitToolbar = self.parent.toolbars['vdigit']
  1140. digitClass = self.parent.digit
  1141. pos1 = self.Pixel2Cell(self.mouse['begin'])
  1142. pos2 = self.Pixel2Cell(self.mouse['end'])
  1143. nselected = 0
  1144. # -> delete line || move line || move vertex
  1145. if digitToolbar.GetAction() in ("moveVertex",
  1146. "editLine"):
  1147. if len(digitClass.driver.GetSelected()) == 0:
  1148. nselected = digitClass.driver.SelectLineByPoint(pos1, type=VDigit_Lines_Type)
  1149. if digitToolbar.GetAction() == "editLine":
  1150. try:
  1151. selVertex = digitClass.driver.GetSelectedVertex(pos1)[0]
  1152. except IndexError:
  1153. selVertex = None
  1154. if selVertex:
  1155. # self.UpdateMap(render=False)
  1156. ids = digitClass.driver.GetSelected(grassId=False)
  1157. # move this line to tmp layer
  1158. self.polycoords = []
  1159. for id in ids:
  1160. if id % 2: # register only vertices
  1161. e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
  1162. self.polycoords.append((e, n))
  1163. digitClass.driver.DrawSelected(False)
  1164. if selVertex < ids[-1] / 2:
  1165. # choose first or last node of line
  1166. self.vdigitMove['id'].reverse()
  1167. self.polycoords.reverse()
  1168. else:
  1169. # unselect
  1170. digitClass.driver.SetSelected([])
  1171. del self.vdigitMove
  1172. self.UpdateMap(render=False)
  1173. elif digitToolbar.GetAction() in ("copyCats",
  1174. "copyAttrs"):
  1175. if not hasattr(self, "copyCatsIds"):
  1176. # 'from' -> select by point
  1177. nselected = digitClass.driver.SelectLineByPoint(pos1, digitClass.GetSelectType())
  1178. if nselected:
  1179. self.copyCatsList = digitClass.driver.GetSelected()
  1180. else:
  1181. # -> 'to' -> select by bbox
  1182. digitClass.driver.SetSelected([])
  1183. # return number of selected features (by box/point)
  1184. nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
  1185. digitClass.GetSelectType())
  1186. if nselected == 0:
  1187. if digitClass.driver.SelectLineByPoint(pos1,
  1188. digitClass.GetSelectType()) is not None:
  1189. nselected = 1
  1190. if nselected > 0:
  1191. self.copyCatsIds = digitClass.driver.GetSelected()
  1192. elif digitToolbar.GetAction() == "queryLine":
  1193. selected = digitClass.SelectLinesByQuery(pos1, pos2)
  1194. nselected = len(selected)
  1195. if nselected > 0:
  1196. digitClass.driver.SetSelected(selected)
  1197. else:
  1198. # -> moveLine || deleteLine, etc. (select by point/box)
  1199. if digitToolbar.GetAction() == 'moveLine' and \
  1200. len(digitClass.driver.GetSelected()) > 0:
  1201. nselected = 0
  1202. else:
  1203. if digitToolbar.GetAction() == 'moveLine':
  1204. drawSeg = True
  1205. else:
  1206. drawSeg = False
  1207. nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
  1208. digitClass.GetSelectType(),
  1209. drawSeg)
  1210. if nselected == 0:
  1211. if digitClass.driver.SelectLineByPoint(pos1,
  1212. digitClass.GetSelectType()) is not None:
  1213. nselected = 1
  1214. if nselected > 0:
  1215. if digitToolbar.GetAction() in ("moveLine",
  1216. "moveVertex"):
  1217. # get pseudoDC id of objects which should be redrawn
  1218. if digitToolbar.GetAction() == "moveLine":
  1219. # -> move line
  1220. self.vdigitMove['id'] = digitClass.driver.GetSelected(grassId=False)
  1221. self.vdigitMove['coord'] = digitClass.driver.GetSelectedCoord()
  1222. else: # moveVertex
  1223. self.vdigitMove['id'] = digitClass.driver.GetSelectedVertex(pos1)
  1224. if len(self.vdigitMove['id']) == 0: # no vertex found
  1225. digitClass.driver.SetSelected([])
  1226. #
  1227. # check for duplicates
  1228. #
  1229. if UserSettings.Get(group='vdigit', key='checkForDupl', subkey='enabled') is True:
  1230. dupl = digitClass.driver.GetDuplicates()
  1231. self.UpdateMap(render=False)
  1232. if dupl:
  1233. posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
  1234. self.mouse['end'][1] + self.dialogOffset))
  1235. dlg = VDigitDuplicatesDialog(parent=self, data=dupl, pos=posWindow)
  1236. if dlg.ShowModal() == wx.ID_OK:
  1237. digitClass.driver.UnSelect(dlg.GetUnSelected())
  1238. # update selected
  1239. self.UpdateMap(render=False)
  1240. if digitToolbar.GetAction() != "editLine":
  1241. # -> move line || move vertex
  1242. self.UpdateMap(render=False)
  1243. else: # no vector object found
  1244. if not (digitToolbar.GetAction() in ("moveLine",
  1245. "moveVertex") and \
  1246. len(self.vdigitMove['id']) > 0):
  1247. # avoid left-click when features are already selected
  1248. self.UpdateMap(render=False, renderVector=False)
  1249. def OnLeftUpVDigitModifyLine(self, event):
  1250. """
  1251. Left mouse button up - vector digitizer split line, add/remove
  1252. vertex action
  1253. """
  1254. digitToolbar = self.parent.toolbars['vdigit']
  1255. digitClass = self.parent.digit
  1256. pos1 = self.Pixel2Cell(self.mouse['begin'])
  1257. pointOnLine = digitClass.driver.SelectLineByPoint(pos1,
  1258. type=VDigit_Lines_Type)
  1259. if not pointOnLine:
  1260. return
  1261. if digitToolbar.GetAction() in ["splitLine", "addVertex"]:
  1262. self.UpdateMap(render=False) # highlight object
  1263. self.DrawCross(pdc=self.pdcTmp, coords=self.Cell2Pixel(pointOnLine),
  1264. size=5)
  1265. else: # removeVertex
  1266. # get only id of vertex
  1267. try:
  1268. id = digitClass.driver.GetSelectedVertex(pos1)[0]
  1269. except IndexError:
  1270. id = None
  1271. if id:
  1272. x, y = self.pdcVector.GetIdBounds(id)[0:2]
  1273. self.pdcVector.RemoveId(id)
  1274. self.UpdateMap(render=False) # highlight object
  1275. self.DrawCross(pdc=self.pdcTmp, coords=(x, y),
  1276. size=5)
  1277. else:
  1278. # unselect
  1279. digitClass.driver.SetSelected([])
  1280. self.UpdateMap(render=False)
  1281. def OnLeftUpVDigitCopyLine(self, event):
  1282. """
  1283. Left mouse button up - vector digitizer copy feature action
  1284. """
  1285. digitToolbar = self.parent.toolbars['vdigit']
  1286. digitClass = self.parent.digit
  1287. if UserSettings.Get(group='vdigit', key='bgmap',
  1288. subkey='value', internal=True) == '':
  1289. # no background map -> copy from current vector map layer
  1290. nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
  1291. digitClass.GetSelectType())
  1292. if nselected > 0:
  1293. # highlight selected features
  1294. self.UpdateMap(render=False)
  1295. else:
  1296. self.UpdateMap(render=False, renderVector=False)
  1297. else:
  1298. # copy features from background map
  1299. self.copyIds = digitClass.SelectLinesFromBackgroundMap(pos1, pos2)
  1300. if len(self.copyIds) > 0:
  1301. color = UserSettings.Get(group='vdigit', key='symbol',
  1302. subkey=['highlight', 'color'])
  1303. colorStr = str(color[0]) + ":" + \
  1304. str(color[1]) + ":" + \
  1305. str(color[2])
  1306. dVectTmp = ['d.vect',
  1307. 'map=%s' % UserSettings.Get(group='vdigit', key='bgmap',
  1308. subkey='value', internal=True),
  1309. 'cats=%s' % utils.ListOfCatsToRange(self.copyIds),
  1310. '-i',
  1311. 'color=%s' % colorStr,
  1312. 'fcolor=%s' % colorStr,
  1313. 'type=point,line,boundary,centroid',
  1314. 'width=2']
  1315. self.layerTmp = self.Map.AddLayer(type='vector',
  1316. name=globalvar.QUERYLAYER,
  1317. command=dVectTmp)
  1318. self.UpdateMap(render=True, renderVector=False)
  1319. else:
  1320. self.UpdateMap(render=False, renderVector=False)
  1321. self.redrawAll = None
  1322. def OnLeftUpVDigitBulkLine(self, event):
  1323. """
  1324. Left mouse button up - vector digitizer z-bulk line action
  1325. """
  1326. digitToolbar = self.parent.toolbars['vdigit']
  1327. digitClass = self.parent.digit
  1328. # select lines to be labeled
  1329. pos1 = self.polycoords[0]
  1330. pos2 = self.polycoords[1]
  1331. nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
  1332. digitClass.GetSelectType())
  1333. if nselected > 0:
  1334. # highlight selected features
  1335. self.UpdateMap(render=False)
  1336. self.DrawLines(pdc=self.pdcTmp) # redraw temp line
  1337. else:
  1338. self.UpdateMap(render=False, renderVector=False)
  1339. def OnLeftUpVDigitConnectLine(self, event):
  1340. """
  1341. Left mouse button up - vector digitizer connect line action
  1342. """
  1343. digitToolbar = self.parent.toolbars['vdigit']
  1344. digitClass = self.parent.digit
  1345. if len(digitClass.driver.GetSelected()) > 0:
  1346. self.UpdateMap(render=False)
  1347. def OnLeftUp(self, event):
  1348. """
  1349. Left mouse button released
  1350. """
  1351. Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
  1352. self.mouse["use"])
  1353. self.mouse['end'] = event.GetPositionTuple()[:]
  1354. if self.mouse['use'] in ["zoom", "pan"]:
  1355. # set region in zoom or pan
  1356. begin = self.mouse['begin']
  1357. end = self.mouse['end']
  1358. if self.mouse['use'] == 'zoom':
  1359. # set region for click (zero-width box)
  1360. if begin[0] - end[0] == 0 or \
  1361. begin[1] - end[1] == 0:
  1362. # zoom 1/2 of the screen (TODO: settings)
  1363. begin = (end[0] - self.Map.width / 4,
  1364. end[1] - self.Map.height / 4)
  1365. end = (end[0] + self.Map.width / 4,
  1366. end[1] + self.Map.height / 4)
  1367. self.Zoom(begin, end, self.zoomtype)
  1368. # redraw map
  1369. self.UpdateMap(render=True)
  1370. # update statusbar
  1371. self.parent.StatusbarUpdate()
  1372. elif self.mouse["use"] == "query":
  1373. # querying
  1374. self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
  1375. elif self.mouse["use"] == "queryVector":
  1376. # editable mode for vector map layers
  1377. self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
  1378. # clear temp canvas
  1379. self.UpdateMap(render=False, renderVector=False)
  1380. elif self.mouse["use"] in ["measure", "profile"]:
  1381. # measure or profile
  1382. if self.mouse["use"] == "measure":
  1383. self.parent.MeasureDist(self.mouse['begin'], self.mouse['end'])
  1384. self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
  1385. self.ClearLines(pdc=self.pdcTmp)
  1386. self.DrawLines(pdc=self.pdcTmp)
  1387. elif self.mouse["use"] == "pointer" and self.parent.gismanager.georectifying:
  1388. # -> georectifying
  1389. coord = self.Pixel2Cell(self.mouse['end'])
  1390. if self.parent.toolbars['georect']:
  1391. coordtype = 'gcpcoord'
  1392. else:
  1393. coordtype = 'mapcoord'
  1394. self.parent.gismanager.georectifying.SetGCPData(coordtype, coord, self)
  1395. self.UpdateMap(render=False, renderVector=False)
  1396. elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
  1397. # digitization tool active
  1398. digitToolbar = self.parent.toolbars['vdigit']
  1399. digitClass = self.parent.digit
  1400. if hasattr(self, "vdigitMove"):
  1401. if len(digitClass.driver.GetSelected()) == 0:
  1402. self.vdigitMove['begin'] = self.Pixel2Cell(self.mouse['begin']) # left down
  1403. # eliminate initial mouse moving efect
  1404. self.mouse['begin'] = self.mouse['end']
  1405. if digitToolbar.GetAction() in ("deleteLine",
  1406. "moveLine",
  1407. "moveVertex",
  1408. "copyCats",
  1409. "copyAttrs",
  1410. "editLine",
  1411. "flipLine",
  1412. "mergeLine",
  1413. "snapLine",
  1414. "queryLine",
  1415. "breakLine",
  1416. "typeConv",
  1417. "connectLine"):
  1418. self.OnLeftUpVDigitVarious(event)
  1419. elif digitToolbar.GetAction() in ("splitLine",
  1420. "addVertex",
  1421. "removeVertex"):
  1422. self.OnLeftUpVDigitModifyLine(event)
  1423. elif digitToolbar.GetAction() == "copyLine":
  1424. self.OnLeftUpVDigitCopyLine(event)
  1425. elif digitToolbar.GetAction() == "zbulkLine" and \
  1426. len(self.polycoords) == 2:
  1427. self.OnLeftUpVDigitBulkLine(event)
  1428. elif digitToolbar.GetAction() == "connectLine":
  1429. self.OnLeftUpConnectLine(event)
  1430. if len(digitClass.driver.GetSelected()) > 0:
  1431. self.redrawAll = None
  1432. elif (self.mouse['use'] == 'pointer' and
  1433. self.dragid >= 0):
  1434. # end drag of overlay decoration
  1435. if self.dragid < 99 and self.overlays.has_key(self.dragid):
  1436. self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
  1437. elif self.dragid > 100 and self.textdict.has_key(self.dragid):
  1438. self.textdict[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
  1439. else:
  1440. pass
  1441. self.dragid = None
  1442. self.currtxtid = None
  1443. def OnButtonDClick(self, event):
  1444. """
  1445. Mouse button double click
  1446. """
  1447. Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
  1448. self.mouse["use"])
  1449. if self.mouse["use"] == "measure":
  1450. # measure
  1451. self.ClearLines(pdc=self.pdcTmp)
  1452. self.polycoords = []
  1453. self.mouse['use'] = 'pointer'
  1454. self.mouse['box'] = 'point'
  1455. self.mouse['end'] = [0, 0]
  1456. self.Refresh()
  1457. self.SetCursor(self.parent.cursors["default"])
  1458. elif self.mouse["use"] == "profile":
  1459. pass
  1460. elif self.mouse['use'] == 'pointer' and \
  1461. self.parent.toolbars['vdigit']:
  1462. # vector digitizer
  1463. pass
  1464. else:
  1465. # select overlay decoration options dialog
  1466. clickposition = event.GetPositionTuple()[:]
  1467. idlist = self.pdc.FindObjects(clickposition[0], clickposition[1], self.hitradius)
  1468. if idlist == []:
  1469. return
  1470. self.dragid = idlist[0]
  1471. # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
  1472. if self.dragid > 100:
  1473. self.currtxtid = self.dragid
  1474. self.parent.OnAddText(None)
  1475. elif self.dragid == 0:
  1476. self.parent.OnAddBarscale(None)
  1477. elif self.dragid == 1:
  1478. self.parent.OnAddLegend(None)
  1479. def OnRightDown(self, event):
  1480. """
  1481. Right mouse button pressed
  1482. """
  1483. Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
  1484. self.mouse["use"])
  1485. digitToolbar = self.parent.toolbars['vdigit']
  1486. if digitToolbar:
  1487. digitClass = self.parent.digit
  1488. # digitization tool (confirm action)
  1489. if digitToolbar.GetAction() in ("moveLine",
  1490. "moveVertex") and \
  1491. hasattr(self, "vdigitMove"):
  1492. pFrom = self.vdigitMove['begin']
  1493. pTo = self.Pixel2Cell(event.GetPositionTuple())
  1494. move = (pTo[0] - pFrom[0],
  1495. pTo[1] - pFrom[1])
  1496. if digitToolbar.GetAction() == "moveLine":
  1497. # move line
  1498. if digitClass.MoveSelectedLines(move) < 0:
  1499. return
  1500. elif digitToolbar.GetAction() == "moveVertex":
  1501. # move vertex
  1502. if digitClass.MoveSelectedVertex(pFrom, move) < 0:
  1503. return
  1504. del self.vdigitMove
  1505. event.Skip()
  1506. def OnRightUp(self, event):
  1507. """
  1508. Right mouse button released
  1509. """
  1510. Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
  1511. self.mouse["use"])
  1512. digitToolbar = self.parent.toolbars['vdigit']
  1513. if digitToolbar:
  1514. digitClass = self.parent.digit
  1515. # digitization tool (confirm action)
  1516. if digitToolbar.GetAction() == "addLine" and \
  1517. digitToolbar.GetAction('type') in ["line", "boundary"]:
  1518. # -> add new line / boundary
  1519. try:
  1520. map = digitToolbar.GetLayer().GetName()
  1521. except:
  1522. map = None
  1523. wx.MessageBox(parent=self,
  1524. message=_("No vector map selected for editing."),
  1525. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  1526. if map:
  1527. # mapcoords = []
  1528. # xy -> EN
  1529. # for coord in self.polycoords:
  1530. # mapcoords.append(self.Pixel2Cell(coord))
  1531. if digitToolbar.GetAction('type') == 'line':
  1532. line = True
  1533. else:
  1534. line = False
  1535. if len(self.polycoords) < 2: # ignore 'one-point' lines
  1536. return
  1537. fid = digitClass.AddLine(map, line, self.polycoords)
  1538. if fid < 0:
  1539. return
  1540. position = self.Cell2Pixel(self.polycoords[-1])
  1541. self.polycoords = []
  1542. self.UpdateMap(render=False)
  1543. self.redrawAll = True
  1544. # add new record into atribute table
  1545. if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled') is True:
  1546. posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
  1547. position[1] + self.dialogOffset))
  1548. # select attributes based on layer and category
  1549. cats = { fid : {
  1550. UserSettings.Get(group='vdigit', key="layer", subkey='value') :
  1551. (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
  1552. }}
  1553. addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
  1554. cats=cats,
  1555. pos=posWindow,
  1556. action="add")
  1557. if addRecordDlg.mapDBInfo and \
  1558. addRecordDlg.ShowModal() == wx.ID_OK:
  1559. sqlfile = tempfile.NamedTemporaryFile(mode="w")
  1560. for sql in addRecordDlg.GetSQLString():
  1561. sqlfile.file.write(sql + ";\n")
  1562. sqlfile.file.flush()
  1563. gcmd.RunCommand('db.execute',
  1564. parent = True,
  1565. quiet = True,
  1566. input = sqlfile.name)
  1567. elif digitToolbar.GetAction() == "deleteLine":
  1568. # -> delete selected vector features
  1569. if digitClass.DeleteSelectedLines() < 0:
  1570. return
  1571. elif digitToolbar.GetAction() == "splitLine":
  1572. # split line
  1573. if digitClass.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
  1574. return
  1575. elif digitToolbar.GetAction() == "addVertex":
  1576. # add vertex
  1577. if digitClass.AddVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
  1578. return
  1579. elif digitToolbar.GetAction() == "removeVertex":
  1580. # remove vertex
  1581. if digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
  1582. return
  1583. elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
  1584. try:
  1585. if digitToolbar.GetAction() == 'copyCats':
  1586. if digitClass.CopyCats(self.copyCatsList,
  1587. self.copyCatsIds, copyAttrb=False) < 0:
  1588. return
  1589. else:
  1590. if digitClass.CopyCats(self.copyCatsList,
  1591. self.copyCatsIds, copyAttrb=True) < 0:
  1592. return
  1593. del self.copyCatsList
  1594. del self.copyCatsIds
  1595. except AttributeError:
  1596. pass
  1597. elif digitToolbar.GetAction() == "editLine" and \
  1598. hasattr(self, "vdigitMove"):
  1599. line = digitClass.driver.GetSelected()
  1600. if digitClass.EditLine(line, self.polycoords) < 0:
  1601. return
  1602. del self.vdigitMove
  1603. elif digitToolbar.GetAction() == "flipLine":
  1604. if digitClass.FlipLine() < 0:
  1605. return
  1606. elif digitToolbar.GetAction() == "mergeLine":
  1607. if digitClass.MergeLine() < 0:
  1608. return
  1609. elif digitToolbar.GetAction() == "breakLine":
  1610. if digitClass.BreakLine() < 0:
  1611. return
  1612. elif digitToolbar.GetAction() == "snapLine":
  1613. if digitClass.SnapLine() < 0:
  1614. return
  1615. elif digitToolbar.GetAction() == "connectLine":
  1616. if len(digitClass.driver.GetSelected()) > 1:
  1617. if digitClass.ConnectLine() < 0:
  1618. return
  1619. elif digitToolbar.GetAction() == "copyLine":
  1620. if digitClass.CopyLine(self.copyIds) < 0:
  1621. return
  1622. del self.copyIds
  1623. if self.layerTmp:
  1624. self.Map.DeleteLayer(self.layerTmp)
  1625. self.UpdateMap(render=True, renderVector=False)
  1626. del self.layerTmp
  1627. elif digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
  1628. pos1 = self.polycoords[0]
  1629. pos2 = self.polycoords[1]
  1630. selected = digitClass.driver.GetSelected()
  1631. dlg = VDigitZBulkDialog(parent=self, title=_("Z bulk-labeling dialog"),
  1632. nselected=len(selected))
  1633. if dlg.ShowModal() == wx.ID_OK:
  1634. if digitClass.ZBulkLine(pos1, pos2, dlg.value.GetValue(),
  1635. dlg.step.GetValue()) < 0:
  1636. return
  1637. self.UpdateMap(render=False, renderVector=True)
  1638. elif digitToolbar.GetAction() == "typeConv":
  1639. # -> feature type conversion
  1640. # - point <-> centroid
  1641. # - line <-> boundary
  1642. if digitClass.TypeConvForSelectedLines() < 0:
  1643. return
  1644. if digitToolbar.GetAction() != "addLine":
  1645. # unselect and re-render
  1646. digitClass.driver.SetSelected([])
  1647. self.polycoords = []
  1648. self.UpdateMap(render=False)
  1649. self.redrawAll = True
  1650. event.Skip()
  1651. def OnMiddleDown(self, event):
  1652. """
  1653. Middle mouse button pressed
  1654. """
  1655. digitToolbar = self.parent.toolbars['vdigit']
  1656. # digitization tool
  1657. if self.mouse["use"] == "pointer" and digitToolbar:
  1658. digitClass = self.parent.digit
  1659. if (digitToolbar.GetAction() == "addLine" and \
  1660. digitToolbar.GetAction('type') in ["line", "boundary"]) or \
  1661. digitToolbar.GetAction() == "editLine":
  1662. # add line or boundary -> remove last point from the line
  1663. try:
  1664. removed = self.polycoords.pop()
  1665. Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
  1666. [removed,])
  1667. self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
  1668. except:
  1669. pass
  1670. if digitToolbar.GetAction() == "editLine":
  1671. # remove last vertex & line
  1672. if len(self.vdigitMove['id']) > 1:
  1673. self.vdigitMove['id'].pop()
  1674. self.UpdateMap(render=False, renderVector=False)
  1675. elif digitToolbar.GetAction() in ["deleteLine", "moveLine", "splitLine",
  1676. "addVertex", "removeVertex", "moveVertex",
  1677. "copyCats", "flipLine", "mergeLine",
  1678. "snapLine", "connectLine", "copyLine",
  1679. "queryLine", "breakLine", "typeConv"]:
  1680. # varios tools -> unselected selected features
  1681. digitClass.driver.SetSelected([])
  1682. if digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
  1683. hasattr(self, "vdigitMove"):
  1684. del self.vdigitMove
  1685. elif digitToolbar.GetAction() == "copyCats":
  1686. try:
  1687. del self.copyCatsList
  1688. del self.copyCatsIds
  1689. except AttributeError:
  1690. pass
  1691. elif digitToolbar.GetAction() == "copyLine":
  1692. del self.copyIds
  1693. if self.layerTmp:
  1694. self.Map.DeleteLayer(self.layerTmp)
  1695. self.UpdateMap(render=True, renderVector=False)
  1696. del self.layerTmp
  1697. self.polycoords = []
  1698. self.UpdateMap(render=False) # render vector
  1699. elif digitToolbar.GetAction() == "zbulkLine":
  1700. # reset polyline
  1701. self.polycoords = []
  1702. digitClass.driver.SetSelected([])
  1703. self.UpdateMap(render=False)
  1704. self.redrawAll = True
  1705. def OnMouseMoving(self, event):
  1706. """
  1707. Motion event and no mouse buttons were pressed
  1708. """
  1709. digitToolbar = self.parent.toolbars['vdigit']
  1710. if self.mouse["use"] == "pointer" and digitToolbar:
  1711. digitClass = self.parent.digit
  1712. self.mouse['end'] = event.GetPositionTuple()[:]
  1713. Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
  1714. (self.mouse['end'][0], self.mouse['end'][1]))
  1715. if digitToolbar.GetAction() == "addLine" and digitToolbar.GetAction('type') in ["line", "boundary"]:
  1716. if len(self.polycoords) > 0:
  1717. self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1]))
  1718. elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] \
  1719. and hasattr(self, "vdigitMove"):
  1720. dx = self.mouse['end'][0] - self.mouse['begin'][0]
  1721. dy = self.mouse['end'][1] - self.mouse['begin'][1]
  1722. if len(self.vdigitMove['id']) > 0:
  1723. # draw lines on new position
  1724. if digitToolbar.GetAction() == "moveLine":
  1725. # move line
  1726. for id in self.vdigitMove['id']:
  1727. self.pdcTmp.TranslateId(id, dx, dy)
  1728. elif digitToolbar.GetAction() in ["moveVertex", "editLine"]:
  1729. # move vertex ->
  1730. # (vertex, left vertex, left line,
  1731. # right vertex, right line)
  1732. # do not draw static lines
  1733. if digitToolbar.GetAction() == "moveVertex":
  1734. self.polycoords = []
  1735. ### self.pdcTmp.TranslateId(self.vdigitMove['id'][0], dx, dy)
  1736. self.pdcTmp.RemoveId(self.vdigitMove['id'][0])
  1737. if self.vdigitMove['id'][1] > 0: # previous vertex
  1738. x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][1])[0:2])
  1739. self.pdcTmp.RemoveId(self.vdigitMove['id'][1]+1)
  1740. self.polycoords.append((x, y))
  1741. ### x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][0])[0:2])
  1742. self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
  1743. if self.vdigitMove['id'][2] > 0: # next vertex
  1744. x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][2])[0:2])
  1745. self.pdcTmp.RemoveId(self.vdigitMove['id'][2]-1)
  1746. self.polycoords.append((x, y))
  1747. self.ClearLines(pdc=self.pdcTmp)
  1748. self.DrawLines(pdc=self.pdcTmp)
  1749. else: # edit line
  1750. try:
  1751. if self.vdigitMove['id'][-1] > 0: # previous vertex
  1752. self.MouseDraw(pdc=self.pdcTmp,
  1753. begin=self.Cell2Pixel(self.polycoords[-1]))
  1754. except: # no line
  1755. self.vdigitMove['id'] = []
  1756. self.polycoords = []
  1757. self.Refresh() # TODO: use RefreshRect()
  1758. self.mouse['begin'] = self.mouse['end']
  1759. elif digitToolbar.GetAction() == "zbulkLine":
  1760. if len(self.polycoords) == 1:
  1761. # draw mouse moving
  1762. self.MouseDraw(self.pdcTmp)
  1763. event.Skip()
  1764. def ClearLines(self, pdc=None):
  1765. """
  1766. Clears temporary drawn lines from PseudoDC
  1767. """
  1768. if not pdc:
  1769. pdc=self.pdcTmp
  1770. try:
  1771. pdc.ClearId(self.lineid)
  1772. pdc.RemoveId(self.lineid)
  1773. except:
  1774. pass
  1775. try:
  1776. pdc.ClearId(self.plineid)
  1777. pdc.RemoveId(self.plineid)
  1778. except:
  1779. pass
  1780. Debug.msg(4, "BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
  1781. (self.lineid, self.plineid))
  1782. ### self.Refresh()
  1783. return True
  1784. def Pixel2Cell(self, (x, y)):
  1785. """
  1786. Convert image coordinates to real word coordinates
  1787. Input : int x, int y
  1788. Output: float x, float y
  1789. """
  1790. try:
  1791. x = int(x)
  1792. y = int(y)
  1793. except:
  1794. return None
  1795. if self.Map.region["ewres"] > self.Map.region["nsres"]:
  1796. res = self.Map.region["ewres"]
  1797. else:
  1798. res = self.Map.region["nsres"]
  1799. w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
  1800. n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
  1801. east = w + x * res
  1802. north = n - y * res
  1803. # extent does not correspond with whole map canvas area...
  1804. # east = self.Map.region['w'] + x * self.Map.region["ewres"]
  1805. # north = self.Map.region['n'] - y * self.Map.region["nsres"]
  1806. return (east, north)
  1807. def Cell2Pixel(self, (east, north)):
  1808. """
  1809. Convert real word coordinates to image coordinates
  1810. """
  1811. try:
  1812. east = float(east)
  1813. north = float(north)
  1814. except:
  1815. return None
  1816. if self.Map.region["ewres"] > self.Map.region["nsres"]:
  1817. res = self.Map.region["ewres"]
  1818. else:
  1819. res = self.Map.region["nsres"]
  1820. w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
  1821. n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
  1822. # x = int((east - w) / res)
  1823. # y = int((n - north) / res)
  1824. x = (east - w) / res
  1825. y = (n - north) / res
  1826. return (x, y)
  1827. def Zoom(self, begin, end, zoomtype):
  1828. """
  1829. Calculates new region while (un)zoom/pan-ing
  1830. """
  1831. x1, y1 = begin
  1832. x2, y2 = end
  1833. newreg = {}
  1834. # threshold - too small squares do not make sense
  1835. # can only zoom to windows of > 5x5 screen pixels
  1836. if abs(x2-x1) > 5 and abs(y2-y1) > 5 and zoomtype != 0:
  1837. if x1 > x2:
  1838. x1, x2 = x2, x1
  1839. if y1 > y2:
  1840. y1, y2 = y2, y1
  1841. # zoom in
  1842. if zoomtype > 0:
  1843. newreg['w'], newreg['n'] = self.Pixel2Cell((x1, y1))
  1844. newreg['e'], newreg['s'] = self.Pixel2Cell((x2, y2))
  1845. # zoom out
  1846. elif zoomtype < 0:
  1847. newreg['w'], newreg['n'] = self.Pixel2Cell((-x1 * 2, -y1 * 2))
  1848. newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width + 2 * \
  1849. (self.Map.width - x2),
  1850. self.Map.height + 2 * \
  1851. (self.Map.height - y2)))
  1852. # pan
  1853. elif zoomtype == 0:
  1854. dx = x1 - x2
  1855. dy = y1 - y2
  1856. newreg['w'], newreg['n'] = self.Pixel2Cell((dx, dy))
  1857. newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width + dx,
  1858. self.Map.height + dy))
  1859. # if new region has been calculated, set the values
  1860. if newreg != {}:
  1861. # LL locations
  1862. if self.parent.Map.projinfo['proj'] == 'll':
  1863. if newreg['n'] > 90.0:
  1864. newreg['n'] = 90.0
  1865. if newreg['s'] < -90.0:
  1866. newreg['s'] = -90.0
  1867. ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
  1868. cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
  1869. if hasattr(self, "vdigitMove"):
  1870. # xo = self.Cell2Pixel((self.Map.region['center_easting'], self.Map.region['center_northing']))
  1871. # xn = self.Cell2Pixel(ce, cn))
  1872. tmp = self.Pixel2Cell(self.mouse['end'])
  1873. # calculate new center point and display resolution
  1874. self.Map.region['center_easting'] = ce
  1875. self.Map.region['center_northing'] = cn
  1876. self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
  1877. self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height
  1878. self.Map.AlignExtentFromDisplay()
  1879. if hasattr(self, "vdigitMove"):
  1880. tmp1 = self.mouse['end']
  1881. tmp2 = self.Cell2Pixel(self.vdigitMove['begin'])
  1882. dx = tmp1[0] - tmp2[0]
  1883. dy = tmp1[1] - tmp2[1]
  1884. self.vdigitMove['beginDiff'] = (dx, dy)
  1885. for id in self.vdigitMove['id']:
  1886. self.pdcTmp.RemoveId(id)
  1887. self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
  1888. self.Map.region['e'], self.Map.region['w'])
  1889. if self.redrawAll is False:
  1890. self.redrawAll = True
  1891. def ZoomBack(self):
  1892. """
  1893. Zoom to previous extents in zoomhistory list
  1894. """
  1895. zoom = []
  1896. if len(self.zoomhistory) > 1:
  1897. self.zoomhistory.pop()
  1898. zoom = self.zoomhistory[len(self.zoomhistory)-1]
  1899. # (n, s, e, w)
  1900. if zoom:
  1901. # zoom to selected region
  1902. self.Map.region['center_easting'] = zoom[3] + \
  1903. (zoom[2] - zoom[3]) / 2
  1904. self.Map.region['center_northing'] = zoom[1] + \
  1905. (zoom[0] - zoom[1]) / 2
  1906. self.Map.region["ewres"] = (zoom[2] - zoom[3]) / self.Map.width
  1907. self.Map.region["nsres"] = (zoom[0] - zoom[1]) / self.Map.height
  1908. self.Map.AlignExtentFromDisplay()
  1909. # update map
  1910. self.UpdateMap()
  1911. # update statusbar
  1912. self.parent.StatusbarUpdate()
  1913. def ZoomHistory(self, n, s, e, w):
  1914. """
  1915. Manages a list of last 10 zoom extents
  1916. Return removed history item if exists
  1917. """
  1918. removed = None
  1919. self.zoomhistory.append((n,s,e,w))
  1920. if len(self.zoomhistory) > 10:
  1921. removed = self.zoomhistory.pop(0)
  1922. if removed:
  1923. Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
  1924. (self.zoomhistory, removed))
  1925. else:
  1926. Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s" %
  1927. (self.zoomhistory))
  1928. return removed
  1929. def OnZoomToMap(self, event):
  1930. """
  1931. Set display extents to match selected raster (including NULLs)
  1932. or vector map.
  1933. """
  1934. self.ZoomToMap()
  1935. def OnZoomToRaster(self, event):
  1936. """
  1937. Set display extents to match selected raster map (ignore NULLs)
  1938. """
  1939. self.ZoomToMap(zoom=True)
  1940. def ZoomToMap(self, layer=None, zoom=False):
  1941. """
  1942. Set display extents to match selected raster
  1943. or vector map.
  1944. """
  1945. zoomreg = {}
  1946. if not layer:
  1947. layer = self.GetSelectedLayer()
  1948. if layer is None:
  1949. return
  1950. Debug.msg (3, "BufferedWindow.ZoomToMap(): layer=%s, type=%s" % \
  1951. (layer.name, layer.type))
  1952. # selected layer must be a valid map
  1953. if layer.type in ('raster', 'rgb', 'his', 'shaded', 'arrow'):
  1954. if layer.type == 'raster':
  1955. self.Map.region = self.Map.GetRegion(rast="%s" % layer.name)
  1956. else:
  1957. self.Map.region = self.Map.GetRegion(rast="%s" % layer.name)
  1958. elif layer.type in ('vector', 'thememap', 'themechart'):
  1959. if self.parent.digit and layer.name == self.parent.digit.map and \
  1960. self.parent.digit.type == 'vdigit':
  1961. w, s, b, e, n, t = self.parent.digit.driver.GetMapBoundingBox()
  1962. self.Map.region = self.Map.GetRegion(n=n, s=s, w=w, e=e)
  1963. else:
  1964. self.Map.region = self.Map.GetRegion(vect="%s" % layer.name)
  1965. else:
  1966. return
  1967. ### self.Map.SetRegion()
  1968. ### self.Map.AlignExtentFromDisplay()
  1969. self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
  1970. self.Map.region['e'], self.Map.region['w'])
  1971. self.UpdateMap()
  1972. self.parent.StatusbarUpdate()
  1973. def ZoomToWind(self, event):
  1974. """
  1975. Set display geometry to match computational
  1976. region settings (set with g.region)
  1977. """
  1978. self.Map.region = self.Map.GetRegion()
  1979. ### self.Map.SetRegion(windres=True)
  1980. self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
  1981. self.Map.region['e'], self.Map.region['w'])
  1982. self.UpdateMap()
  1983. self.parent.StatusbarUpdate()
  1984. def ZoomToDefault(self, event):
  1985. """
  1986. Set display geometry to match default region settings
  1987. """
  1988. self.Map.region = self.Map.GetRegion(default=True)
  1989. self.Map.AdjustRegion() # aling region extent to the display
  1990. self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
  1991. self.Map.region['e'], self.Map.region['w'])
  1992. self.UpdateMap()
  1993. self.parent.StatusbarUpdate()
  1994. def DisplayToWind(self, event):
  1995. """
  1996. Set computational region (WIND file) to
  1997. match display extents
  1998. """
  1999. tmpreg = os.getenv("GRASS_REGION")
  2000. if tmpreg:
  2001. del os.environ["GRASS_REGION"]
  2002. # We ONLY want to set extents here. Don't mess with resolution. Leave that
  2003. # for user to set explicitly with g.region
  2004. new = self.Map.AlignResolution()
  2005. gcmd.RunCommand('g.region',
  2006. parent = self,
  2007. overwrite = True,
  2008. n = new['n'],
  2009. s = new['s'],
  2010. e = new['e'],
  2011. w = new['w'],
  2012. rows = int(new['rows']),
  2013. cols = int(new['cols']))
  2014. if tmpreg:
  2015. os.environ["GRASS_REGION"] = tmpreg
  2016. def ZoomToSaved(self, event):
  2017. """
  2018. Set display geometry to match extents in
  2019. saved region file
  2020. """
  2021. zoomreg = {}
  2022. dlg = gdialogs.SavedRegion(self, wx.ID_ANY, _("Zoom to saved region extents"),
  2023. pos=wx.DefaultPosition, size=wx.DefaultSize,
  2024. style=wx.DEFAULT_DIALOG_STYLE,
  2025. loadsave='load')
  2026. if dlg.ShowModal() == wx.ID_CANCEL:
  2027. dlg.Destroy()
  2028. return
  2029. wind = dlg.wind
  2030. region = gcmd.RunCommand('g.region',
  2031. parent = self,
  2032. read = True,
  2033. flags = 'ugp',
  2034. region = wind)
  2035. if not region:
  2036. dlg.Destroy()
  2037. return
  2038. for line in region.splitlines():
  2039. key, val = line.split('=')
  2040. zoomreg[key.strip()] = float(val.strip())
  2041. self.Map.region['n'] = zoomreg['n']
  2042. self.Map.region['s'] = zoomreg['s']
  2043. self.Map.region['e'] = zoomreg['e']
  2044. self.Map.region['w'] = zoomreg['w']
  2045. self.ZoomHistory(self.Map.region['n'],
  2046. self.Map.region['s'],
  2047. self.Map.region['e'],
  2048. self.Map.region['w'])
  2049. self.UpdateMap()
  2050. dlg.Destroy()
  2051. def SaveDisplayRegion(self, event):
  2052. """
  2053. Save display extents to named region file.
  2054. """
  2055. dlg = gdialogs.SavedRegion(self, wx.ID_ANY, "Save display extents to region file",
  2056. pos=wx.DefaultPosition, size=wx.DefaultSize,
  2057. style=wx.DEFAULT_DIALOG_STYLE,
  2058. loadsave='save')
  2059. if dlg.ShowModal() == wx.ID_CANCEL:
  2060. dlg.Destroy()
  2061. return
  2062. wind = dlg.wind
  2063. # test to see if it already exists and ask permission to overwrite
  2064. windpath = os.path.join(self.Map.env["GISDBASE"], self.Map.env["LOCATION_NAME"],
  2065. self.Map.env["MAPSET"],"windows",wind)
  2066. if windpath and not os.path.exists(windpath):
  2067. self.SaveRegion(wind)
  2068. elif windpath and os.path.exists(windpath):
  2069. overwrite = wx.MessageBox(_("Region file <%s> already exists. "
  2070. "Do you want to overwrite it?") % (wind),
  2071. _("Warning"), wx.YES_NO)
  2072. if (overwrite == wx.YES):
  2073. self.SaveRegion(wind)
  2074. else:
  2075. pass
  2076. dlg.Destroy()
  2077. def SaveRegion(self, wind):
  2078. """
  2079. Save region settings
  2080. """
  2081. new = self.Map.AlignResolution()
  2082. cmdRegion = ["g.region",
  2083. "-u",
  2084. "n=%f" % new['n'],
  2085. "s=%f" % new['s'],
  2086. "e=%f" % new['e'],
  2087. "w=%f" % new['w'],
  2088. "rows=%d" % new['rows'],
  2089. "cols=%d" % new['cols'],
  2090. "save=%s" % wind,
  2091. "--o"]
  2092. tmpreg = os.getenv("GRASS_REGION")
  2093. if tmpreg:
  2094. del os.environ["GRASS_REGION"]
  2095. gcmd.RunCommand('g.region',
  2096. overwrite = True,
  2097. parent = self,
  2098. flags = 'u',
  2099. n = new['n'],
  2100. s = new['s'],
  2101. e = new['e'],
  2102. w = new['w'],
  2103. rows = int(new['rows']),
  2104. cols = int(new['cols']),
  2105. save = wind)
  2106. if tmpreg:
  2107. os.environ["GRASS_REGION"] = tmpreg
  2108. def Distance(self, beginpt, endpt, screen=True):
  2109. """Calculete distance
  2110. LL-locations not supported
  2111. @todo Use m.distance
  2112. @param beginpt first point
  2113. @param endpt second point
  2114. @param screen True for screen coordinates otherwise EN
  2115. """
  2116. x1, y1 = beginpt
  2117. x2, y2 = endpt
  2118. if screen:
  2119. dEast = (x2 - x1) * self.Map.region["ewres"]
  2120. dNorth = (y2 - y1) * self.Map.region["nsres"]
  2121. else:
  2122. dEast = (x2 - x1)
  2123. dNorth = (y2 - y1)
  2124. return (math.sqrt(math.pow((dEast),2) + math.pow((dNorth),2)), (dEast, dNorth))