ii2t_manager.py 109 KB

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