mapdisp_window.py 94 KB

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