manager.py 111 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549
  1. """
  2. @package gcp.manager
  3. @brief Georectification module for GRASS GIS. Includes ground control
  4. point management and interactive point and click GCP creation
  5. Classes:
  6. - manager::GCPWizard
  7. - manager::LocationPage
  8. - manager::GroupPage
  9. - manager::DispMapPage
  10. - manager::GCP
  11. - manager::GCPList
  12. - manager::VectGroup
  13. - manager::EditGCP
  14. - manager::GrSettingsDialog
  15. (C) 2006-2014 by the GRASS Development Team
  16. This program is free software under the GNU General Public License
  17. (>=v2). Read the file COPYING that comes with GRASS for details.
  18. @author Original author Michael Barton
  19. @author Original version improved by Martin Landa <landa.martin gmail.com>
  20. @author Rewritten by Markus Metz redesign georectfier -> GCP Manage
  21. @author Support for GraphicsSet added by Stepan Turek <stepan.turek seznam.cz> (2012)
  22. """
  23. from __future__ import print_function
  24. import os
  25. import sys
  26. import shutil
  27. import six
  28. from copy import copy
  29. import wx
  30. from wx.lib.mixins.listctrl import ColumnSorterMixin, ListCtrlAutoWidthMixin
  31. import wx.lib.colourselect as csel
  32. from core import globalvar
  33. if globalvar.wxPythonPhoenix:
  34. from wx import adv as wiz
  35. else:
  36. from wx import wizard as wiz
  37. import grass.script as grass
  38. from core import utils
  39. from core.render import Map
  40. from gui_core.gselect import Select, LocationSelect, MapsetSelect
  41. from gui_core.dialogs import GroupDialog
  42. from core.gcmd import RunCommand, GMessage, GError, GWarning
  43. from core.settings import UserSettings
  44. from gcp.mapdisplay import MapFrame
  45. from core.giface import Notification
  46. from gui_core.wrap import (
  47. SpinCtrl,
  48. Button,
  49. StaticText,
  50. StaticBox,
  51. CheckListBox,
  52. TextCtrl,
  53. Menu,
  54. ListCtrl,
  55. BitmapFromImage,
  56. CheckListCtrlMixin,
  57. )
  58. from location_wizard.wizard import GridBagSizerTitledPage as TitledPage
  59. #
  60. # global variables
  61. #
  62. global src_map
  63. global tgt_map
  64. global maptype
  65. src_map = ""
  66. tgt_map = {"raster": "", "vector": ""}
  67. maptype = "raster"
  68. def getSmallUpArrowImage():
  69. stream = open(os.path.join(globalvar.IMGDIR, "small_up_arrow.png"), "rb")
  70. try:
  71. img = wx.Image(stream)
  72. finally:
  73. stream.close()
  74. return img
  75. def getSmallDnArrowImage():
  76. stream = open(os.path.join(globalvar.IMGDIR, "small_down_arrow.png"), "rb")
  77. try:
  78. img = wx.Image(stream)
  79. finally:
  80. stream.close()
  81. stream.close()
  82. return img
  83. class GCPWizard(object):
  84. """
  85. Start wizard here and finish wizard here
  86. """
  87. def __init__(self, parent, giface):
  88. self.parent = parent # GMFrame
  89. self._giface = giface
  90. #
  91. # get environmental variables
  92. #
  93. self.grassdatabase = grass.gisenv()["GISDBASE"]
  94. #
  95. # read original environment settings
  96. #
  97. self.target_gisrc = os.environ["GISRC"]
  98. self.gisrc_dict = {}
  99. try:
  100. f = open(self.target_gisrc, "r")
  101. for line in f.readlines():
  102. line = line.replace("\n", "").strip()
  103. if len(line) < 1:
  104. continue
  105. key, value = line.split(":", 1)
  106. self.gisrc_dict[key.strip()] = value.strip()
  107. finally:
  108. f.close()
  109. self.currentlocation = self.gisrc_dict["LOCATION_NAME"]
  110. self.currentmapset = self.gisrc_dict["MAPSET"]
  111. # location for xy map to georectify
  112. self.newlocation = ""
  113. # mapset for xy map to georectify
  114. self.newmapset = ""
  115. global maptype
  116. global src_map
  117. global tgt_map
  118. # src_map = ''
  119. # tgt_map = ''
  120. maptype = "raster"
  121. # GISRC file for source location/mapset of map(s) to georectify
  122. self.source_gisrc = ""
  123. self.src_maps = []
  124. #
  125. # define wizard pages
  126. #
  127. self.wizard = wiz.Wizard(
  128. parent=parent, id=wx.ID_ANY, title=_("Setup for georectification")
  129. )
  130. self.startpage = LocationPage(self.wizard, self)
  131. self.grouppage = GroupPage(self.wizard, self)
  132. self.mappage = DispMapPage(self.wizard, self)
  133. #
  134. # set the initial order of the pages
  135. #
  136. self.startpage.SetNext(self.grouppage)
  137. self.grouppage.SetPrev(self.startpage)
  138. self.grouppage.SetNext(self.mappage)
  139. self.mappage.SetPrev(self.grouppage)
  140. #
  141. # do pages layout
  142. #
  143. self.startpage.DoLayout()
  144. self.grouppage.DoLayout()
  145. self.mappage.DoLayout()
  146. self.wizard.FitToPage(self.startpage)
  147. # self.Bind(wx.EVT_CLOSE, self.Cleanup)
  148. # self.parent.Bind(wx.EVT_ACTIVATE, self.OnGLMFocus)
  149. success = False
  150. #
  151. # run wizard
  152. #
  153. if self.wizard.RunWizard(self.startpage):
  154. success = self.OnWizFinished()
  155. if not success:
  156. GMessage(parent=self.parent, message=_("Georectifying setup canceled."))
  157. self.Cleanup()
  158. else:
  159. GMessage(parent=self.parent, message=_("Georectifying setup canceled."))
  160. self.Cleanup()
  161. #
  162. # start GCP display
  163. #
  164. if success:
  165. # instance of render.Map to be associated with display
  166. self.SwitchEnv("source")
  167. self.SrcMap = Map(gisrc=self.source_gisrc)
  168. self.SwitchEnv("target")
  169. self.TgtMap = Map(gisrc=self.target_gisrc)
  170. self.Map = self.SrcMap
  171. #
  172. # add layer to source map
  173. #
  174. if maptype == "raster":
  175. rendertype = "raster"
  176. cmdlist = ["d.rast", "map=%s" % src_map]
  177. else: # -> vector layer
  178. rendertype = "vector"
  179. cmdlist = ["d.vect", "map=%s" % src_map]
  180. self.SwitchEnv("source")
  181. name, found = utils.GetLayerNameFromCmd(cmdlist)
  182. self.SrcMap.AddLayer(
  183. ltype=rendertype,
  184. command=cmdlist,
  185. active=True,
  186. name=name,
  187. hidden=False,
  188. opacity=1.0,
  189. render=False,
  190. )
  191. self.SwitchEnv("target")
  192. web_service_layer = self.mappage.GetWebServiceLayers(name=tgt_map["raster"])
  193. if tgt_map["raster"] and web_service_layer:
  194. #
  195. # add web service layer to target map
  196. #
  197. rendertype = web_service_layer["type"]
  198. cmdlist = web_service_layer["cmd"]
  199. name = tgt_map["raster"]
  200. self.TgtMap.AddLayer(
  201. ltype=rendertype,
  202. command=cmdlist,
  203. active=True,
  204. name=name,
  205. hidden=False,
  206. opacity=1.0,
  207. render=False,
  208. )
  209. elif tgt_map["raster"]:
  210. #
  211. # add raster layer to target map
  212. #
  213. rendertype = "raster"
  214. cmdlist = ["d.rast", "map=%s" % tgt_map["raster"]]
  215. name, found = utils.GetLayerNameFromCmd(cmdlist)
  216. self.TgtMap.AddLayer(
  217. ltype=rendertype,
  218. command=cmdlist,
  219. active=True,
  220. name=name,
  221. hidden=False,
  222. opacity=1.0,
  223. render=False,
  224. )
  225. if tgt_map["vector"]:
  226. #
  227. # add raster layer to target map
  228. #
  229. rendertype = "vector"
  230. cmdlist = ["d.vect", "map=%s" % tgt_map["vector"]]
  231. name, found = utils.GetLayerNameFromCmd(cmdlist)
  232. self.TgtMap.AddLayer(
  233. ltype=rendertype,
  234. command=cmdlist,
  235. active=True,
  236. name=name,
  237. hidden=False,
  238. opacity=1.0,
  239. render=False,
  240. )
  241. #
  242. # start GCP Manager
  243. #
  244. self.gcpmgr = GCP(
  245. self.parent,
  246. giface=self._giface,
  247. grwiz=self,
  248. size=globalvar.MAP_WINDOW_SIZE,
  249. toolbars=["gcpdisp"],
  250. Map=self.SrcMap,
  251. lmgr=self.parent,
  252. )
  253. # load GCPs
  254. self.gcpmgr.InitMapDisplay()
  255. self.gcpmgr.CenterOnScreen()
  256. self.gcpmgr.Show()
  257. # need to update AUI here for wingrass
  258. self.gcpmgr._mgr.Update()
  259. else:
  260. self.Cleanup()
  261. def SetSrcEnv(self, location, mapset):
  262. """Create environment to use for location and mapset
  263. that are the source of the file(s) to georectify
  264. :param location: source location
  265. :param mapset: source mapset
  266. :return: False on error
  267. :return: True on success
  268. """
  269. self.newlocation = location
  270. self.newmapset = mapset
  271. # check to see if we are georectifying map in current working
  272. # location/mapset
  273. if (
  274. self.newlocation == self.currentlocation
  275. and self.newmapset == self.currentmapset
  276. ):
  277. return False
  278. self.gisrc_dict["LOCATION_NAME"] = location
  279. self.gisrc_dict["MAPSET"] = mapset
  280. self.source_gisrc = utils.GetTempfile()
  281. try:
  282. f = open(self.source_gisrc, mode="w")
  283. for line in self.gisrc_dict.items():
  284. f.write(line[0] + ": " + line[1] + "\n")
  285. finally:
  286. f.close()
  287. return True
  288. def SwitchEnv(self, grc):
  289. """
  290. Switches between original working location/mapset and
  291. location/mapset that is source of file(s) to georectify
  292. """
  293. # check to see if we are georectifying map in current working
  294. # location/mapset
  295. if (
  296. self.newlocation == self.currentlocation
  297. and self.newmapset == self.currentmapset
  298. ):
  299. return False
  300. if grc == "target":
  301. os.environ["GISRC"] = str(self.target_gisrc)
  302. elif grc == "source":
  303. os.environ["GISRC"] = str(self.source_gisrc)
  304. return True
  305. def OnWizFinished(self):
  306. # self.Cleanup()
  307. return True
  308. def OnGLMFocus(self, event):
  309. """Layer Manager focus"""
  310. # self.SwitchEnv('target')
  311. event.Skip()
  312. def Cleanup(self):
  313. """Return to current location and mapset"""
  314. # here was also the cleaning of gcpmanagement from layer manager
  315. # which is no longer needed
  316. self.SwitchEnv("target")
  317. self.wizard.Destroy()
  318. class LocationPage(TitledPage):
  319. """
  320. Set map type (raster or vector) to georectify and
  321. select location/mapset of map(s) to georectify.
  322. """
  323. def __init__(self, wizard, parent):
  324. TitledPage.__init__(self, wizard, _("Select map type and location/mapset"))
  325. self.parent = parent
  326. self.grassdatabase = self.parent.grassdatabase
  327. self.xylocation = ""
  328. self.xymapset = ""
  329. #
  330. # layout
  331. #
  332. # map type
  333. self.rb_maptype = wx.RadioBox(
  334. parent=self,
  335. id=wx.ID_ANY,
  336. label=" %s " % _("Map type to georectify"),
  337. choices=[_("raster"), _("vector")],
  338. majorDimension=wx.RA_SPECIFY_COLS,
  339. )
  340. self.sizer.Add(
  341. self.rb_maptype,
  342. flag=wx.ALIGN_CENTER | wx.ALL | wx.EXPAND,
  343. border=5,
  344. pos=(1, 1),
  345. span=(1, 2),
  346. )
  347. # location
  348. self.sizer.Add(
  349. StaticText(parent=self, id=wx.ID_ANY, label=_("Select source location:")),
  350. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  351. border=5,
  352. pos=(2, 1),
  353. )
  354. self.cb_location = LocationSelect(parent=self, gisdbase=self.grassdatabase)
  355. self.sizer.Add(
  356. self.cb_location,
  357. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  358. border=5,
  359. pos=(2, 2),
  360. )
  361. # mapset
  362. self.sizer.Add(
  363. StaticText(parent=self, id=wx.ID_ANY, label=_("Select source mapset:")),
  364. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  365. border=5,
  366. pos=(3, 1),
  367. )
  368. self.cb_mapset = MapsetSelect(
  369. parent=self, gisdbase=self.grassdatabase, setItems=False
  370. )
  371. self.sizer.Add(
  372. self.cb_mapset,
  373. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  374. border=5,
  375. pos=(3, 2),
  376. )
  377. self.sizer.AddGrowableCol(2)
  378. #
  379. # bindings
  380. #
  381. self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
  382. self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
  383. self.cb_mapset.Bind(wx.EVT_TEXT, self.OnMapset)
  384. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  385. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  386. # self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  387. def OnMaptype(self, event):
  388. """Change map type"""
  389. global maptype
  390. if event.GetInt() == 0:
  391. maptype = "raster"
  392. else:
  393. maptype = "vector"
  394. def OnLocation(self, event):
  395. """Sets source location for map(s) to georectify"""
  396. self.xylocation = event.GetString()
  397. # create a list of valid mapsets
  398. tmplist = os.listdir(os.path.join(self.grassdatabase, self.xylocation))
  399. self.mapsetList = []
  400. for item in tmplist:
  401. if os.path.isdir(
  402. os.path.join(self.grassdatabase, self.xylocation, item)
  403. ) and os.path.exists(
  404. os.path.join(self.grassdatabase, self.xylocation, item, "WIND")
  405. ):
  406. if item != "PERMANENT":
  407. self.mapsetList.append(item)
  408. self.xymapset = "PERMANENT"
  409. utils.ListSortLower(self.mapsetList)
  410. self.mapsetList.insert(0, "PERMANENT")
  411. self.cb_mapset.SetItems(self.mapsetList)
  412. self.cb_mapset.SetStringSelection(self.xymapset)
  413. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  414. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  415. def OnMapset(self, event):
  416. """Sets source mapset for map(s) to georectify"""
  417. if self.xylocation == "":
  418. GMessage(
  419. _("You must select a valid location " "before selecting a mapset"),
  420. parent=self,
  421. )
  422. return
  423. self.xymapset = event.GetString()
  424. if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
  425. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  426. def OnPageChanging(self, event=None):
  427. if event.GetDirection() and (self.xylocation == "" or self.xymapset == ""):
  428. GMessage(
  429. _(
  430. "You must select a valid location "
  431. "and mapset in order to continue"
  432. ),
  433. parent=self,
  434. )
  435. event.Veto()
  436. return
  437. self.parent.SetSrcEnv(self.xylocation, self.xymapset)
  438. def OnEnterPage(self, event=None):
  439. if self.xylocation == "" or self.xymapset == "":
  440. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  441. else:
  442. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  443. class GroupPage(TitledPage):
  444. """
  445. Set group to georectify. Create group if desired.
  446. """
  447. def __init__(self, wizard, parent):
  448. TitledPage.__init__(self, wizard, _("Select image/map group to georectify"))
  449. self.parent = parent
  450. self.grassdatabase = self.parent.grassdatabase
  451. self.groupList = []
  452. self.xylocation = ""
  453. self.xymapset = ""
  454. self.xygroup = ""
  455. # default extension
  456. self.extension = "_georect" + str(os.getpid())
  457. #
  458. # layout
  459. #
  460. # group
  461. self.sizer.Add(
  462. StaticText(parent=self, id=wx.ID_ANY, label=_("Select/create group:")),
  463. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  464. border=5,
  465. pos=(1, 1),
  466. )
  467. self.cb_group = wx.ComboBox(
  468. parent=self,
  469. id=wx.ID_ANY,
  470. choices=self.groupList,
  471. size=(350, -1),
  472. style=wx.CB_DROPDOWN,
  473. )
  474. self.sizer.Add(
  475. self.cb_group,
  476. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  477. border=5,
  478. pos=(1, 2),
  479. )
  480. # create group
  481. self.sizer.Add(
  482. StaticText(
  483. parent=self, id=wx.ID_ANY, label=_("Create group if none exists")
  484. ),
  485. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  486. border=5,
  487. pos=(2, 1),
  488. )
  489. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  490. self.btn_mkgroup = Button(
  491. parent=self, id=wx.ID_ANY, label=_("Create/edit group...")
  492. )
  493. self.btn_vgroup = Button(
  494. parent=self, id=wx.ID_ANY, label=_("Add vector map to group...")
  495. )
  496. btnSizer.Add(self.btn_mkgroup, flag=wx.RIGHT, border=5)
  497. btnSizer.Add(self.btn_vgroup, flag=wx.LEFT, border=5)
  498. self.sizer.Add(
  499. btnSizer,
  500. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  501. border=5,
  502. pos=(2, 2),
  503. )
  504. # extension
  505. self.sizer.Add(
  506. StaticText(
  507. parent=self, id=wx.ID_ANY, label=_("Extension for output maps:")
  508. ),
  509. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  510. border=5,
  511. pos=(3, 1),
  512. )
  513. self.ext_txt = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(350, -1))
  514. self.ext_txt.SetValue(self.extension)
  515. self.sizer.Add(
  516. self.ext_txt,
  517. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  518. border=5,
  519. pos=(3, 2),
  520. )
  521. self.sizer.AddGrowableCol(2)
  522. #
  523. # bindings
  524. #
  525. self.Bind(wx.EVT_COMBOBOX, self.OnGroup, self.cb_group)
  526. self.Bind(wx.EVT_TEXT, self.OnExtension, self.ext_txt)
  527. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  528. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  529. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  530. # hide vector group button by default
  531. self.btn_vgroup.Hide()
  532. def OnGroup(self, event):
  533. self.xygroup = event.GetString()
  534. def OnMkGroup(self, event):
  535. """Create new group in source location/mapset"""
  536. if self.xygroup == "":
  537. self.xygroup = self.cb_group.GetValue()
  538. dlg = GroupDialog(parent=self, defaultGroup=self.xygroup)
  539. dlg.DisableSubgroupEdit()
  540. dlg.ShowModal()
  541. gr, s = dlg.GetSelectedGroup()
  542. if gr in dlg.GetExistGroups():
  543. self.xygroup = gr
  544. else:
  545. gr = ""
  546. dlg.Destroy()
  547. self.OnEnterPage()
  548. self.Update()
  549. def OnVGroup(self, event):
  550. """Add vector maps to group"""
  551. if self.xygroup == "":
  552. self.xygroup = self.cb_group.GetValue()
  553. vector_dir = os.path.join(
  554. self.grassdatabase, self.xylocation, self.xymapset, "vector"
  555. )
  556. if os.path.exists(vector_dir):
  557. dlg = VectGroup(
  558. parent=self,
  559. id=wx.ID_ANY,
  560. grassdb=self.grassdatabase,
  561. location=self.xylocation,
  562. mapset=self.xymapset,
  563. group=self.xygroup,
  564. )
  565. if dlg.ShowModal() != wx.ID_OK:
  566. return
  567. dlg.MakeVGroup()
  568. self.OnEnterPage()
  569. else:
  570. GError(parent=self, message=_("No vector maps."))
  571. def OnExtension(self, event):
  572. self.extension = self.ext_txt.GetValue()
  573. def OnPageChanging(self, event=None):
  574. if event.GetDirection() and self.xygroup == "":
  575. GMessage(
  576. _("You must select a valid image/map " "group in order to continue"),
  577. parent=self,
  578. )
  579. event.Veto()
  580. return
  581. if event.GetDirection() and self.extension == "":
  582. GMessage(
  583. _("You must enter an map name " "extension in order to continue"),
  584. parent=self,
  585. )
  586. event.Veto()
  587. return
  588. def OnEnterPage(self, event=None):
  589. global maptype
  590. self.groupList = []
  591. self.xylocation = self.parent.gisrc_dict["LOCATION_NAME"]
  592. self.xymapset = self.parent.gisrc_dict["MAPSET"]
  593. # create a list of groups in selected mapset
  594. if os.path.isdir(
  595. os.path.join(self.grassdatabase, self.xylocation, self.xymapset, "group")
  596. ):
  597. tmplist = os.listdir(
  598. os.path.join(
  599. self.grassdatabase, self.xylocation, self.xymapset, "group"
  600. )
  601. )
  602. for item in tmplist:
  603. if os.path.isdir(
  604. os.path.join(
  605. self.grassdatabase,
  606. self.xylocation,
  607. self.xymapset,
  608. "group",
  609. item,
  610. )
  611. ):
  612. self.groupList.append(item)
  613. if maptype == "raster":
  614. self.btn_vgroup.Hide()
  615. self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
  616. elif maptype == "vector":
  617. self.btn_vgroup.Show()
  618. self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
  619. self.Bind(wx.EVT_BUTTON, self.OnVGroup, self.btn_vgroup)
  620. utils.ListSortLower(self.groupList)
  621. self.cb_group.SetItems(self.groupList)
  622. if len(self.groupList) > 0:
  623. if self.xygroup and self.xygroup in self.groupList:
  624. self.cb_group.SetStringSelection(self.xygroup)
  625. else:
  626. self.cb_group.SetSelection(0)
  627. self.xygroup = self.groupList[0]
  628. if self.xygroup == "" or self.extension == "":
  629. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  630. else:
  631. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  632. # switch to source
  633. self.parent.SwitchEnv("source")
  634. class DispMapPage(TitledPage):
  635. """
  636. Select ungeoreferenced map to display for interactively
  637. setting ground control points (GCPs).
  638. """
  639. def __init__(self, wizard, parent):
  640. TitledPage.__init__(
  641. self,
  642. wizard,
  643. _("Select maps to display for ground control point (GCP) creation"),
  644. )
  645. self.parent = parent
  646. global maptype
  647. self.web_servc_lyrs_root_node_name = _("Map Display Web Service Layer(s)")
  648. #
  649. # layout
  650. #
  651. self.sizer.Add(
  652. StaticText(
  653. parent=self, id=wx.ID_ANY, label=_("Select source map to display:")
  654. ),
  655. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  656. border=5,
  657. pos=(1, 1),
  658. )
  659. self.srcselection = Select(
  660. self,
  661. id=wx.ID_ANY,
  662. size=globalvar.DIALOG_GSELECT_SIZE,
  663. type=maptype,
  664. updateOnPopup=False,
  665. )
  666. self.sizer.Add(
  667. self.srcselection,
  668. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  669. border=5,
  670. pos=(1, 2),
  671. )
  672. self.sizer.Add(
  673. StaticText(
  674. parent=self,
  675. id=wx.ID_ANY,
  676. label=_("Select target raster map to display:"),
  677. ),
  678. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  679. border=5,
  680. pos=(2, 1),
  681. )
  682. self.tgtrastselection = Select(
  683. self,
  684. id=wx.ID_ANY,
  685. size=globalvar.DIALOG_GSELECT_SIZE,
  686. type="raster",
  687. updateOnPopup=False,
  688. extraItems=self.GetSelectTargetRasterExtraItems(),
  689. )
  690. self.sizer.Add(
  691. self.tgtrastselection,
  692. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  693. border=5,
  694. pos=(2, 2),
  695. )
  696. self.sizer.Add(
  697. StaticText(
  698. parent=self,
  699. id=wx.ID_ANY,
  700. label=_("Select target vector map to display:"),
  701. ),
  702. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  703. border=5,
  704. pos=(3, 1),
  705. )
  706. self.tgtvectselection = Select(
  707. self,
  708. id=wx.ID_ANY,
  709. size=globalvar.DIALOG_GSELECT_SIZE,
  710. type="vector",
  711. updateOnPopup=False,
  712. )
  713. self.sizer.Add(
  714. self.tgtvectselection,
  715. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  716. border=5,
  717. pos=(3, 2),
  718. )
  719. #
  720. # bindings
  721. #
  722. self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
  723. self.tgtrastselection.Bind(wx.EVT_TEXT, self.OnTgtRastSelection)
  724. self.tgtvectselection.Bind(wx.EVT_TEXT, self.OnTgtVectSelection)
  725. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
  726. self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
  727. self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
  728. def OnSrcSelection(self, event):
  729. """Source map to display selected"""
  730. global src_map
  731. global maptype
  732. src_map = self.srcselection.GetValue()
  733. if src_map == "":
  734. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  735. else:
  736. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  737. try:
  738. # set computational region to match selected map and zoom display
  739. # to region
  740. if maptype == "raster":
  741. p = RunCommand("g.region", "raster=src_map")
  742. elif maptype == "vector":
  743. p = RunCommand("g.region", "vector=src_map")
  744. if p.returncode == 0:
  745. print("returncode = ", str(p.returncode))
  746. self.parent.Map.region = self.parent.Map.GetRegion()
  747. except:
  748. pass
  749. def OnTgtRastSelection(self, event):
  750. """Source map to display selected"""
  751. global tgt_map
  752. tgt_map["raster"] = self.tgtrastselection.GetValue()
  753. def OnTgtVectSelection(self, event):
  754. """Source map to display selected"""
  755. global tgt_map
  756. tgt_map["vector"] = self.tgtvectselection.GetValue()
  757. def OnPageChanging(self, event=None):
  758. global src_map
  759. global tgt_map
  760. if event.GetDirection() and (src_map == ""):
  761. GMessage(
  762. _("You must select a source map " "in order to continue"), parent=self
  763. )
  764. event.Veto()
  765. return
  766. self.parent.SwitchEnv("target")
  767. def OnEnterPage(self, event=None):
  768. global maptype
  769. global src_map
  770. global tgt_map
  771. self.srcselection.SetElementList(maptype)
  772. if maptype == "raster":
  773. ret = RunCommand(
  774. "i.group",
  775. parent=self,
  776. read=True,
  777. group=self.parent.grouppage.xygroup,
  778. flags="g",
  779. )
  780. if ret:
  781. self.parent.src_maps = ret.splitlines()
  782. else:
  783. GError(
  784. parent=self,
  785. message=_(
  786. "No maps in selected group <%s>.\n"
  787. "Please edit group or select another group."
  788. )
  789. % self.parent.grouppage.xygroup,
  790. )
  791. return
  792. elif maptype == "vector":
  793. grassdatabase = self.parent.grassdatabase
  794. xylocation = self.parent.gisrc_dict["LOCATION_NAME"]
  795. xymapset = self.parent.gisrc_dict["MAPSET"]
  796. # make list of vectors to georectify from VREF
  797. vgrpfile = os.path.join(
  798. grassdatabase,
  799. xylocation,
  800. xymapset,
  801. "group",
  802. self.parent.grouppage.xygroup,
  803. "VREF",
  804. )
  805. error_message = (
  806. _(
  807. "No maps in selected group <%s>.\n"
  808. "Please edit group or select another group."
  809. )
  810. % self.parent.grouppage.xygroup
  811. )
  812. try:
  813. with open(vgrpfile) as f:
  814. for vect in f.readlines():
  815. vect = vect.strip("\n")
  816. if len(vect) < 1:
  817. continue
  818. self.parent.src_maps.append(vect)
  819. except FileNotFoundError:
  820. GError(parent=self, message=error_message, showTraceback=False)
  821. return
  822. if len(self.parent.src_maps) < 1:
  823. GError(parent=self, message=error_message)
  824. return
  825. # filter out all maps not in group
  826. self.srcselection.tcp.GetElementList(elements=self.parent.src_maps)
  827. src_map = self.parent.src_maps[0]
  828. self.srcselection.SetValue(src_map)
  829. self.parent.SwitchEnv("target")
  830. self.tgtrastselection.SetElementList("raster")
  831. self.tgtrastselection.GetElementList()
  832. self.tgtvectselection.SetElementList("vector")
  833. self.tgtvectselection.GetElementList()
  834. self.parent.SwitchEnv("source")
  835. if src_map == "":
  836. wx.FindWindowById(wx.ID_FORWARD).Enable(False)
  837. else:
  838. wx.FindWindowById(wx.ID_FORWARD).Enable(True)
  839. def GetWebServiceLayers(self, ltype=("wms"), name=None):
  840. """Get Map Display web service layer(s).
  841. :param ltype: map layer type
  842. :param name: map layer name
  843. :return: web service layer(s) dict
  844. {
  845. web_service_map_layer_name: {'type': ltype, 'cmd': [cmd list]},
  846. ...
  847. }
  848. :return: None when web service map layer name doesn't exist
  849. """
  850. layers = {}
  851. for layer in self.parent._giface.GetLayerList():
  852. if layer.type in ltype:
  853. layers[str(layer)] = {"type": layer.type, "cmd": layer.cmd}
  854. if name:
  855. return layers.get(name)
  856. return layers
  857. def GetSelectTargetRasterExtraItems(self):
  858. """Get select target raster widget extra items."""
  859. return {self.web_servc_lyrs_root_node_name: self.GetWebServiceLayers().keys()}
  860. class GCP(MapFrame, ColumnSorterMixin):
  861. """
  862. Manages ground control points for georectifying. Calculates RMS statistics.
  863. Calls i.rectify or v.rectify to georectify map.
  864. """
  865. def __init__(
  866. self,
  867. parent,
  868. giface,
  869. grwiz=None,
  870. id=wx.ID_ANY,
  871. title=_("Manage Ground Control Points"),
  872. size=(700, 300),
  873. toolbars=["gcpdisp"],
  874. Map=None,
  875. lmgr=None,
  876. ):
  877. self.grwiz = grwiz # GR Wizard
  878. self._giface = giface
  879. if tgt_map["raster"] == "" and tgt_map["vector"] == "":
  880. self.show_target = False
  881. else:
  882. self.show_target = True
  883. # wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
  884. MapFrame.__init__(
  885. self,
  886. parent=parent,
  887. giface=self._giface,
  888. title=title,
  889. size=size,
  890. Map=Map,
  891. toolbars=toolbars,
  892. name="GCPMapWindow",
  893. )
  894. # init variables
  895. self.parent = parent
  896. #
  897. # register data structures for drawing GCP's
  898. #
  899. self.pointsToDrawTgt = self.TgtMapWindow.RegisterGraphicsToDraw(
  900. graphicsType="point", setStatusFunc=self.SetGCPSatus
  901. )
  902. self.pointsToDrawSrc = self.SrcMapWindow.RegisterGraphicsToDraw(
  903. graphicsType="point", setStatusFunc=self.SetGCPSatus
  904. )
  905. # connect to the map windows signals
  906. # used to add or edit GCP
  907. self.SrcMapWindow.mouseLeftUpPointer.connect(
  908. lambda x, y: self._onMouseLeftUpPointer(self.SrcMapWindow, x, y)
  909. )
  910. self.TgtMapWindow.mouseLeftUpPointer.connect(
  911. lambda x, y: self._onMouseLeftUpPointer(self.TgtMapWindow, x, y)
  912. )
  913. # window resized
  914. self.resize = False
  915. self.grassdatabase = self.grwiz.grassdatabase
  916. self.currentlocation = self.grwiz.currentlocation
  917. self.currentmapset = self.grwiz.currentmapset
  918. self.newlocation = self.grwiz.newlocation
  919. self.newmapset = self.grwiz.newmapset
  920. self.xylocation = self.grwiz.gisrc_dict["LOCATION_NAME"]
  921. self.xymapset = self.grwiz.gisrc_dict["MAPSET"]
  922. self.xygroup = self.grwiz.grouppage.xygroup
  923. self.src_maps = self.grwiz.src_maps
  924. self.extension = self.grwiz.grouppage.extension
  925. self.outname = ""
  926. self.VectGRList = []
  927. self.file = {
  928. "points": os.path.join(
  929. self.grassdatabase,
  930. self.xylocation,
  931. self.xymapset,
  932. "group",
  933. self.xygroup,
  934. "POINTS",
  935. ),
  936. "points_bak": os.path.join(
  937. self.grassdatabase,
  938. self.xylocation,
  939. self.xymapset,
  940. "group",
  941. self.xygroup,
  942. "POINTS_BAK",
  943. ),
  944. "rgrp": os.path.join(
  945. self.grassdatabase,
  946. self.xylocation,
  947. self.xymapset,
  948. "group",
  949. self.xygroup,
  950. "REF",
  951. ),
  952. "vgrp": os.path.join(
  953. self.grassdatabase,
  954. self.xylocation,
  955. self.xymapset,
  956. "group",
  957. self.xygroup,
  958. "VREF",
  959. ),
  960. "target": os.path.join(
  961. self.grassdatabase,
  962. self.xylocation,
  963. self.xymapset,
  964. "group",
  965. self.xygroup,
  966. "TARGET",
  967. ),
  968. }
  969. # make a backup of the current points file
  970. if os.path.exists(self.file["points"]):
  971. shutil.copy(self.file["points"], self.file["points_bak"])
  972. # polynomial order transformation for georectification
  973. self.gr_order = 1
  974. # interpolation method for georectification
  975. self.gr_method = "nearest"
  976. # region clipping for georectified map
  977. self.clip_to_region = False
  978. # overwrite result map
  979. self.overwrite = False
  980. # number of GCPs selected to be used for georectification (checked)
  981. self.GCPcount = 0
  982. # forward RMS error
  983. self.fwd_rmserror = 0.0
  984. # backward RMS error
  985. self.bkw_rmserror = 0.0
  986. # list map coords and ID of map display they came from
  987. self.mapcoordlist = []
  988. self.mapcoordlist.append(
  989. [
  990. 0, # GCP number
  991. 0.0, # source east
  992. 0.0, # source north
  993. 0.0, # target east
  994. 0.0, # target north
  995. 0.0, # forward error
  996. 0.0,
  997. ]
  998. ) # backward error
  999. # init vars to highlight high RMS errors
  1000. self.highest_only = True
  1001. self.show_unused = True
  1002. self.highest_key = -1
  1003. self.rmsthresh = 0
  1004. self.rmsmean = 0
  1005. self.rmssd = 0
  1006. self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
  1007. self.itemDataMap = None
  1008. # images for column sorting
  1009. # CheckListCtrlMixin must set an ImageList first
  1010. self.il = self.list.GetImageList(wx.IMAGE_LIST_SMALL)
  1011. SmallUpArrow = BitmapFromImage(getSmallUpArrowImage())
  1012. SmallDnArrow = BitmapFromImage(getSmallDnArrowImage())
  1013. self.sm_dn = self.il.Add(SmallDnArrow)
  1014. self.sm_up = self.il.Add(SmallUpArrow)
  1015. # set mouse characteristics
  1016. self.mapwin = self.SrcMapWindow
  1017. self.mapwin.mouse["box"] = "point"
  1018. self.mapwin.mouse["use"] == "pointer"
  1019. self.mapwin.zoomtype = 0
  1020. self.mapwin.pen = wx.Pen(colour="black", width=2, style=wx.SOLID)
  1021. self.mapwin.SetNamedCursor("cross")
  1022. self.mapwin = self.TgtMapWindow
  1023. # set mouse characteristics
  1024. self.mapwin.mouse["box"] = "point"
  1025. self.mapwin.mouse["use"] == "pointer"
  1026. self.mapwin.zoomtype = 0
  1027. self.mapwin.pen = wx.Pen(colour="black", width=2, style=wx.SOLID)
  1028. self.mapwin.SetNamedCursor("cross")
  1029. #
  1030. # show new display & draw map
  1031. #
  1032. if self.show_target:
  1033. self.MapWindow = self.TgtMapWindow
  1034. self.Map = self.TgtMap
  1035. self.OnZoomToMap(None)
  1036. self.MapWindow = self.SrcMapWindow
  1037. self.Map = self.SrcMap
  1038. self.OnZoomToMap(None)
  1039. #
  1040. # bindings
  1041. #
  1042. self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
  1043. self.Bind(wx.EVT_SIZE, self.OnSize)
  1044. self.Bind(wx.EVT_IDLE, self.OnIdle)
  1045. self.Bind(wx.EVT_CLOSE, self.OnQuit)
  1046. self.SetSettings()
  1047. def __del__(self):
  1048. """Disable GCP manager mode"""
  1049. # leaving the method here but was used only to delete gcpmanagement
  1050. # from layer manager which is now not needed
  1051. pass
  1052. def CreateGCPList(self):
  1053. """Create GCP List Control"""
  1054. return GCPList(parent=self, gcp=self)
  1055. # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
  1056. def GetListCtrl(self):
  1057. return self.list
  1058. def GetMapCoordList(self):
  1059. return self.mapcoordlist
  1060. # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
  1061. def GetSortImages(self):
  1062. return (self.sm_dn, self.sm_up)
  1063. def GetFwdError(self):
  1064. return self.fwd_rmserror
  1065. def GetBkwError(self):
  1066. return self.bkw_rmserror
  1067. def InitMapDisplay(self):
  1068. self.list.LoadData()
  1069. # initialize column sorter
  1070. self.itemDataMap = self.mapcoordlist
  1071. ncols = self.list.GetColumnCount()
  1072. ColumnSorterMixin.__init__(self, ncols)
  1073. # init to ascending sort on first click
  1074. self._colSortFlag = [1] * ncols
  1075. def SetTarget(self, tgroup, tlocation, tmapset):
  1076. """
  1077. Sets rectification target to current location and mapset
  1078. """
  1079. # check to see if we are georectifying map in current working
  1080. # location/mapset
  1081. if (
  1082. self.newlocation == self.currentlocation
  1083. and self.newmapset == self.currentmapset
  1084. ):
  1085. RunCommand("i.target", parent=self, flags="c", group=tgroup)
  1086. else:
  1087. self.grwiz.SwitchEnv("source")
  1088. RunCommand(
  1089. "i.target",
  1090. parent=self,
  1091. group=tgroup,
  1092. location=tlocation,
  1093. mapset=tmapset,
  1094. )
  1095. self.grwiz.SwitchEnv("target")
  1096. def AddGCP(self, event):
  1097. """
  1098. Appends an item to GCP list
  1099. """
  1100. keyval = self.list.AddGCPItem() + 1
  1101. # source east, source north, target east, target north, forward error,
  1102. # backward error
  1103. self.mapcoordlist.append(
  1104. [
  1105. keyval, # GCP number
  1106. 0.0, # source east
  1107. 0.0, # source north
  1108. 0.0, # target east
  1109. 0.0, # target north
  1110. 0.0, # forward error
  1111. 0.0,
  1112. ]
  1113. ) # backward error
  1114. if self.statusbarManager.GetMode() == 8: # go to
  1115. self.StatusbarUpdate()
  1116. def DeleteGCP(self, event):
  1117. """
  1118. Deletes selected item in GCP list
  1119. """
  1120. minNumOfItems = self.OnGROrder(None)
  1121. if self.list.GetItemCount() <= minNumOfItems:
  1122. GMessage(
  1123. parent=self,
  1124. message=_("At least %d GCPs required. Operation canceled.")
  1125. % minNumOfItems,
  1126. )
  1127. return
  1128. key = self.list.DeleteGCPItem()
  1129. del self.mapcoordlist[key]
  1130. # update key and GCP number
  1131. for newkey in range(key, len(self.mapcoordlist)):
  1132. index = self.list.FindItem(-1, newkey + 1)
  1133. self.mapcoordlist[newkey][0] = newkey
  1134. self.list.SetItem(index, 0, str(newkey))
  1135. self.list.SetItemData(index, newkey)
  1136. # update selected
  1137. if self.list.GetItemCount() > 0:
  1138. if self.list.selected < self.list.GetItemCount():
  1139. self.list.selectedkey = self.list.GetItemData(self.list.selected)
  1140. else:
  1141. self.list.selected = self.list.GetItemCount() - 1
  1142. self.list.selectedkey = self.list.GetItemData(self.list.selected)
  1143. self.list.SetItemState(
  1144. self.list.selected, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED
  1145. )
  1146. else:
  1147. self.list.selected = wx.NOT_FOUND
  1148. self.list.selectedkey = -1
  1149. self.UpdateColours()
  1150. if self.statusbarManager.GetMode() == 8: # go to
  1151. self.StatusbarUpdate()
  1152. if self.list.selectedkey > 0:
  1153. self.statusbarManager.SetProperty("gotoGCP", self.list.selectedkey)
  1154. def ClearGCP(self, event):
  1155. """
  1156. Clears all values in selected item of GCP list and unchecks it
  1157. """
  1158. index = self.list.GetSelected()
  1159. key = self.list.GetItemData(index)
  1160. for i in range(1, 5):
  1161. self.list.SetItem(index, i, "0.0")
  1162. self.list.SetItem(index, 5, "")
  1163. self.list.SetItem(index, 6, "")
  1164. self.list.CheckItem(index, False)
  1165. # GCP number, source E, source N, target E, target N, fwd error, bkwd
  1166. # error
  1167. self.mapcoordlist[key] = [key, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
  1168. def SetSettings(self):
  1169. """Sets settings for drawing of GCP's."""
  1170. self.highest_only = UserSettings.Get(
  1171. group="gcpman", key="rms", subkey="highestonly"
  1172. )
  1173. self.show_unused = UserSettings.Get(
  1174. group="gcpman", key="symbol", subkey="unused"
  1175. )
  1176. colours = {
  1177. "color": "default",
  1178. "hcolor": "highest",
  1179. "scolor": "selected",
  1180. "ucolor": "unused",
  1181. }
  1182. wpx = UserSettings.Get(group="gcpman", key="symbol", subkey="width")
  1183. for k, v in six.iteritems(colours):
  1184. col = UserSettings.Get(group="gcpman", key="symbol", subkey=k)
  1185. self.pointsToDrawSrc.GetPen(v).SetColour(
  1186. wx.Colour(col[0], col[1], col[2], 255)
  1187. ) # TODO GetPen neni to spatne?
  1188. self.pointsToDrawTgt.GetPen(v).SetColour(
  1189. wx.Colour(col[0], col[1], col[2], 255)
  1190. )
  1191. self.pointsToDrawSrc.GetPen(v).SetWidth(wpx)
  1192. self.pointsToDrawTgt.GetPen(v).SetWidth(wpx)
  1193. spx = UserSettings.Get(group="gcpman", key="symbol", subkey="size")
  1194. self.pointsToDrawSrc.SetPropertyVal("size", int(spx))
  1195. self.pointsToDrawTgt.SetPropertyVal("size", int(spx))
  1196. font = self.GetFont()
  1197. font.SetPointSize(int(spx) + 2)
  1198. textProp = {}
  1199. textProp["active"] = True
  1200. textProp["font"] = font
  1201. self.pointsToDrawSrc.SetPropertyVal("text", textProp)
  1202. self.pointsToDrawTgt.SetPropertyVal("text", copy(textProp))
  1203. # overwrite result map
  1204. self.overwrite = UserSettings.Get(group="gcpman", key="map", subkey="overwrite")
  1205. def SetGCPSatus(self, item, itemIndex):
  1206. """Before GCP is drawn, decides it's colour and whether it
  1207. will be drawed.
  1208. """
  1209. key = self.list.GetItemData(itemIndex)
  1210. # incremented because of itemDataMap (has one more item) - will be
  1211. # changed
  1212. itemIndex += 1
  1213. if not self.list.IsItemChecked(key - 1):
  1214. wxPen = "unused"
  1215. if not self.show_unused:
  1216. item.SetPropertyVal("hide", True)
  1217. else:
  1218. item.SetPropertyVal("hide", False)
  1219. else:
  1220. item.SetPropertyVal("hide", False)
  1221. if self.highest_only:
  1222. if itemIndex == self.highest_key:
  1223. wxPen = "highest"
  1224. else:
  1225. wxPen = "default"
  1226. else:
  1227. if self.mapcoordlist[key][5] > self.rmsthresh:
  1228. wxPen = "highest"
  1229. else:
  1230. wxPen = "default"
  1231. if itemIndex == self.list.selectedkey:
  1232. wxPen = "selected"
  1233. item.SetPropertyVal("label", str(itemIndex))
  1234. item.SetPropertyVal("penName", wxPen)
  1235. def SetGCPData(self, coordtype, coord, mapdisp=None, confirm=False):
  1236. """Inserts coordinates from file, mouse click on map, or
  1237. after editing into selected item of GCP list and checks it for
  1238. use.
  1239. """
  1240. index = self.list.GetSelected()
  1241. if index == wx.NOT_FOUND:
  1242. return
  1243. coord0 = coord[0]
  1244. coord1 = coord[1]
  1245. key = self.list.GetItemData(index)
  1246. if confirm:
  1247. if self.MapWindow == self.SrcMapWindow:
  1248. currloc = _("source")
  1249. else:
  1250. currloc = _("target")
  1251. ret = wx.MessageBox(
  1252. parent=self,
  1253. caption=_("Set GCP coordinates"),
  1254. message=_(
  1255. "Set %(coor)s coordinates for GCP No. %(key)s? \n\n"
  1256. "East: %(coor0)s \n"
  1257. "North: %(coor1)s"
  1258. )
  1259. % {
  1260. "coor": currloc,
  1261. "key": str(key),
  1262. "coor0": str(coord0),
  1263. "coor1": str(coord1),
  1264. },
  1265. style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE,
  1266. )
  1267. # for wingrass
  1268. if os.name == "nt":
  1269. self.MapWindow.SetFocus()
  1270. if ret == wx.NO:
  1271. return
  1272. if coordtype == "source":
  1273. self.list.SetItem(index, 1, str(coord0))
  1274. self.list.SetItem(index, 2, str(coord1))
  1275. self.mapcoordlist[key][1] = coord[0]
  1276. self.mapcoordlist[key][2] = coord[1]
  1277. self.pointsToDrawSrc.GetItem(key - 1).SetCoords([coord0, coord1])
  1278. elif coordtype == "target":
  1279. self.list.SetItem(index, 3, str(coord0))
  1280. self.list.SetItem(index, 4, str(coord1))
  1281. self.mapcoordlist[key][3] = coord[0]
  1282. self.mapcoordlist[key][4] = coord[1]
  1283. self.pointsToDrawTgt.GetItem(key - 1).SetCoords([coord0, coord1])
  1284. self.list.SetItem(index, 5, "0")
  1285. self.list.SetItem(index, 6, "0")
  1286. self.mapcoordlist[key][5] = 0.0
  1287. self.mapcoordlist[key][6] = 0.0
  1288. # self.list.ResizeColumns()
  1289. def SaveGCPs(self, event):
  1290. """Make a POINTS file or save GCP coordinates to existing
  1291. POINTS file
  1292. """
  1293. self.GCPcount = 0
  1294. try:
  1295. f = open(self.file["points"], mode="w")
  1296. # use os.linesep or '\n' here ???
  1297. f.write("# Ground Control Points File\n")
  1298. f.write("# \n")
  1299. f.write("# target location: " + self.currentlocation + "\n")
  1300. f.write("# target mapset: " + self.currentmapset + "\n")
  1301. f.write("#\tsource\t\ttarget\t\tstatus\n")
  1302. f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n")
  1303. f.write(
  1304. "#----------------------- ----------------------- ---------------\n"
  1305. )
  1306. for index in range(self.list.GetItemCount()):
  1307. if self.list.IsItemChecked(index):
  1308. check = "1"
  1309. self.GCPcount += 1
  1310. else:
  1311. check = "0"
  1312. coord0 = self.list.GetItem(index, 1).GetText()
  1313. coord1 = self.list.GetItem(index, 2).GetText()
  1314. coord2 = self.list.GetItem(index, 3).GetText()
  1315. coord3 = self.list.GetItem(index, 4).GetText()
  1316. f.write(
  1317. coord0
  1318. + " "
  1319. + coord1
  1320. + " "
  1321. + coord2
  1322. + " "
  1323. + coord3
  1324. + " "
  1325. + check
  1326. + "\n"
  1327. )
  1328. except IOError as err:
  1329. GError(
  1330. parent=self,
  1331. message="%s <%s>. %s%s"
  1332. % (
  1333. _("Writing POINTS file failed"),
  1334. self.file["points"],
  1335. os.linesep,
  1336. err,
  1337. ),
  1338. )
  1339. return
  1340. f.close()
  1341. # if event != None save also to backup file
  1342. if event:
  1343. shutil.copy(self.file["points"], self.file["points_bak"])
  1344. self._giface.WriteLog(_("POINTS file saved for group <%s>") % self.xygroup)
  1345. # self.SetStatusText(_('POINTS file saved'))
  1346. def ReadGCPs(self):
  1347. """
  1348. Reads GCPs and georectified coordinates from POINTS file
  1349. """
  1350. self.GCPcount = 0
  1351. sourceMapWin = self.SrcMapWindow
  1352. targetMapWin = self.TgtMapWindow
  1353. if not sourceMapWin:
  1354. GError(parent=self, message=_("source mapwin not defined"))
  1355. if not targetMapWin:
  1356. GError(parent=self, message=_("target mapwin not defined"))
  1357. try:
  1358. f = open(self.file["points"], "r")
  1359. GCPcnt = 0
  1360. for line in f.readlines():
  1361. if line[0] == "#" or line == "":
  1362. continue
  1363. line = line.replace("\n", "").strip()
  1364. coords = list(map(float, line.split()))
  1365. if coords[4] == 1:
  1366. check = True
  1367. self.GCPcount += 1
  1368. else:
  1369. check = False
  1370. self.AddGCP(event=None)
  1371. self.SetGCPData("source", (coords[0], coords[1]), sourceMapWin)
  1372. self.SetGCPData("target", (coords[2], coords[3]), targetMapWin)
  1373. index = self.list.GetSelected()
  1374. if index != wx.NOT_FOUND:
  1375. self.list.CheckItem(index, check)
  1376. GCPcnt += 1
  1377. except IOError as err:
  1378. GError(
  1379. parent=self,
  1380. message="%s <%s>. %s%s"
  1381. % (
  1382. _("Reading POINTS file failed"),
  1383. self.file["points"],
  1384. os.linesep,
  1385. err,
  1386. ),
  1387. )
  1388. return
  1389. f.close()
  1390. if GCPcnt == 0:
  1391. # 3 gcp is minimum
  1392. for i in range(3):
  1393. self.AddGCP(None)
  1394. if self.CheckGCPcount():
  1395. # calculate RMS
  1396. self.RMSError(self.xygroup, self.gr_order)
  1397. def ReloadGCPs(self, event):
  1398. """Reload data from file"""
  1399. # use backup
  1400. shutil.copy(self.file["points_bak"], self.file["points"])
  1401. # delete all items in mapcoordlist
  1402. self.mapcoordlist = []
  1403. self.mapcoordlist.append(
  1404. [
  1405. 0, # GCP number
  1406. 0.0, # source east
  1407. 0.0, # source north
  1408. 0.0, # target east
  1409. 0.0, # target north
  1410. 0.0, # forward error
  1411. 0.0,
  1412. ]
  1413. ) # backward error
  1414. self.list.LoadData()
  1415. self.itemDataMap = self.mapcoordlist
  1416. if self._col != -1:
  1417. self.list.ClearColumnImage(self._col)
  1418. self._colSortFlag = [1] * self.list.GetColumnCount()
  1419. # draw GCPs (source and target)
  1420. sourceMapWin = self.SrcMapWindow
  1421. sourceMapWin.UpdateMap(render=False, renderVector=False)
  1422. if self.show_target:
  1423. targetMapWin = self.TgtMapWindow
  1424. targetMapWin.UpdateMap(render=False, renderVector=False)
  1425. def OnFocus(self, event):
  1426. # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapFrame?
  1427. # self.grwiz.SwitchEnv('source')
  1428. pass
  1429. def _onMouseLeftUpPointer(self, mapWindow, x, y):
  1430. if mapWindow == self.SrcMapWindow:
  1431. coordtype = "source"
  1432. else:
  1433. coordtype = "target"
  1434. coord = (x, y)
  1435. self.SetGCPData(coordtype, coord, self, confirm=True)
  1436. mapWindow.UpdateMap(render=False, renderVector=False)
  1437. def OnRMS(self, event):
  1438. """
  1439. RMS button handler
  1440. """
  1441. self.RMSError(self.xygroup, self.gr_order)
  1442. sourceMapWin = self.SrcMapWindow
  1443. sourceMapWin.UpdateMap(render=False, renderVector=False)
  1444. if self.show_target:
  1445. targetMapWin = self.TgtMapWindow
  1446. targetMapWin.UpdateMap(render=False, renderVector=False)
  1447. def CheckGCPcount(self, msg=False):
  1448. """
  1449. Checks to make sure that the minimum number of GCPs have been defined and
  1450. are active for the selected transformation order
  1451. """
  1452. if (
  1453. (self.GCPcount < 3 and self.gr_order == 1)
  1454. or (self.GCPcount < 6 and self.gr_order == 2)
  1455. or (self.GCPcount < 10 and self.gr_order == 3)
  1456. ):
  1457. if msg:
  1458. GWarning(
  1459. parent=self,
  1460. message=_(
  1461. "Insufficient points defined and active (checked) "
  1462. "for selected rectification method (order: %d).\n"
  1463. "3+ points needed for 1st order,\n"
  1464. "6+ points for 2nd order, and\n"
  1465. "10+ points for 3rd order."
  1466. )
  1467. % self.gr_order,
  1468. )
  1469. return False
  1470. else:
  1471. return True
  1472. def _getOverWriteDialog(self, maptype, overwrite):
  1473. """Get overwrite confirm dialog
  1474. :param str maptype: map type
  1475. :param bool overwrite: overwrite
  1476. :return
  1477. object: overwrite dialog
  1478. None: it isn't necessary to display the overwrite dialog
  1479. """
  1480. if maptype == "raster":
  1481. self.grwiz.SwitchEnv("source")
  1482. maps = grass.read_command(
  1483. "i.group",
  1484. flags="gl",
  1485. group=self.xygroup,
  1486. quiet=True,
  1487. ).split("\n")
  1488. self.grwiz.SwitchEnv("target")
  1489. found_maps = []
  1490. if maps:
  1491. for map in maps:
  1492. if map:
  1493. map_name = map.split("@")[0] + self.extension
  1494. found = grass.find_file(
  1495. name=map_name,
  1496. element="cell",
  1497. mapset=self.currentmapset,
  1498. )
  1499. if found["name"]:
  1500. found_maps.append("<{}>".format(found["name"]))
  1501. map_name = ", ".join(found_maps)
  1502. else:
  1503. self.grwiz.SwitchEnv("target")
  1504. found = grass.find_file(
  1505. name=self.outname,
  1506. element="vector",
  1507. mapset=self.currentmapset,
  1508. )
  1509. self.grwiz.SwitchEnv("source")
  1510. map_name = "<{}>".format(found["name"])
  1511. if found["name"] and not overwrite:
  1512. overwrite_dlg = wx.MessageDialog(
  1513. self.GetParent(),
  1514. message=_(
  1515. "The {map_type} map {map_name} exists. "
  1516. "Do you want to overwrite?".format(
  1517. map_type=maptype,
  1518. map_name=map_name,
  1519. ),
  1520. ),
  1521. caption=_("Overwrite?"),
  1522. style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION,
  1523. )
  1524. return overwrite_dlg
  1525. def OnGeorect(self, event):
  1526. """
  1527. Georectifies map(s) in group using i.rectify or v.transform
  1528. """
  1529. global maptype
  1530. self.SaveGCPs(None)
  1531. if not self.CheckGCPcount(msg=True):
  1532. return
  1533. if maptype == "raster":
  1534. overwrite_dlg = self._getOverWriteDialog(
  1535. maptype=maptype,
  1536. overwrite=self.overwrite,
  1537. )
  1538. if overwrite_dlg:
  1539. if not overwrite_dlg.ShowModal() == wx.ID_YES:
  1540. overwrite_dlg.Destroy()
  1541. return
  1542. overwrite_dlg.Destroy()
  1543. overwrite = True
  1544. else:
  1545. overwrite = self.overwrite
  1546. self.grwiz.SwitchEnv("source")
  1547. if self.clip_to_region:
  1548. flags = "ac"
  1549. else:
  1550. flags = "a"
  1551. busy = wx.BusyInfo(_("Rectifying images, please wait..."), parent=self)
  1552. wx.GetApp().Yield()
  1553. ret, msg = RunCommand(
  1554. "i.rectify",
  1555. parent=self,
  1556. getErrorMsg=True,
  1557. quiet=True,
  1558. group=self.xygroup,
  1559. extension=self.extension,
  1560. order=self.gr_order,
  1561. method=self.gr_method,
  1562. flags=flags,
  1563. overwrite=overwrite,
  1564. )
  1565. del busy
  1566. # provide feedback on failure
  1567. if ret != 0:
  1568. print(msg, file=sys.stderr)
  1569. elif maptype == "vector":
  1570. # loop through all vectors in VREF
  1571. self.grwiz.SwitchEnv("source")
  1572. # make list of vectors to georectify from VREF
  1573. f = open(self.file["vgrp"])
  1574. vectlist = []
  1575. try:
  1576. for vect in f.readlines():
  1577. vect = vect.strip("\n")
  1578. if len(vect) < 1:
  1579. continue
  1580. vectlist.append(vect)
  1581. finally:
  1582. f.close()
  1583. # georectify each vector in VREF using v.rectify
  1584. for vect in vectlist:
  1585. self.outname = str(vect.split("@")[0]) + self.extension
  1586. overwrite_dlg = self._getOverWriteDialog(
  1587. maptype=maptype,
  1588. overwrite=self.overwrite,
  1589. )
  1590. if overwrite_dlg:
  1591. if not overwrite_dlg.ShowModal() == wx.ID_YES:
  1592. overwrite_dlg.Destroy()
  1593. return
  1594. overwrite_dlg.Destroy()
  1595. overwrite = True
  1596. else:
  1597. overwrite = self.overwrite
  1598. self._giface.WriteLog(
  1599. text=_("Transforming <%s>...") % vect,
  1600. notification=Notification.MAKE_VISIBLE,
  1601. )
  1602. ret = msg = ""
  1603. busy = wx.BusyInfo(
  1604. _("Rectifying vector map <%s>, please wait...") % vect, parent=self
  1605. )
  1606. wx.GetApp().Yield()
  1607. ret, msg = RunCommand(
  1608. "v.rectify",
  1609. parent=self,
  1610. getErrorMsg=True,
  1611. quiet=True,
  1612. input=vect,
  1613. output=self.outname,
  1614. group=self.xygroup,
  1615. order=self.gr_order,
  1616. overwrite=overwrite,
  1617. )
  1618. del busy
  1619. # provide feedback on failure
  1620. if ret != 0:
  1621. print(msg, file=sys.stderr)
  1622. self.grwiz.SwitchEnv("target")
  1623. def OnGeorectDone(self, **kargs):
  1624. """Print final message"""
  1625. global maptype
  1626. if maptype == "raster":
  1627. return
  1628. returncode = kargs["returncode"]
  1629. if returncode == 0:
  1630. self.VectGRList.append(self.outname)
  1631. print("*****vector list = " + str(self.VectGRList))
  1632. else:
  1633. self._giface.WriteError(
  1634. _("Georectification of vector map <%s> failed") % self.outname
  1635. )
  1636. def OnSettings(self, event):
  1637. """GCP Manager settings"""
  1638. dlg = GrSettingsDialog(
  1639. parent=self,
  1640. giface=self._giface,
  1641. id=wx.ID_ANY,
  1642. title=_("GCP Manager settings"),
  1643. )
  1644. if dlg.ShowModal() == wx.ID_OK:
  1645. pass
  1646. dlg.Destroy()
  1647. def UpdateColours(
  1648. self,
  1649. srcrender=False,
  1650. srcrenderVector=False,
  1651. tgtrender=False,
  1652. tgtrenderVector=False,
  1653. ):
  1654. """update colours"""
  1655. highest_fwd_err = 0.0
  1656. self.highest_key = 0
  1657. highest_idx = 0
  1658. for index in range(self.list.GetItemCount()):
  1659. if self.list.IsItemChecked(index):
  1660. key = self.list.GetItemData(index)
  1661. fwd_err = self.mapcoordlist[key][5]
  1662. if self.highest_only:
  1663. self.list.SetItemTextColour(index, wx.BLACK)
  1664. if highest_fwd_err < fwd_err:
  1665. highest_fwd_err = fwd_err
  1666. self.highest_key = key
  1667. highest_idx = index
  1668. elif self.rmsthresh > 0:
  1669. if fwd_err > self.rmsthresh:
  1670. self.list.SetItemTextColour(index, wx.RED)
  1671. else:
  1672. self.list.SetItemTextColour(index, wx.BLACK)
  1673. else:
  1674. self.list.SetItemTextColour(index, wx.BLACK)
  1675. if self.highest_only and highest_fwd_err > 0.0:
  1676. self.list.SetItemTextColour(highest_idx, wx.RED)
  1677. sourceMapWin = self.SrcMapWindow
  1678. sourceMapWin.UpdateMap(render=srcrender, renderVector=srcrenderVector)
  1679. if self.show_target:
  1680. targetMapWin = self.TgtMapWindow
  1681. targetMapWin.UpdateMap(render=tgtrender, renderVector=tgtrenderVector)
  1682. def OnQuit(self, event):
  1683. """Quit georectifier"""
  1684. ret = wx.MessageBox(
  1685. parent=self,
  1686. caption=_("Quit GCP Manager"),
  1687. message=_("Save ground control points?"),
  1688. style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.CENTRE,
  1689. )
  1690. if ret != wx.CANCEL:
  1691. if ret == wx.YES:
  1692. self.SaveGCPs(None)
  1693. elif ret == wx.NO:
  1694. # restore POINTS file from backup
  1695. if os.path.exists(self.file["points_bak"]):
  1696. shutil.copy(self.file["points_bak"], self.file["points"])
  1697. if os.path.exists(self.file["points_bak"]):
  1698. os.unlink(self.file["points_bak"])
  1699. self.SrcMap.Clean()
  1700. self.TgtMap.Clean()
  1701. self.grwiz.Cleanup()
  1702. self._mgr.UnInit()
  1703. self.Destroy()
  1704. # event.Skip()
  1705. def OnGROrder(self, event):
  1706. """
  1707. sets transformation order for georectifying
  1708. """
  1709. if event:
  1710. self.gr_order = event.GetInt() + 1
  1711. numOfItems = self.list.GetItemCount()
  1712. minNumOfItems = numOfItems
  1713. if self.gr_order == 1:
  1714. minNumOfItems = 3
  1715. # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order'))
  1716. elif self.gr_order == 2:
  1717. minNumOfItems = 6
  1718. diff = 6 - numOfItems
  1719. # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order'))
  1720. elif self.gr_order == 3:
  1721. minNumOfItems = 10
  1722. # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order'))
  1723. for i in range(minNumOfItems - numOfItems):
  1724. self.AddGCP(None)
  1725. return minNumOfItems
  1726. def RMSError(self, xygroup, order):
  1727. """
  1728. Uses m.transform to calculate forward and backward error for each used GCP
  1729. in POINTS file and insert error values into GCP list.
  1730. Calculates total forward and backward RMS error for all used points
  1731. """
  1732. # save GCPs to points file to make sure that all checked GCPs are used
  1733. self.SaveGCPs(None)
  1734. # self.SetStatusText('')
  1735. if not self.CheckGCPcount(msg=True):
  1736. return
  1737. # get list of forward and reverse rms error values for each point
  1738. self.grwiz.SwitchEnv("source")
  1739. ret = RunCommand(
  1740. "m.transform", parent=self, read=True, group=xygroup, order=order
  1741. )
  1742. self.grwiz.SwitchEnv("target")
  1743. if ret:
  1744. errlist = ret.splitlines()
  1745. else:
  1746. GError(
  1747. parent=self,
  1748. message=_(
  1749. "Could not calculate RMS Error.\n"
  1750. "Possible error with m.transform."
  1751. ),
  1752. )
  1753. return
  1754. # insert error values into GCP list for checked items
  1755. sdfactor = float(UserSettings.Get(group="gcpman", key="rms", subkey="sdfactor"))
  1756. GCPcount = 0
  1757. sumsq_fwd_err = 0.0
  1758. sumsq_bkw_err = 0.0
  1759. sum_fwd_err = 0.0
  1760. highest_fwd_err = 0.0
  1761. self.highest_key = 0
  1762. highest_idx = 0
  1763. for index in range(self.list.GetItemCount()):
  1764. key = self.list.GetItemData(index)
  1765. if self.list.IsItemChecked(index):
  1766. fwd_err, bkw_err = errlist[GCPcount].split()
  1767. self.list.SetItem(index, 5, fwd_err)
  1768. self.list.SetItem(index, 6, bkw_err)
  1769. self.mapcoordlist[key][5] = float(fwd_err)
  1770. self.mapcoordlist[key][6] = float(bkw_err)
  1771. self.list.SetItemTextColour(index, wx.BLACK)
  1772. if self.highest_only:
  1773. if highest_fwd_err < float(fwd_err):
  1774. highest_fwd_err = float(fwd_err)
  1775. self.highest_key = key
  1776. highest_idx = index
  1777. sumsq_fwd_err += float(fwd_err) ** 2
  1778. sumsq_bkw_err += float(bkw_err) ** 2
  1779. sum_fwd_err += float(fwd_err)
  1780. GCPcount += 1
  1781. else:
  1782. self.list.SetItem(index, 5, "")
  1783. self.list.SetItem(index, 6, "")
  1784. self.mapcoordlist[key][5] = 0.0
  1785. self.mapcoordlist[key][6] = 0.0
  1786. self.list.SetItemTextColour(index, wx.BLACK)
  1787. # SD
  1788. if GCPcount > 0:
  1789. self.rmsmean = sum_fwd_err / GCPcount
  1790. self.rmssd = (sumsq_fwd_err - self.rmsmean ** 2) ** 0.5
  1791. self.rmsthresh = self.rmsmean + sdfactor * self.rmssd
  1792. else:
  1793. self.rmsthresh = 0
  1794. self.rmsmean = 0
  1795. self.rmssd = 0
  1796. if self.highest_only and highest_fwd_err > 0.0:
  1797. self.list.SetItemTextColour(highest_idx, wx.RED)
  1798. elif GCPcount > 0 and self.rmsthresh > 0 and not self.highest_only:
  1799. for index in range(self.list.GetItemCount()):
  1800. if self.list.IsItemChecked(index):
  1801. key = self.list.GetItemData(index)
  1802. if self.mapcoordlist[key][5] > self.rmsthresh:
  1803. self.list.SetItemTextColour(index, wx.RED)
  1804. # calculate global RMS error (geometric mean)
  1805. self.fwd_rmserror = round((sumsq_fwd_err / GCPcount) ** 0.5, 4)
  1806. self.bkw_rmserror = round((sumsq_bkw_err / GCPcount) ** 0.5, 4)
  1807. self.list.ResizeColumns()
  1808. def GetNewExtent(self, region, map=None):
  1809. coord_file = utils.GetTempfile()
  1810. newreg = {
  1811. "n": 0.0,
  1812. "s": 0.0,
  1813. "e": 0.0,
  1814. "w": 0.0,
  1815. }
  1816. try:
  1817. f = open(coord_file, mode="w")
  1818. # NW corner
  1819. f.write(str(region["e"]) + " " + str(region["n"]) + "\n")
  1820. # NE corner
  1821. f.write(str(region["e"]) + " " + str(region["s"]) + "\n")
  1822. # SW corner
  1823. f.write(str(region["w"]) + " " + str(region["n"]) + "\n")
  1824. # SE corner
  1825. f.write(str(region["w"]) + " " + str(region["s"]) + "\n")
  1826. finally:
  1827. f.close()
  1828. # save GCPs to points file to make sure that all checked GCPs are used
  1829. self.SaveGCPs(None)
  1830. order = self.gr_order
  1831. self.gr_order = 1
  1832. if not self.CheckGCPcount(msg=True):
  1833. self.gr_order = order
  1834. return
  1835. self.gr_order = order
  1836. # get list of forward and reverse rms error values for each point
  1837. self.grwiz.SwitchEnv("source")
  1838. if map == "source":
  1839. ret = RunCommand(
  1840. "m.transform",
  1841. parent=self,
  1842. read=True,
  1843. group=self.xygroup,
  1844. order=1,
  1845. format="dst",
  1846. coords=coord_file,
  1847. )
  1848. elif map == "target":
  1849. ret = RunCommand(
  1850. "m.transform",
  1851. parent=self,
  1852. read=True,
  1853. group=self.xygroup,
  1854. order=1,
  1855. flags="r",
  1856. format="src",
  1857. coords=coord_file,
  1858. )
  1859. os.unlink(coord_file)
  1860. self.grwiz.SwitchEnv("target")
  1861. if ret:
  1862. errlist = ret.splitlines()
  1863. else:
  1864. GError(
  1865. parent=self,
  1866. message=_(
  1867. "Could not calculate new extends.\n"
  1868. "Possible error with m.transform."
  1869. ),
  1870. )
  1871. return
  1872. # fist corner
  1873. e, n = errlist[0].split()
  1874. fe = float(e)
  1875. fn = float(n)
  1876. newreg["n"] = fn
  1877. newreg["s"] = fn
  1878. newreg["e"] = fe
  1879. newreg["w"] = fe
  1880. # other three corners
  1881. for i in range(1, 4):
  1882. e, n = errlist[i].split()
  1883. fe = float(e)
  1884. fn = float(n)
  1885. if fe < newreg["w"]:
  1886. newreg["w"] = fe
  1887. if fe > newreg["e"]:
  1888. newreg["e"] = fe
  1889. if fn < newreg["s"]:
  1890. newreg["s"] = fn
  1891. if fn > newreg["n"]:
  1892. newreg["n"] = fn
  1893. return newreg
  1894. def OnHelp(self, event):
  1895. """Show GCP Manager manual page"""
  1896. self._giface.Help(entry="wxGUI.gcp")
  1897. def OnUpdateActive(self, event):
  1898. if self.activemap.GetSelection() == 0:
  1899. self.MapWindow = self.SrcMapWindow
  1900. self.Map = self.SrcMap
  1901. else:
  1902. self.MapWindow = self.TgtMapWindow
  1903. self.Map = self.TgtMap
  1904. self.UpdateActive(self.MapWindow)
  1905. # for wingrass
  1906. if os.name == "nt":
  1907. self.MapWindow.SetFocus()
  1908. def UpdateActive(self, win):
  1909. # optionally disable tool zoomback tool
  1910. self.GetMapToolbar().Enable(
  1911. "zoomback", enable=(len(self.MapWindow.zoomhistory) > 1)
  1912. )
  1913. if self.activemap.GetSelection() != (win == self.TgtMapWindow):
  1914. self.activemap.SetSelection(win == self.TgtMapWindow)
  1915. self.StatusbarUpdate()
  1916. def AdjustMap(self, newreg):
  1917. """Adjust map window to new extents"""
  1918. # adjust map window
  1919. self.Map.region["n"] = newreg["n"]
  1920. self.Map.region["s"] = newreg["s"]
  1921. self.Map.region["e"] = newreg["e"]
  1922. self.Map.region["w"] = newreg["w"]
  1923. self.MapWindow.ZoomHistory(
  1924. self.Map.region["n"],
  1925. self.Map.region["s"],
  1926. self.Map.region["e"],
  1927. self.Map.region["w"],
  1928. )
  1929. # LL locations
  1930. if self.Map.projinfo["proj"] == "ll":
  1931. if newreg["n"] > 90.0:
  1932. newreg["n"] = 90.0
  1933. if newreg["s"] < -90.0:
  1934. newreg["s"] = -90.0
  1935. ce = newreg["w"] + (newreg["e"] - newreg["w"]) / 2
  1936. cn = newreg["s"] + (newreg["n"] - newreg["s"]) / 2
  1937. # calculate new center point and display resolution
  1938. self.Map.region["center_easting"] = ce
  1939. self.Map.region["center_northing"] = cn
  1940. self.Map.region["ewres"] = (newreg["e"] - newreg["w"]) / self.Map.width
  1941. self.Map.region["nsres"] = (newreg["n"] - newreg["s"]) / self.Map.height
  1942. self.Map.AlignExtentFromDisplay()
  1943. self.MapWindow.ZoomHistory(
  1944. self.Map.region["n"],
  1945. self.Map.region["s"],
  1946. self.Map.region["e"],
  1947. self.Map.region["w"],
  1948. )
  1949. if self.MapWindow.redrawAll is False:
  1950. self.MapWindow.redrawAll = True
  1951. self.MapWindow.UpdateMap()
  1952. self.StatusbarUpdate()
  1953. def OnZoomToSource(self, event):
  1954. """Set target map window to match extents of source map window"""
  1955. if not self.MapWindow == self.TgtMapWindow:
  1956. self.MapWindow = self.TgtMapWindow
  1957. self.Map = self.TgtMap
  1958. self.UpdateActive(self.TgtMapWindow)
  1959. # get new N, S, E, W for target
  1960. newreg = self.GetNewExtent(self.SrcMap.region, "source")
  1961. if newreg:
  1962. self.AdjustMap(newreg)
  1963. def OnZoomToTarget(self, event):
  1964. """Set source map window to match extents of target map window"""
  1965. if not self.MapWindow == self.SrcMapWindow:
  1966. self.MapWindow = self.SrcMapWindow
  1967. self.Map = self.SrcMap
  1968. self.UpdateActive(self.SrcMapWindow)
  1969. # get new N, S, E, W for target
  1970. newreg = self.GetNewExtent(self.TgtMap.region, "target")
  1971. if newreg:
  1972. self.AdjustMap(newreg)
  1973. def OnZoomMenuGCP(self, event):
  1974. """Popup Zoom menu"""
  1975. point = wx.GetMousePosition()
  1976. zoommenu = Menu()
  1977. # Add items to the menu
  1978. zoomsource = wx.MenuItem(
  1979. zoommenu, wx.ID_ANY, _("Adjust source display to target display")
  1980. )
  1981. zoommenu.AppendItem(zoomsource)
  1982. self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
  1983. zoomtarget = wx.MenuItem(
  1984. zoommenu, wx.ID_ANY, _("Adjust target display to source display")
  1985. )
  1986. zoommenu.AppendItem(zoomtarget)
  1987. self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
  1988. # Popup the menu. If an item is selected then its handler
  1989. # will be called before PopupMenu returns.
  1990. self.PopupMenu(zoommenu)
  1991. zoommenu.Destroy()
  1992. def OnSize(self, event):
  1993. """Adjust Map Windows after GCP Map Display has been resized"""
  1994. # re-render image on idle
  1995. self.resize = grass.clock()
  1996. super(MapFrame, self).OnSize(event)
  1997. def OnIdle(self, event):
  1998. """GCP Map Display resized, adjust Map Windows"""
  1999. if self.GetMapToolbar():
  2000. if self.resize and self.resize + 0.2 < grass.clock():
  2001. srcwidth, srcheight = self.SrcMapWindow.GetSize()
  2002. tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
  2003. srcwidth = (srcwidth + tgtwidth) / 2
  2004. if self.show_target:
  2005. self._mgr.GetPane("target").Hide()
  2006. self._mgr.Update()
  2007. self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
  2008. self._mgr.GetPane("target").BestSize((srcwidth, tgtheight))
  2009. if self.show_target:
  2010. self._mgr.GetPane("target").Show()
  2011. self._mgr.Update()
  2012. self.resize = False
  2013. elif self.resize:
  2014. event.RequestMore()
  2015. pass
  2016. class GCPList(ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
  2017. def __init__(
  2018. self,
  2019. parent,
  2020. gcp,
  2021. id=wx.ID_ANY,
  2022. pos=wx.DefaultPosition,
  2023. size=wx.DefaultSize,
  2024. style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES | wx.LC_SINGLE_SEL,
  2025. ):
  2026. ListCtrl.__init__(self, parent, id, pos, size, style)
  2027. self.gcp = gcp # GCP class
  2028. self.render = True
  2029. # Mixin settings
  2030. CheckListCtrlMixin.__init__(self)
  2031. ListCtrlAutoWidthMixin.__init__(self)
  2032. # TextEditMixin.__init__(self)
  2033. # tracks whether list items are checked or not
  2034. self.CheckList = []
  2035. self._Create()
  2036. self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
  2037. self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
  2038. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
  2039. self.selected = wx.NOT_FOUND
  2040. self.selectedkey = -1
  2041. def _Create(self):
  2042. if 0:
  2043. # normal, simple columns
  2044. idx_col = 0
  2045. for col in (
  2046. _("use"),
  2047. _("source E"),
  2048. _("source N"),
  2049. _("target E"),
  2050. _("target N"),
  2051. _("Forward error"),
  2052. _("Backward error"),
  2053. ):
  2054. self.InsertColumn(idx_col, col)
  2055. idx_col += 1
  2056. else:
  2057. # the hard way: we want images on the column header
  2058. info = wx.ListItem()
  2059. info.SetMask(wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT)
  2060. info.SetImage(-1)
  2061. info.m_format = wx.LIST_FORMAT_LEFT
  2062. idx_col = 0
  2063. for lbl in (
  2064. _("use"),
  2065. _("source E"),
  2066. _("source N"),
  2067. _("target E"),
  2068. _("target N"),
  2069. _("Forward error"),
  2070. _("Backward error"),
  2071. ):
  2072. info.SetText(lbl)
  2073. self.InsertColumn(idx_col, info)
  2074. idx_col += 1
  2075. def LoadData(self):
  2076. """Load data into list"""
  2077. self.DeleteAllItems()
  2078. self.render = False
  2079. if os.path.isfile(self.gcp.file["points"]):
  2080. self.gcp.ReadGCPs()
  2081. else:
  2082. # 3 gcp is minimum
  2083. for i in range(3):
  2084. self.gcp.AddGCP(None)
  2085. # select first point by default
  2086. self.selected = 0
  2087. self.selectedkey = self.GetItemData(self.selected)
  2088. self.SetItemState(self.selected, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
  2089. self.ResizeColumns()
  2090. self.render = True
  2091. self.EnsureVisible(self.selected)
  2092. def OnCheckItem(self, index, flag):
  2093. """Item is checked/unchecked"""
  2094. if self.render:
  2095. # redraw points
  2096. sourceMapWin = self.gcp.SrcMapWindow
  2097. sourceMapWin.UpdateMap(render=False, renderVector=False)
  2098. if self.gcp.show_target:
  2099. targetMapWin = self.gcp.TgtMapWindow
  2100. targetMapWin.UpdateMap(render=False, renderVector=False)
  2101. def AddGCPItem(self):
  2102. """
  2103. Appends an item to GCP list
  2104. """
  2105. self.selectedkey = self.GetItemCount() + 1
  2106. self.Append(
  2107. [
  2108. str(self.selectedkey), # GCP number
  2109. "0.0", # source E
  2110. "0.0", # source N
  2111. "0.0", # target E
  2112. "0.0", # target N
  2113. "", # forward error
  2114. "",
  2115. ]
  2116. ) # backward error
  2117. self.selected = self.GetItemCount() - 1
  2118. self.SetItemData(self.selected, self.selectedkey)
  2119. self.SetItemState(self.selected, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
  2120. self.ResizeColumns()
  2121. self.gcp.pointsToDrawSrc.AddItem(coords=[0, 0], label=str(self.selectedkey))
  2122. self.gcp.pointsToDrawTgt.AddItem(coords=[0, 0], label=str(self.selectedkey))
  2123. self.EnsureVisible(self.selected)
  2124. return self.selected
  2125. def DeleteGCPItem(self):
  2126. """Deletes selected item in GCP list."""
  2127. if self.selected == wx.NOT_FOUND:
  2128. return
  2129. key = self.GetItemData(self.selected)
  2130. self.DeleteItem(self.selected)
  2131. if self.selected != wx.NOT_FOUND:
  2132. item = self.gcp.pointsToDrawSrc.GetItem(key - 1)
  2133. self.gcp.pointsToDrawSrc.DeleteItem(item)
  2134. item = self.gcp.pointsToDrawTgt.GetItem(key - 1)
  2135. self.gcp.pointsToDrawTgt.DeleteItem(item)
  2136. return key
  2137. def ResizeColumns(self):
  2138. """Resize columns"""
  2139. minWidth = [90, 120]
  2140. for i in range(self.GetColumnCount()):
  2141. self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
  2142. # first column is checkbox, don't set to minWidth
  2143. if i > 0 and self.GetColumnWidth(i) < minWidth[i > 4]:
  2144. self.SetColumnWidth(i, minWidth[i > 4])
  2145. self.SendSizeEvent()
  2146. def GetSelected(self):
  2147. """Get index of selected item"""
  2148. return self.selected
  2149. def OnItemSelected(self, event):
  2150. """Item selected"""
  2151. if self.render and self.selected != event.GetIndex():
  2152. self.selected = event.GetIndex()
  2153. self.selectedkey = self.GetItemData(self.selected)
  2154. sourceMapWin = self.gcp.SrcMapWindow
  2155. sourceMapWin.UpdateMap(render=False, renderVector=False)
  2156. if self.gcp.show_target:
  2157. targetMapWin = self.gcp.TgtMapWindow
  2158. targetMapWin.UpdateMap(render=False, renderVector=False)
  2159. event.Skip()
  2160. def OnItemActivated(self, event):
  2161. """
  2162. When item double clicked, open editor to update coordinate values
  2163. """
  2164. coords = []
  2165. index = event.GetIndex()
  2166. key = self.GetItemData(index)
  2167. changed = False
  2168. for i in range(1, 5):
  2169. coords.append(self.GetItem(index, i).GetText())
  2170. dlg = EditGCP(parent=self, id=wx.ID_ANY, data=coords, gcpno=key)
  2171. if dlg.ShowModal() == wx.ID_OK:
  2172. values = dlg.GetValues() # string
  2173. if len(values) == 0:
  2174. GError(
  2175. parent=self,
  2176. message=_("Invalid coordinate value. Operation canceled."),
  2177. )
  2178. else:
  2179. for i in range(len(values)):
  2180. if values[i] != coords[i]:
  2181. self.SetItem(index, i + 1, values[i])
  2182. changed = True
  2183. if changed:
  2184. # reset RMS and update mapcoordlist
  2185. self.SetItem(index, 5, "")
  2186. self.SetItem(index, 6, "")
  2187. key = self.GetItemData(index)
  2188. self.gcp.mapcoordlist[key] = [
  2189. key,
  2190. float(values[0]),
  2191. float(values[1]),
  2192. float(values[2]),
  2193. float(values[3]),
  2194. 0.0,
  2195. 0.0,
  2196. ]
  2197. self.gcp.pointsToDrawSrc.GetItem(key - 1).SetCoords(
  2198. [float(values[0]), float(values[1])]
  2199. )
  2200. self.gcp.pointsToDrawTgt.GetItem(key - 1).SetCoords(
  2201. [float(values[2]), float(values[3])]
  2202. )
  2203. self.gcp.UpdateColours()
  2204. def OnColClick(self, event):
  2205. """ListCtrl forgets selected item..."""
  2206. self.selected = self.FindItem(-1, self.selectedkey)
  2207. self.SetItemState(self.selected, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
  2208. event.Skip()
  2209. class VectGroup(wx.Dialog):
  2210. """Dialog to create a vector group (VREF file) for georectifying
  2211. .. todo::
  2212. Replace by g.group
  2213. """
  2214. def __init__(
  2215. self,
  2216. parent,
  2217. id,
  2218. grassdb,
  2219. location,
  2220. mapset,
  2221. group,
  2222. style=wx.DEFAULT_DIALOG_STYLE,
  2223. ):
  2224. wx.Dialog.__init__(
  2225. self, parent, id, style=style, title=_("Create vector map group")
  2226. )
  2227. self.grassdatabase = grassdb
  2228. self.xylocation = location
  2229. self.xymapset = mapset
  2230. self.xygroup = group
  2231. #
  2232. # get list of valid vector directories
  2233. #
  2234. vectlist = os.listdir(
  2235. os.path.join(self.grassdatabase, self.xylocation, self.xymapset, "vector")
  2236. )
  2237. for dir in vectlist:
  2238. if not os.path.isfile(
  2239. os.path.join(
  2240. self.grassdatabase,
  2241. self.xylocation,
  2242. self.xymapset,
  2243. "vector",
  2244. dir,
  2245. "coor",
  2246. )
  2247. ):
  2248. vectlist.remove(dir)
  2249. utils.ListSortLower(vectlist)
  2250. # path to vref file
  2251. self.vgrpfile = os.path.join(
  2252. self.grassdatabase,
  2253. self.xylocation,
  2254. self.xymapset,
  2255. "group",
  2256. self.xygroup,
  2257. "VREF",
  2258. )
  2259. #
  2260. # buttons
  2261. #
  2262. self.btnCancel = Button(parent=self, id=wx.ID_CANCEL)
  2263. self.btnOK = Button(parent=self, id=wx.ID_OK)
  2264. self.btnOK.SetDefault()
  2265. #
  2266. # list of vector maps
  2267. #
  2268. self.listMap = CheckListBox(parent=self, id=wx.ID_ANY, choices=vectlist)
  2269. if os.path.isfile(self.vgrpfile):
  2270. f = open(self.vgrpfile)
  2271. try:
  2272. checked = []
  2273. for line in f.readlines():
  2274. line = line.replace("\n", "")
  2275. if len(line) < 1:
  2276. continue
  2277. checked.append(line.split("@")[0])
  2278. self.listMap.SetCheckedStrings(checked)
  2279. finally:
  2280. f.close()
  2281. line = wx.StaticLine(
  2282. parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  2283. )
  2284. #
  2285. # layout
  2286. #
  2287. sizer = wx.BoxSizer(wx.VERTICAL)
  2288. box = wx.BoxSizer(wx.HORIZONTAL)
  2289. box.Add(
  2290. StaticText(
  2291. parent=self,
  2292. id=wx.ID_ANY,
  2293. label=_("Select vector map(s) to add to group:"),
  2294. ),
  2295. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  2296. border=5,
  2297. )
  2298. box.Add(
  2299. self.listMap,
  2300. flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  2301. border=5,
  2302. )
  2303. sizer.Add(box, flag=wx.ALIGN_RIGHT | wx.ALL, border=3)
  2304. sizer.Add(
  2305. line,
  2306. proportion=0,
  2307. flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
  2308. border=5,
  2309. )
  2310. # buttons
  2311. btnSizer = wx.StdDialogButtonSizer()
  2312. btnSizer.AddButton(self.btnCancel)
  2313. btnSizer.AddButton(self.btnOK)
  2314. btnSizer.Realize()
  2315. sizer.Add(
  2316. btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5
  2317. )
  2318. self.SetSizer(sizer)
  2319. sizer.Fit(self)
  2320. self.Layout()
  2321. def MakeVGroup(self):
  2322. """Create VREF file"""
  2323. vgrouplist = []
  2324. for item in range(self.listMap.GetCount()):
  2325. if not self.listMap.IsChecked(item):
  2326. continue
  2327. vgrouplist.append(self.listMap.GetString(item) + "@" + self.xymapset)
  2328. dirname = os.path.dirname(self.vgrpfile)
  2329. if not os.path.exists(dirname):
  2330. os.makedirs(dirname)
  2331. f = open(self.vgrpfile, mode="w")
  2332. try:
  2333. for vect in vgrouplist:
  2334. f.write(vect + "\n")
  2335. finally:
  2336. f.close()
  2337. class EditGCP(wx.Dialog):
  2338. def __init__(
  2339. self,
  2340. parent,
  2341. data,
  2342. gcpno,
  2343. id=wx.ID_ANY,
  2344. title=_("Edit GCP"),
  2345. style=wx.DEFAULT_DIALOG_STYLE,
  2346. ):
  2347. """Dialog for editing GPC and map coordinates in list control"""
  2348. wx.Dialog.__init__(self, parent, id, title=title, style=style)
  2349. panel = wx.Panel(parent=self)
  2350. sizer = wx.BoxSizer(wx.VERTICAL)
  2351. box = StaticBox(
  2352. parent=panel,
  2353. id=wx.ID_ANY,
  2354. label=" %s %s " % (_("Ground Control Point No."), str(gcpno)),
  2355. )
  2356. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  2357. # source coordinates
  2358. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  2359. self.xcoord = TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  2360. self.ycoord = TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  2361. self.ecoord = TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  2362. self.ncoord = TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
  2363. # swap source N, target E
  2364. tmp_coord = data[1]
  2365. data[1] = data[2]
  2366. data[2] = tmp_coord
  2367. row = 0
  2368. col = 0
  2369. idx = 0
  2370. for label, win in (
  2371. (_("source E:"), self.xcoord),
  2372. (_("target E:"), self.ecoord),
  2373. (_("source N:"), self.ycoord),
  2374. (_("target N:"), self.ncoord),
  2375. ):
  2376. label = StaticText(parent=panel, id=wx.ID_ANY, label=label)
  2377. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, col))
  2378. col += 1
  2379. win.SetValue(str(data[idx]))
  2380. gridSizer.Add(win, pos=(row, col))
  2381. col += 1
  2382. idx += 1
  2383. if col > 3:
  2384. row += 1
  2385. col = 0
  2386. boxSizer.Add(gridSizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  2387. sizer.Add(boxSizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  2388. #
  2389. # buttons
  2390. #
  2391. self.btnCancel = Button(panel, wx.ID_CANCEL)
  2392. self.btnOk = Button(panel, wx.ID_OK)
  2393. self.btnOk.SetDefault()
  2394. btnSizer = wx.StdDialogButtonSizer()
  2395. btnSizer.AddButton(self.btnCancel)
  2396. btnSizer.AddButton(self.btnOk)
  2397. btnSizer.Realize()
  2398. sizer.Add(btnSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  2399. panel.SetSizer(sizer)
  2400. sizer.Fit(self)
  2401. def GetValues(self, columns=None):
  2402. """Return list of values (as strings)."""
  2403. valuelist = []
  2404. try:
  2405. float(self.xcoord.GetValue())
  2406. float(self.ycoord.GetValue())
  2407. float(self.ecoord.GetValue())
  2408. float(self.ncoord.GetValue())
  2409. except ValueError:
  2410. return valuelist
  2411. valuelist.append(self.xcoord.GetValue())
  2412. valuelist.append(self.ycoord.GetValue())
  2413. valuelist.append(self.ecoord.GetValue())
  2414. valuelist.append(self.ncoord.GetValue())
  2415. return valuelist
  2416. class GrSettingsDialog(wx.Dialog):
  2417. def __init__(
  2418. self,
  2419. parent,
  2420. id,
  2421. giface,
  2422. title,
  2423. pos=wx.DefaultPosition,
  2424. size=wx.DefaultSize,
  2425. style=wx.DEFAULT_DIALOG_STYLE,
  2426. ):
  2427. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  2428. """
  2429. Dialog to set profile text options: font, title
  2430. and font size, axis labels and font size
  2431. """
  2432. #
  2433. # initialize variables
  2434. #
  2435. self.parent = parent
  2436. self.new_src_map = src_map
  2437. self.new_tgt_map = {"raster": tgt_map["raster"], "vector": tgt_map["vector"]}
  2438. self.sdfactor = 0
  2439. self.symbol = {}
  2440. self.methods = [
  2441. "nearest",
  2442. "linear",
  2443. "linear_f",
  2444. "cubic",
  2445. "cubic_f",
  2446. "lanczos",
  2447. "lanczos_f",
  2448. ]
  2449. # notebook
  2450. notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  2451. self.__CreateSymbologyPage(notebook)
  2452. self.__CreateRectificationPage(notebook)
  2453. # buttons
  2454. btnSave = Button(self, wx.ID_SAVE)
  2455. btnApply = Button(self, wx.ID_APPLY)
  2456. btnClose = Button(self, wx.ID_CLOSE)
  2457. btnApply.SetDefault()
  2458. # bindings
  2459. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  2460. btnApply.SetToolTip(_("Apply changes for the current session"))
  2461. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  2462. btnSave.SetToolTip(
  2463. _(
  2464. "Apply and save changes to user settings file (default for next sessions)"
  2465. )
  2466. )
  2467. btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
  2468. btnClose.SetToolTip(_("Close dialog"))
  2469. # sizers
  2470. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  2471. btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
  2472. btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
  2473. btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
  2474. # sizers
  2475. mainSizer = wx.BoxSizer(wx.VERTICAL)
  2476. mainSizer.Add(notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  2477. mainSizer.Add(btnSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  2478. # flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
  2479. self.SetSizer(mainSizer)
  2480. mainSizer.Fit(self)
  2481. def __CreateSymbologyPage(self, notebook):
  2482. """Create notebook page with symbology settings"""
  2483. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  2484. notebook.AddPage(page=panel, text=_("Symbology"))
  2485. sizer = wx.BoxSizer(wx.VERTICAL)
  2486. rmsgridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  2487. # highlight only highest forward RMS error
  2488. self.highlighthighest = wx.CheckBox(
  2489. parent=panel, id=wx.ID_ANY, label=_("Highlight highest RMS error only")
  2490. )
  2491. hh = UserSettings.Get(group="gcpman", key="rms", subkey="highestonly")
  2492. self.highlighthighest.SetValue(hh)
  2493. rmsgridSizer.Add(
  2494. self.highlighthighest, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0)
  2495. )
  2496. # RMS forward error threshold
  2497. rmslabel = StaticText(
  2498. parent=panel,
  2499. id=wx.ID_ANY,
  2500. label=_("Highlight RMS error > M + SD * factor:"),
  2501. )
  2502. rmslabel.SetToolTip(
  2503. _(
  2504. "Highlight GCPs with an RMS error larger than \n"
  2505. "mean + standard deviation * given factor. \n"
  2506. "Recommended values for this factor are between 1 and 2."
  2507. )
  2508. )
  2509. rmsgridSizer.Add(rmslabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  2510. sdfactor = UserSettings.Get(group="gcpman", key="rms", subkey="sdfactor")
  2511. self.rmsWin = TextCtrl(
  2512. parent=panel, id=wx.ID_ANY, size=(70, -1), style=wx.TE_NOHIDESEL
  2513. )
  2514. self.rmsWin.SetValue("%s" % str(sdfactor))
  2515. if self.parent.highest_only:
  2516. self.rmsWin.Disable()
  2517. self.symbol["sdfactor"] = self.rmsWin.GetId()
  2518. rmsgridSizer.Add(self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
  2519. rmsgridSizer.AddGrowableCol(1)
  2520. sizer.Add(rmsgridSizer, flag=wx.EXPAND | wx.ALL, border=5)
  2521. box = StaticBox(parent=panel, id=wx.ID_ANY, label=" %s " % _("Symbol settings"))
  2522. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  2523. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  2524. #
  2525. # general symbol color
  2526. #
  2527. row = 0
  2528. label = StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
  2529. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2530. col = UserSettings.Get(group="gcpman", key="symbol", subkey="color")
  2531. colWin = csel.ColourSelect(
  2532. parent=panel, id=wx.ID_ANY, colour=wx.Colour(col[0], col[1], col[2], 255)
  2533. )
  2534. self.symbol["color"] = colWin.GetId()
  2535. gridSizer.Add(colWin, flag=wx.ALIGN_RIGHT, pos=(row, 1))
  2536. #
  2537. # symbol color for high forward RMS error
  2538. #
  2539. row += 1
  2540. label = StaticText(
  2541. parent=panel, id=wx.ID_ANY, label=_("Color for high RMS error:")
  2542. )
  2543. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2544. hcol = UserSettings.Get(group="gcpman", key="symbol", subkey="hcolor")
  2545. hcolWin = csel.ColourSelect(
  2546. parent=panel, id=wx.ID_ANY, colour=wx.Colour(hcol[0], hcol[1], hcol[2], 255)
  2547. )
  2548. self.symbol["hcolor"] = hcolWin.GetId()
  2549. gridSizer.Add(hcolWin, flag=wx.ALIGN_RIGHT, pos=(row, 1))
  2550. #
  2551. # symbol color for selected GCP
  2552. #
  2553. row += 1
  2554. label = StaticText(
  2555. parent=panel, id=wx.ID_ANY, label=_("Color for selected GCP:")
  2556. )
  2557. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2558. scol = UserSettings.Get(group="gcpman", key="symbol", subkey="scolor")
  2559. scolWin = csel.ColourSelect(
  2560. parent=panel, id=wx.ID_ANY, colour=wx.Colour(scol[0], scol[1], scol[2], 255)
  2561. )
  2562. self.symbol["scolor"] = scolWin.GetId()
  2563. gridSizer.Add(scolWin, flag=wx.ALIGN_RIGHT, pos=(row, 1))
  2564. #
  2565. # symbol color for unused GCP
  2566. #
  2567. row += 1
  2568. label = StaticText(
  2569. parent=panel, id=wx.ID_ANY, label=_("Color for unused GCPs:")
  2570. )
  2571. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2572. ucol = UserSettings.Get(group="gcpman", key="symbol", subkey="ucolor")
  2573. ucolWin = csel.ColourSelect(
  2574. parent=panel, id=wx.ID_ANY, colour=wx.Colour(ucol[0], ucol[1], ucol[2], 255)
  2575. )
  2576. self.symbol["ucolor"] = ucolWin.GetId()
  2577. gridSizer.Add(ucolWin, flag=wx.ALIGN_RIGHT, pos=(row, 1))
  2578. # show unused GCPs
  2579. row += 1
  2580. self.showunused = wx.CheckBox(
  2581. parent=panel, id=wx.ID_ANY, label=_("Show unused GCPs")
  2582. )
  2583. shuu = UserSettings.Get(group="gcpman", key="symbol", subkey="unused")
  2584. self.showunused.SetValue(shuu)
  2585. gridSizer.Add(self.showunused, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2586. #
  2587. # symbol size
  2588. #
  2589. row += 1
  2590. label = StaticText(parent=panel, id=wx.ID_ANY, label=_("Symbol size:"))
  2591. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2592. symsize = int(UserSettings.Get(group="gcpman", key="symbol", subkey="size"))
  2593. sizeWin = SpinCtrl(parent=panel, id=wx.ID_ANY, min=1, max=20)
  2594. sizeWin.SetValue(symsize)
  2595. self.symbol["size"] = sizeWin.GetId()
  2596. gridSizer.Add(sizeWin, flag=wx.ALIGN_RIGHT, pos=(row, 1))
  2597. #
  2598. # symbol width
  2599. #
  2600. row += 1
  2601. label = StaticText(parent=panel, id=wx.ID_ANY, label=_("Line width:"))
  2602. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  2603. width = int(UserSettings.Get(group="gcpman", key="symbol", subkey="width"))
  2604. widWin = SpinCtrl(parent=panel, id=wx.ID_ANY, min=1, max=10)
  2605. widWin.SetValue(width)
  2606. self.symbol["width"] = widWin.GetId()
  2607. gridSizer.Add(widWin, flag=wx.ALIGN_RIGHT, pos=(row, 1))
  2608. gridSizer.AddGrowableCol(1)
  2609. boxSizer.Add(gridSizer, flag=wx.EXPAND)
  2610. sizer.Add(boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
  2611. #
  2612. # maps to display
  2613. #
  2614. # source map to display
  2615. self.srcselection = Select(
  2616. panel,
  2617. id=wx.ID_ANY,
  2618. size=globalvar.DIALOG_GSELECT_SIZE,
  2619. type="maptype",
  2620. updateOnPopup=False,
  2621. )
  2622. self.parent.grwiz.SwitchEnv("source")
  2623. self.srcselection.SetElementList(maptype)
  2624. # filter out all maps not in group
  2625. self.srcselection.tcp.GetElementList(elements=self.parent.src_maps)
  2626. # target map(s) to display
  2627. self.parent.grwiz.SwitchEnv("target")
  2628. self.tgtrastselection = Select(
  2629. panel,
  2630. id=wx.ID_ANY,
  2631. size=globalvar.DIALOG_GSELECT_SIZE,
  2632. type="raster",
  2633. updateOnPopup=False,
  2634. extraItems=self.parent.grwiz.mappage.GetSelectTargetRasterExtraItems(),
  2635. )
  2636. self.tgtrastselection.SetElementList("cell")
  2637. self.tgtrastselection.GetElementList()
  2638. self.tgtvectselection = Select(
  2639. panel,
  2640. id=wx.ID_ANY,
  2641. size=globalvar.DIALOG_GSELECT_SIZE,
  2642. type="vector",
  2643. updateOnPopup=False,
  2644. )
  2645. self.tgtvectselection.SetElementList("vector")
  2646. self.tgtvectselection.GetElementList()
  2647. sizer.Add(
  2648. StaticText(
  2649. parent=panel, id=wx.ID_ANY, label=_("Select source map to display:")
  2650. ),
  2651. proportion=0,
  2652. flag=wx.ALIGN_LEFT | wx.ALL,
  2653. border=5,
  2654. )
  2655. sizer.Add(
  2656. self.srcselection, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=5
  2657. )
  2658. self.srcselection.SetValue(src_map)
  2659. sizer.Add(
  2660. StaticText(
  2661. parent=panel,
  2662. id=wx.ID_ANY,
  2663. label=_("Select target raster map to display:"),
  2664. ),
  2665. proportion=0,
  2666. flag=wx.ALIGN_LEFT | wx.ALL,
  2667. border=5,
  2668. )
  2669. sizer.Add(
  2670. self.tgtrastselection, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=5
  2671. )
  2672. self.tgtrastselection.SetValue(tgt_map["raster"])
  2673. sizer.Add(
  2674. StaticText(
  2675. parent=panel,
  2676. id=wx.ID_ANY,
  2677. label=_("Select target vector map to display:"),
  2678. ),
  2679. proportion=0,
  2680. flag=wx.ALIGN_LEFT | wx.ALL,
  2681. border=5,
  2682. )
  2683. sizer.Add(
  2684. self.tgtvectselection, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=5
  2685. )
  2686. self.tgtvectselection.SetValue(tgt_map["vector"])
  2687. # bindings
  2688. self.highlighthighest.Bind(wx.EVT_CHECKBOX, self.OnHighlight)
  2689. self.rmsWin.Bind(wx.EVT_TEXT, self.OnSDFactor)
  2690. self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
  2691. self.tgtrastselection.Bind(wx.EVT_TEXT, self.OnTgtRastSelection)
  2692. self.tgtvectselection.Bind(wx.EVT_TEXT, self.OnTgtVectSelection)
  2693. panel.SetSizer(sizer)
  2694. return panel
  2695. def __CreateRectificationPage(self, notebook):
  2696. """Create notebook page with symbology settings"""
  2697. panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
  2698. notebook.AddPage(page=panel, text=_("Rectification"))
  2699. sizer = wx.BoxSizer(wx.VERTICAL)
  2700. # transformation order
  2701. self.rb_grorder = wx.RadioBox(
  2702. parent=panel,
  2703. id=wx.ID_ANY,
  2704. label=" %s " % _("Select rectification order"),
  2705. choices=[_("1st order"), _("2nd order"), _("3rd order")],
  2706. majorDimension=wx.RA_SPECIFY_COLS,
  2707. )
  2708. sizer.Add(self.rb_grorder, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
  2709. self.rb_grorder.SetSelection(self.parent.gr_order - 1)
  2710. # interpolation method
  2711. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  2712. gridSizer.Add(
  2713. StaticText(
  2714. parent=panel, id=wx.ID_ANY, label=_("Select interpolation method:")
  2715. ),
  2716. pos=(0, 0),
  2717. flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  2718. border=5,
  2719. )
  2720. self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY, choices=self.methods)
  2721. gridSizer.Add(self.grmethod, pos=(0, 1), flag=wx.ALIGN_RIGHT, border=5)
  2722. self.grmethod.SetStringSelection(self.parent.gr_method)
  2723. gridSizer.AddGrowableCol(1)
  2724. sizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
  2725. # clip to region
  2726. self.check = wx.CheckBox(
  2727. parent=panel,
  2728. id=wx.ID_ANY,
  2729. label=_("clip to computational region in target location"),
  2730. )
  2731. sizer.Add(self.check, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
  2732. self.check.SetValue(self.parent.clip_to_region)
  2733. # overwrite result map
  2734. overwrite = UserSettings.Get(group="gcpman", key="map", subkey="overwrite")
  2735. self.overwrite = wx.CheckBox(
  2736. parent=panel, id=wx.ID_ANY, label=_("overwrite result map")
  2737. )
  2738. self.Bind(wx.EVT_CHECKBOX, self.OnOverwrite, self.overwrite)
  2739. sizer.Add(self.overwrite, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
  2740. self.overwrite.SetValue(overwrite)
  2741. self.parent.overwrite = overwrite
  2742. # extension
  2743. sizer.Add(
  2744. StaticText(
  2745. parent=panel, id=wx.ID_ANY, label=_("Extension for output maps:")
  2746. ),
  2747. proportion=0,
  2748. flag=wx.ALIGN_LEFT | wx.ALL,
  2749. border=5,
  2750. )
  2751. self.ext_txt = TextCtrl(parent=panel, id=wx.ID_ANY, value="", size=(350, -1))
  2752. self.ext_txt.SetValue(self.parent.extension)
  2753. sizer.Add(self.ext_txt, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=5)
  2754. # bindings
  2755. self.ext_txt.Bind(wx.EVT_TEXT, self.OnExtension)
  2756. self.Bind(wx.EVT_RADIOBOX, self.parent.OnGROrder, self.rb_grorder)
  2757. self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
  2758. self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
  2759. panel.SetSizer(sizer)
  2760. return panel
  2761. def OnHighlight(self, event):
  2762. """Checkbox 'highlighthighest' checked/unchecked"""
  2763. if self.highlighthighest.IsChecked():
  2764. self.parent.highest_only = True
  2765. self.rmsWin.Disable()
  2766. else:
  2767. self.parent.highest_only = False
  2768. self.rmsWin.Enable()
  2769. def OnSDFactor(self, event):
  2770. """New factor for RMS threshold = M + SD * factor"""
  2771. try:
  2772. self.sdfactor = float(self.rmsWin.GetValue())
  2773. except ValueError:
  2774. return
  2775. if self.sdfactor <= 0:
  2776. GError(parent=self, message=_("RMS threshold factor must be > 0"))
  2777. elif self.sdfactor < 1:
  2778. GError(
  2779. parent=self,
  2780. message=_(
  2781. "RMS threshold factor is < 1\n"
  2782. "Too many points might be highlighted"
  2783. ),
  2784. )
  2785. def OnSrcSelection(self, event):
  2786. """Source map to display selected"""
  2787. global src_map
  2788. tmp_map = self.srcselection.GetValue()
  2789. if not tmp_map == "" and not tmp_map == src_map:
  2790. self.new_src_map = tmp_map
  2791. def OnTgtRastSelection(self, event):
  2792. """Target map to display selected"""
  2793. global tgt_map
  2794. self.new_tgt_map["raster"] = self.tgtrastselection.GetValue()
  2795. def OnTgtVectSelection(self, event):
  2796. """Target map to display selected"""
  2797. global tgt_map
  2798. self.new_tgt_map["vector"] = self.tgtvectselection.GetValue()
  2799. def OnMethod(self, event):
  2800. self.parent.gr_method = self.methods[event.GetSelection()]
  2801. def OnClipRegion(self, event):
  2802. self.parent.clip_to_region = event.IsChecked()
  2803. def OnOverwrite(self, event):
  2804. self.parent.overwrite = event.IsChecked()
  2805. def OnExtension(self, event):
  2806. self.parent.extension = self.ext_txt.GetValue()
  2807. def UpdateSettings(self):
  2808. global src_map
  2809. global tgt_map
  2810. global maptype
  2811. layers = None
  2812. UserSettings.Set(
  2813. group="gcpman",
  2814. key="rms",
  2815. subkey="highestonly",
  2816. value=self.highlighthighest.GetValue(),
  2817. )
  2818. if self.sdfactor > 0:
  2819. UserSettings.Set(
  2820. group="gcpman", key="rms", subkey="sdfactor", value=self.sdfactor
  2821. )
  2822. self.parent.sdfactor = self.sdfactor
  2823. if self.parent.rmsthresh > 0:
  2824. self.parent.rmsthresh = (
  2825. self.parent.rmsmean + self.parent.sdfactor * self.parent.rmssd
  2826. )
  2827. UserSettings.Set(
  2828. group="gcpman",
  2829. key="symbol",
  2830. subkey="color",
  2831. value=tuple(wx.FindWindowById(self.symbol["color"]).GetColour()),
  2832. )
  2833. UserSettings.Set(
  2834. group="gcpman",
  2835. key="symbol",
  2836. subkey="hcolor",
  2837. value=tuple(wx.FindWindowById(self.symbol["hcolor"]).GetColour()),
  2838. )
  2839. UserSettings.Set(
  2840. group="gcpman",
  2841. key="symbol",
  2842. subkey="scolor",
  2843. value=tuple(wx.FindWindowById(self.symbol["scolor"]).GetColour()),
  2844. )
  2845. UserSettings.Set(
  2846. group="gcpman",
  2847. key="symbol",
  2848. subkey="ucolor",
  2849. value=tuple(wx.FindWindowById(self.symbol["ucolor"]).GetColour()),
  2850. )
  2851. UserSettings.Set(
  2852. group="gcpman",
  2853. key="symbol",
  2854. subkey="unused",
  2855. value=self.showunused.GetValue(),
  2856. )
  2857. UserSettings.Set(
  2858. group="gcpman",
  2859. key="symbol",
  2860. subkey="size",
  2861. value=wx.FindWindowById(self.symbol["size"]).GetValue(),
  2862. )
  2863. UserSettings.Set(
  2864. group="gcpman",
  2865. key="symbol",
  2866. subkey="width",
  2867. value=wx.FindWindowById(self.symbol["width"]).GetValue(),
  2868. )
  2869. UserSettings.Set(
  2870. group="gcpman",
  2871. key="map",
  2872. subkey="overwrite",
  2873. value=self.parent.overwrite,
  2874. )
  2875. srcrender = False
  2876. srcrenderVector = False
  2877. tgtrender = False
  2878. tgtrenderVector = False
  2879. reload_target = False
  2880. if self.new_src_map != src_map:
  2881. # remove old layer
  2882. layers = self.parent.grwiz.SrcMap.GetListOfLayers()
  2883. self.parent.grwiz.SrcMap.DeleteLayer(layers[0])
  2884. src_map = self.new_src_map
  2885. if maptype == "raster":
  2886. cmdlist = ["d.rast", "map=%s" % src_map]
  2887. srcrender = True
  2888. else:
  2889. cmdlist = ["d.vect", "map=%s" % src_map]
  2890. srcrenderVector = True
  2891. self.parent.grwiz.SwitchEnv("source")
  2892. name, found = utils.GetLayerNameFromCmd(cmdlist)
  2893. self.parent.grwiz.SrcMap.AddLayer(
  2894. ltype=maptype,
  2895. command=cmdlist,
  2896. active=True,
  2897. name=name,
  2898. hidden=False,
  2899. opacity=1.0,
  2900. render=False,
  2901. )
  2902. self.parent.grwiz.SwitchEnv("target")
  2903. if (
  2904. self.new_tgt_map["raster"] != tgt_map["raster"]
  2905. or self.new_tgt_map["vector"] != tgt_map["vector"]
  2906. ):
  2907. # remove all layers
  2908. layers = self.parent.grwiz.TgtMap.GetListOfLayers()
  2909. while layers:
  2910. self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
  2911. del layers[0]
  2912. layers = self.parent.grwiz.TgtMap.GetListOfLayers()
  2913. # self.parent.grwiz.TgtMap.DeleteAllLayers()
  2914. reload_target = True
  2915. tgt_map["raster"] = self.new_tgt_map["raster"]
  2916. tgt_map["vector"] = self.new_tgt_map["vector"]
  2917. web_service_layer = self.parent.grwiz.mappage.GetWebServiceLayers(
  2918. name=tgt_map["raster"]
  2919. )
  2920. if tgt_map["raster"] != "" and web_service_layer:
  2921. #
  2922. # add web service layer to target map
  2923. #
  2924. rendertype = web_service_layer["type"]
  2925. cmdlist = web_service_layer["cmd"]
  2926. name = tgt_map["raster"]
  2927. self.parent.grwiz.TgtMap.AddLayer(
  2928. ltype=rendertype,
  2929. command=cmdlist,
  2930. active=True,
  2931. name=name,
  2932. hidden=False,
  2933. opacity=1.0,
  2934. render=False,
  2935. )
  2936. elif tgt_map["raster"] != "":
  2937. cmdlist = ["d.rast", "map=%s" % tgt_map["raster"]]
  2938. name, found = utils.GetLayerNameFromCmd(cmdlist)
  2939. self.parent.grwiz.TgtMap.AddLayer(
  2940. ltype="raster",
  2941. command=cmdlist,
  2942. active=True,
  2943. name=name,
  2944. hidden=False,
  2945. opacity=1.0,
  2946. render=False,
  2947. )
  2948. tgtrender = True
  2949. if tgt_map["vector"] != "":
  2950. cmdlist = ["d.vect", "map=%s" % tgt_map["vector"]]
  2951. name, found = utils.GetLayerNameFromCmd(cmdlist)
  2952. self.parent.grwiz.TgtMap.AddLayer(
  2953. ltype="vector",
  2954. command=cmdlist,
  2955. active=True,
  2956. name=name,
  2957. hidden=False,
  2958. opacity=1.0,
  2959. render=False,
  2960. )
  2961. tgtrenderVector = True
  2962. if tgt_map["raster"] == "" and tgt_map["vector"] == "":
  2963. if self.parent.show_target:
  2964. self.parent.show_target = False
  2965. self.parent._mgr.GetPane("target").Hide()
  2966. self.parent._mgr.Update()
  2967. self.parent.activemap.SetSelection(0)
  2968. self.parent.activemap.Enable(False)
  2969. self.parent.GetMapToolbar().Enable("zoommenu", enable=False)
  2970. else:
  2971. if not self.parent.show_target:
  2972. self.parent.show_target = True
  2973. self.parent._mgr.GetPane("target").Show()
  2974. self.parent._mgr.Update()
  2975. self.parent.activemap.SetSelection(0)
  2976. self.parent.activemap.Enable(True)
  2977. self.parent.GetMapToolbar().Enable("zoommenu", enable=True)
  2978. self.parent.TgtMapWindow.ZoomToMap(
  2979. layers=self.parent.TgtMap.GetListOfLayers()
  2980. )
  2981. self.parent.UpdateColours(
  2982. srcrender, srcrenderVector, tgtrender, tgtrenderVector
  2983. )
  2984. self.parent.SetSettings()
  2985. def OnSave(self, event):
  2986. """Button 'Save' pressed"""
  2987. self.UpdateSettings()
  2988. fileSettings = {}
  2989. UserSettings.ReadSettingsFile(settings=fileSettings)
  2990. fileSettings["gcpman"] = UserSettings.Get(group="gcpman")
  2991. file = UserSettings.SaveToFile(fileSettings)
  2992. self.parent._giface.WriteLog(
  2993. _("GCP Manager settings saved to file '%s'.") % file
  2994. )
  2995. # self.Close()
  2996. def OnApply(self, event):
  2997. """Button 'Apply' pressed"""
  2998. self.UpdateSettings()
  2999. # self.Close()
  3000. def OnClose(self, event):
  3001. """Button 'Cancel' pressed"""
  3002. self.Close()