manager.py 112 KB

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