From ullah at grass.itc.it Mon Oct 1 20:06:28 2007 From: ullah at grass.itc.it (ullah@grass.itc.it) Date: Mon Oct 1 20:06:29 2007 Subject: [grass-addons] r1118 - trunk/grassaddons/LandDyn/r.landscape.evol Message-ID: <200710011806.l91I6SK3023572@grass.itc.it> Author: ullah Date: 2007-10-01 20:06:22 +0200 (Mon, 01 Oct 2007) New Revision: 1118 Modified: trunk/grassaddons/LandDyn/r.landscape.evol/r.landscape.evol Log: updated statsout option to actually work... Modified: trunk/grassaddons/LandDyn/r.landscape.evol/r.landscape.evol =================================================================== --- trunk/grassaddons/LandDyn/r.landscape.evol/r.landscape.evol 2007-09-30 20:23:45 UTC (rev 1117) +++ trunk/grassaddons/LandDyn/r.landscape.evol/r.landscape.evol 2007-10-01 18:06:22 UTC (rev 1118) @@ -775,15 +775,15 @@ g.remove --quiet rast=$tmperosion,$tmpdep - if [ -e $GIS_OPT_statsout ]; then + if [ -z $GIS_OPT_statsout ]; then - txtout=$GIS_OPT_statsout + mapset=`eval g.gisenv get=MAPSET` + txtout=$mapset"_"$prefx"_lsevol_stats.txt" else + + txtout=$GIS_OPT_statsout - mapset=`eval g.gisenv get=MAPSET` - txtout=$mapset"_"$prefx"_lsevol_stats.txt" - fi echo "outputing stats to textfile: $txtout" From ullah at grass.itc.it Wed Oct 3 22:16:54 2007 From: ullah at grass.itc.it (ullah@grass.itc.it) Date: Wed Oct 3 22:16:55 2007 Subject: [grass-addons] r1119 - in trunk/grassaddons/LandDyn: . r.cfactor Message-ID: <200710032016.l93KGsD9002627@grass.itc.it> Author: ullah Date: 2007-10-03 22:16:46 +0200 (Wed, 03 Oct 2007) New Revision: 1119 Added: trunk/grassaddons/LandDyn/r.cfactor/ trunk/grassaddons/LandDyn/r.cfactor/r.cfactor trunk/grassaddons/LandDyn/r.cfactor/rules/ Log: Added the r.cfactor module, and example rules test files needed to run it. Added: trunk/grassaddons/LandDyn/r.cfactor/r.cfactor =================================================================== --- trunk/grassaddons/LandDyn/r.cfactor/r.cfactor (rev 0) +++ trunk/grassaddons/LandDyn/r.cfactor/r.cfactor 2007-10-03 20:16:46 UTC (rev 1119) @@ -0,0 +1,110 @@ +#!/bin/sh +# +############################################################################ +# +# MODULE: r.cfactor +# AUTHOR(S): Isaac Ullah, Michael Barton, Arizona State University +# PURPOSE: Converts a map of landcover values to a c-factor map based +# on a set of reclass rules +# ACKNOWLEDGEMENTS: National Science Foundation Grant #BCS0410269 +# COPYRIGHT: (C) 2007 by Isaac Ullah, Michael Barton, Arizona State University +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +############################################################################# + + +#%Module +#% description: Converts a map of landcover values to a c-factor map based on a set of reclass rules +#%END + +#%option +#% key: inmap +#% type: string +#% gisprompt: old,cell,raster +#% description: input landcover map (integer values aligned with reclass rules) +#% required : yes +#%END + +#%option +#% key: outcfact +#% type: string +#% gisprompt: string +#% description: c_factor output map name +#% answer: year1_cfactor +#% required : yes +#%END + +#%option +#% key: cfact_rules +#% type: string +#% gisprompt: string +#% description: path to recode rules file for c-factor map +#% answer: /usr/local/grass-6.3.cvs/scripts/rules/cfactor_recode_rules.txt +#% required : yes +#%END + +#%option +#% key: cfact_color +#% type: string +#% gisprompt: string +#% description: path to color rules file for c-factor map +#% answer: /usr/local/grass-6.3.cvs/scripts/rules/cfactor_colors.txt +#% required : yes +#%END + + + +if [ -z "$GISBASE" ] ; then + echo "You must be in GRASS GIS to run this program." >&2 + exit 1 +fi + +if [ "$1" != "@ARGS_PARSED@" ] ; then + exec g.parser "$0" "$@" +fi + + + +#setting up variables for use later on + +inmap=$GIS_OPT_inmap + +outcfact=$GIS_OPT_outcfact + +cfact_rules=$GIS_OPT_cfact_rules + +cfact_color=$GIS_OPT_cfact_color + +#setting initial conditions of map area + +g.region rast=$inmap + +r.mask --quiet input=$inmap maskcats=* + +#creating c-factor map and setting colors + + cat $cfact_rules | r.recode input=$inmap output=$outcfact + + r.colors map=$outcfact rules=$cfact_color + + + + +echo "" +echo "*************************" +echo " Cleaning up" +echo "*************************" +echo "" + + +g.remove --quiet rast=MASK + + + +echo "" +echo "DONE!" +echo "" +echo "" + Property changes on: trunk/grassaddons/LandDyn/r.cfactor/r.cfactor ___________________________________________________________________ Name: svn:executable + * From landa at grass.itc.it Thu Oct 4 15:28:13 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 4 15:28:15 2007 Subject: [grass-addons] r1120 - in trunk/grassaddons/gui/screenshots: . digitization general Message-ID: <200710041328.l94DSDab016166@grass.itc.it> Author: landa Date: 2007-10-04 15:28:10 +0200 (Thu, 04 Oct 2007) New Revision: 1120 Added: trunk/grassaddons/gui/screenshots/digitization/ trunk/grassaddons/gui/screenshots/digitization/digit-01.png trunk/grassaddons/gui/screenshots/digitization/digit-02.png trunk/grassaddons/gui/screenshots/digitization/digit-03.png trunk/grassaddons/gui/screenshots/digitization/digit-attributes.png trunk/grassaddons/gui/screenshots/digitization/digit-gism.png trunk/grassaddons/gui/screenshots/digitization/digit-mapdisplay.png trunk/grassaddons/gui/screenshots/digitization/digit-move.png trunk/grassaddons/gui/screenshots/digitization/digit-new-feature.png trunk/grassaddons/gui/screenshots/digitization/digit-settings-1.png trunk/grassaddons/gui/screenshots/digitization/digit-settings.png trunk/grassaddons/gui/screenshots/general/ trunk/grassaddons/gui/screenshots/general/aui-toolbars.png trunk/grassaddons/gui/screenshots/general/dbmanager-01.png trunk/grassaddons/gui/screenshots/general/gism-0.png trunk/grassaddons/gui/screenshots/general/mapdisplay-0.png trunk/grassaddons/gui/screenshots/general/wxgrass-2007-03-mac.png trunk/grassaddons/gui/screenshots/general/wxgrass-2007-05-linux.png Removed: trunk/grassaddons/gui/screenshots/aui-toolbars.png trunk/grassaddons/gui/screenshots/dbmanager-01.png trunk/grassaddons/gui/screenshots/digit-01.png trunk/grassaddons/gui/screenshots/digit-02.png trunk/grassaddons/gui/screenshots/digit-03.png trunk/grassaddons/gui/screenshots/digit-attributes.png trunk/grassaddons/gui/screenshots/digit-gism.png trunk/grassaddons/gui/screenshots/digit-mapdisplay.png trunk/grassaddons/gui/screenshots/digit-move.png trunk/grassaddons/gui/screenshots/digit-new-feature.png trunk/grassaddons/gui/screenshots/digit-settings-1.png trunk/grassaddons/gui/screenshots/digit-settings.png trunk/grassaddons/gui/screenshots/gism-0.png trunk/grassaddons/gui/screenshots/mapdisplay-0.png trunk/grassaddons/gui/screenshots/wxgrass-2007-03-mac.png trunk/grassaddons/gui/screenshots/wxgrass-2007-05-linux.png Log: reorganization, sections added Deleted: trunk/grassaddons/gui/screenshots/aui-toolbars.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/dbmanager-01.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-01.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-02.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-03.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-attributes.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-gism.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-mapdisplay.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-move.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-new-feature.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-settings-1.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/digit-settings.png =================================================================== (Binary files differ) Added: trunk/grassaddons/gui/screenshots/digitization/digit-01.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-01.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-02.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-02.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-03.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-03.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-attributes.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-attributes.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-gism.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-gism.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-mapdisplay.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-mapdisplay.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-move.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-move.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-new-feature.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-new-feature.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-settings-1.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-settings-1.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/digitization/digit-settings.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/digitization/digit-settings.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/general/aui-toolbars.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/general/aui-toolbars.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/general/dbmanager-01.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/general/dbmanager-01.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/general/gism-0.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/general/gism-0.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/general/mapdisplay-0.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/general/mapdisplay-0.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/general/wxgrass-2007-03-mac.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/general/wxgrass-2007-03-mac.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/screenshots/general/wxgrass-2007-05-linux.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/screenshots/general/wxgrass-2007-05-linux.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Deleted: trunk/grassaddons/gui/screenshots/gism-0.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/mapdisplay-0.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/wxgrass-2007-03-mac.png =================================================================== (Binary files differ) Deleted: trunk/grassaddons/gui/screenshots/wxgrass-2007-05-linux.png =================================================================== (Binary files differ) From ullah at grass.itc.it Fri Oct 5 00:02:56 2007 From: ullah at grass.itc.it (ullah@grass.itc.it) Date: Fri Oct 5 00:02:58 2007 Subject: [grass-addons] r1121 - trunk/grassaddons/LandDyn/devs_landcover_scripts/rules Message-ID: <200710042202.l94M2uq3023429@grass.itc.it> Author: ullah Date: 2007-10-05 00:02:50 +0200 (Fri, 05 Oct 2007) New Revision: 1121 Modified: trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_recode_rules.txt Log: updated rules text file Modified: trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_recode_rules.txt =================================================================== --- trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_recode_rules.txt 2007-10-04 13:28:10 UTC (rev 1120) +++ trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_recode_rules.txt 2007-10-04 22:02:50 UTC (rev 1121) @@ -1,7 +1,7 @@ -0:2:0.8:0.6 -3:7:0.6:0.3 -8:12:0.3:0.1 -13:18:0.1:0.08 -19:37:0.08:0.06 -38:50:0.06:0.05 +0:2:0.1:0.08 +3:7:0.08:0.05 +8:12:0.05:0.03 +13:18:0.03:0.01 +19:37:0.01:0.008 +38:50:0.008:0.005 end From ullah at grass.itc.it Fri Oct 5 00:04:14 2007 From: ullah at grass.itc.it (ullah@grass.itc.it) Date: Fri Oct 5 00:04:15 2007 Subject: [grass-addons] r1122 - trunk/grassaddons/LandDyn Message-ID: <200710042204.l94M4E76023449@grass.itc.it> Author: ullah Date: 2007-10-05 00:04:08 +0200 (Fri, 05 Oct 2007) New Revision: 1122 Removed: trunk/grassaddons/LandDyn/r.cfactor/ Log: got rid of eroneous script.... From landa at grass.itc.it Fri Oct 5 10:40:53 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 5 10:40:54 2007 Subject: [grass-addons] r1123 - trunk/grassaddons/gui/gui_modules Message-ID: <200710050840.l958eroi031079@grass.itc.it> Author: landa Date: 2007-10-05 10:40:52 +0200 (Fri, 05 Oct 2007) New Revision: 1123 Modified: trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/menuform.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py Log: Minor fixes, use default parameters (menuform). Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-04 22:04:08 UTC (rev 1122) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-05 08:40:52 UTC (rev 1123) @@ -88,8 +88,9 @@ # set message formatting # message_format = os.getenv("GRASS_MESSAGE_FORMAT") - os.environ["GRASS_MESSAGE_FORMAT"] = "gui" - + # os.environ["GRASS_MESSAGE_FORMAT"] = "gui" + os.environ["GRASS_MESSAGE_FORMAT"] = "txt" + # # run command ... # @@ -123,14 +124,15 @@ # # read stderr # ... - self.messages = [] - self.errors = [] - self.warnings = [] - try: - self.__ProcessMessages() # -> messages, errors, warnings - except EndOfCommand: - pass + # self.messages = [] + # self.errors = [] + # self.warnings = [] + # try: + # self.__ProcessMessages() # -> messages, errors, warnings + # except EndOfCommand: + # pass + if self.module: if wait: self.module.wait() @@ -138,9 +140,10 @@ # failed? if dlgMsg and self.returncode != 0: + errs = self.ReadErrOutput() if dlgMsg == 'gui': # GUI dialog dlg = wx.MessageDialog(None, - ("Execution failed: '%s'") % (' '.join(self.cmd)), + ("Execution failed: '%s'\n\nDetails:\n%s") % (' '.join(self.cmd), '\n'.join(errs)), ("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() @@ -181,21 +184,32 @@ else: self.messages.append(content) - def ReadStdOutput(self): - """Read standard output and return list + def __ReadOutput(self, stream): + """Read stream and return list of lines Note: Remove '\n' from output (TODO: '\r\n' ??) """ lineList = [] while True: - line = self.module_stdout.readline() + line = stream.readline() if not line: break line = line.replace('\n', '') lineList.append(line) return lineList + + def ReadStdOutput(self): + """Read standard output and return list""" + return self.__ReadOutput(self.module_stdout) + + def ReadErrOutput(self): + """Read standard error output and return list""" + + return self.__ReadOutput(self.module_stderr) + + # testing ... if __name__ == "__main__": SEP = "-----------------------------------------------------------------------------" Modified: trunk/grassaddons/gui/gui_modules/menuform.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-04 22:04:08 UTC (rev 1122) +++ trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-05 08:40:52 UTC (rev 1123) @@ -81,6 +81,7 @@ sys.path.append(imagepath) import select +import gcmd try: import subprocess except: @@ -228,10 +229,13 @@ cmd += [ '-' + flag['name'] ] for p in self.params: if p.get('value','') == '' and p.get('required','no') != 'no': - cmd += [ '%s=%s' % ( p['name'], _('') ) ] - errStr += _("Parameter %s (%s) is missing\n") % ( p['name'], p['description'] ) - errors += 1 - if p.get('value','') != '' and p['value'] != p.get('default','') : + if p.get('default', '') != '': + cmd += [ '%s=%s' % ( p['name'], p['default'] ) ] + else: + cmd += [ '%s=%s' % ( p['name'], _('') ) ] + errStr += _("Parameter %s (%s) is missing.\n") % ( p['name'], p['description'] ) + errors += 1 + elif p.get('value','') != '' and p['value'] != p.get('default','') : # Output only values that have been set, and different from defaults cmd += [ '%s=%s' % ( p['name'], p['value'] ) ] if errors and not ignoreErrors: @@ -474,7 +478,6 @@ if findALink is None and findImgLink is None: contents.append( l ) self.SetPage( "".join( contents ) ) - print "#", contents self.Ok = True except: # The Manual file was not found self.Ok = False @@ -606,7 +609,7 @@ constrained_size = self.notebookpanel.GetSize() self.notebookpanel.SetSize( (constrained_size[0],constrained_size[1]+80) ) # 80 takes the tabbar into account self.notebookpanel.Layout() - + # for too long descriptions self.description = StaticWrapText (parent=self, label=self.task.description) topsizer.Add (item=self.description, proportion=1, border=5, @@ -642,7 +645,7 @@ """Run the command""" cmd = self.createCmd() - if cmd == []: + if cmd == [] or cmd == None: return # change page if needed @@ -659,14 +662,15 @@ print >> sys.stderr, "parent window is: %s" % (str(self.parent)) # Send any other command to the shell. else: - try: - retcode = subprocess.call(cmd, shell=True) - if retcode < 0: - print >>sys.stderr, "Child was terminated by signal", -retcode - elif retcode > 0: - print >>sys.stderr, "Child returned", retcode - except OSError, e: - print >>sys.stderr, "Execution failed:", e + runCmd = gcmd.Command(cmd) + # try: + # retcode = subprocess.call(cmd, shell=True) + # if retcode < 0: + # print >>sys.stderr, "Child was terminated by signal", -retcode + # elif retcode > 0: + # print >>sys.stderr, "Child returned", retcode + # except OSError, e: + # print >>sys.stderr, "Execution failed:", e def OnCopy(self, event): """Copy the command""" Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-04 22:04:08 UTC (rev 1122) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-05 08:40:52 UTC (rev 1123) @@ -172,7 +172,7 @@ trgif = Icons["addrnum"].GetBitmap(bmpsize) self.rnum_icon = il.Add(trgif) - trgif = Icons["elvect"].GetBitmap(bmpsize) + trgif = Icons["addvect"].GetBitmap(bmpsize) self.vect_icon = il.Add(trgif) trgif = Icons["addthematic"].GetBitmap(bmpsize) From ullah at grass.itc.it Fri Oct 5 19:07:38 2007 From: ullah at grass.itc.it (ullah@grass.itc.it) Date: Fri Oct 5 19:07:39 2007 Subject: [grass-addons] r1124 - trunk/grassaddons/LandDyn/devs_landcover_scripts/rules Message-ID: <200710051707.l95H7cOr004943@grass.itc.it> Author: ullah Date: 2007-10-05 19:07:32 +0200 (Fri, 05 Oct 2007) New Revision: 1124 Modified: trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_colors.txt Log: updated cfactor color rules file to match updated cfactor recode rules values Modified: trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_colors.txt =================================================================== --- trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_colors.txt 2007-10-05 08:40:52 UTC (rev 1123) +++ trunk/grassaddons/LandDyn/devs_landcover_scripts/rules/cfactor_colors.txt 2007-10-05 17:07:32 UTC (rev 1124) @@ -1,6 +1,6 @@ -0.8 grey -0.5 red -0.3 orange -0.1 brown -0.08 yellow -0.05 green +0.1 grey +0.05 red +0.03 orange +0.01 brown +0.008 yellow +0.005 green From landa at grass.itc.it Sun Oct 7 11:02:28 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sun Oct 7 11:02:31 2007 Subject: [grass-addons] r1125 - in trunk/grassaddons/gui: display_driver gui_modules Message-ID: <200710070902.l9792Sau009537@grass.itc.it> Author: landa Date: 2007-10-07 11:02:21 +0200 (Sun, 07 Oct 2007) New Revision: 1125 Modified: trunk/grassaddons/gui/display_driver/driver.cpp trunk/grassaddons/gui/display_driver/driver.h trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py Log: Digitization tool: various fixes, driver optimalization Modified: trunk/grassaddons/gui/display_driver/driver.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-07 09:02:21 UTC (rev 1125) @@ -31,7 +31,6 @@ G_gisinit(""); /* GRASS functions */ mapInfo = NULL; - dcId = 1; dc = (wxPseudoDC *) device; @@ -39,7 +38,7 @@ pointsScreen = new wxList(); cats = Vect_new_cats_struct(); - topology.recorded = true; + drawSegments = false; } /** @@ -90,14 +89,10 @@ BOUND_BOX mapBox; struct ilist *listLines; - // initialize - dcId = 1; - ids.clear(); + // ids.clear(); listLines = Vect_new_list(); - if (force) { - ResetTopology(); - } + ResetTopology(); /* nlines = Vect_get_num_lines(mapInfo); */ @@ -131,22 +126,16 @@ #endif bool inBox; - for (int line = 1; line <= Vect_get_num_lines(mapInfo); line++) { - if (Vect_val_in_list(listLines, line)) - inBox = true; - else - inBox = false; - DrawLine(line, inBox); + dc->BeginDrawing(); + for (int i = 0; i < listLines->n_values; i++) { + DrawLine(listLines->value[i]); } + dc->EndDrawing(); #ifdef DEBUG PrintIds(); #endif - if (force) { - topology.recorded = true; - } - Vect_destroy_list(listLines); return listLines->n_values; @@ -156,39 +145,44 @@ \brief Draw selected vector objects to the device \param[in] line id - \param[in] inBox line inside of current region? \return 1 on success \return -1 on failure (vector object is dead, etc.) */ -int DisplayDriver::DrawLine(int line, bool inBox) +int DisplayDriver::DrawLine(int line) { if (!dc || !Vect_line_alive (mapInfo, line)) return -1; + int dcId; // 0 | 1 | segment id int type; // line type - int x, y, z; // screen coordinates + double x, y, z; // screen coordinates bool draw; // draw object ? + wxPen *pen; + // read line type = Vect_read_line (mapInfo, points, cats, line); // add ids // -> node1, line1, vertex1, line2, ..., node2 - struct lineDesc desc = {points->n_points, dcId}; - ids[line] = desc; + // struct lineDesc desc = {points->n_points, dcId}; + // ids[line] = desc; // update id for next line - dcId += points->n_points * 2 - 1; + // dcId += points->n_points * 2 - 1; if (IsSelected(line)) { // line selected ? - dc->SetPen(wxPen(settings.highlight, settings.lineWidth, wxSOLID)); + pen = new wxPen(settings.highlight, settings.lineWidth, wxSOLID); draw = true; + dcId = 1; + topology.highlight++; } - else if (!topology.recorded) { // determine color of vector object + else { + dcId = 0; if (type & GV_LINES) { switch (type) { case GV_LINE: - dc->SetPen(wxPen(settings.line.color, settings.lineWidth, wxSOLID)); - topology.line.push_back(line); + pen = new wxPen(settings.line.color, settings.lineWidth, wxSOLID); + topology.line++; draw = settings.line.enabled; break; case GV_BOUNDARY: @@ -196,18 +190,18 @@ Vect_get_line_areas(mapInfo, line, &left, &right); if (left == 0 && right == 0) { - dc->SetPen(wxPen(settings.boundaryNo.color, settings.lineWidth, wxSOLID)); - topology.boundaryNo.push_back(line); + pen = new wxPen(settings.boundaryNo.color, settings.lineWidth, wxSOLID); + topology.boundaryNo++; draw = settings.boundaryNo.enabled; } else if (left > 0 && right > 0) { - dc->SetPen(wxPen(settings.boundaryTwo.color, settings.lineWidth, wxSOLID)); - topology.boundaryTwo.push_back(line); + pen = new wxPen(settings.boundaryTwo.color, settings.lineWidth, wxSOLID); + topology.boundaryTwo++; draw = settings.boundaryTwo.enabled; } else { - dc->SetPen(wxPen(settings.boundaryOne.color, settings.lineWidth, wxSOLID)); - topology.boundaryOne.push_back(line); + pen = new wxPen(settings.boundaryOne.color, settings.lineWidth, wxSOLID); + topology.boundaryOne++; draw = settings.boundaryOne.enabled; } break; @@ -218,33 +212,33 @@ } else if (type & GV_POINTS) { if (type == GV_POINT && settings.point.enabled) { - dc->SetPen(wxPen(settings.point.color, settings.lineWidth, wxSOLID)); - topology.point.push_back(line); + pen = new wxPen(settings.point.color, settings.lineWidth, wxSOLID); + topology.point++; draw = settings.point.enabled; } else if (type == GV_CENTROID) { int cret = Vect_get_centroid_area(mapInfo, line); if (cret > 0) { // -> area draw = settings.centroidIn.enabled; - dc->SetPen(wxPen(settings.centroidIn.color, settings.lineWidth, wxSOLID)); - topology.centroidIn.push_back(line); + pen = new wxPen(settings.centroidIn.color, settings.lineWidth, wxSOLID); + topology.centroidIn++; } else if (cret == 0) { draw = settings.centroidOut.enabled; - dc->SetPen(wxPen(settings.centroidOut.color, settings.lineWidth, wxSOLID)); - topology.centroidOut.push_back(line); + pen = new wxPen(settings.centroidOut.color, settings.lineWidth, wxSOLID); + topology.centroidOut++; } else { draw = settings.centroidDup.enabled; - dc->SetPen(wxPen(settings.centroidDup.color, settings.lineWidth, wxSOLID)); - topology.centroidDup.push_back(line); + pen = new wxPen(settings.centroidDup.color, settings.lineWidth, wxSOLID); + topology.centroidDup++; } } } } - + // draw object - if (inBox && draw) { + if (draw) { // clear screen points & convert EN -> xy pointsScreen->Clear(); for (int i = 0; i < points->n_points; i++) { @@ -253,30 +247,47 @@ pointsScreen->Append((wxObject*) new wxPoint(x, y)); /* TODO: 3D */ } + dc->SetId(dcId); /* 0 | 1 (selected) */ + dc->SetPen(*pen); + if (type & GV_POINTS) { DrawCross(line, (const wxPoint *) pointsScreen->GetFirst()->GetData()); } else { - long int startId = ids[line].startId + 1; - - for (int i = 0; i < pointsScreen->GetCount() - 1; startId += 2) { + // long int startId = ids[line].startId + 1; + if (dcId > 0 && drawSegments) { + dcId = 2; // first segment + for (int i = 0; i < pointsScreen->GetCount() - 1; dcId += 2) { wxPoint *point_beg = (wxPoint *) pointsScreen->Item(i)->GetData(); wxPoint *point_end = (wxPoint *) pointsScreen->Item(++i)->GetData(); - + // set bounds for line // wxRect rect (*point_beg, *point_end); // dc->SetIdBounds(startId, rect); - // draw line if needed - dc->SetId(startId); + dc->SetId(dcId); // set unique id & set bbox for each segment + dc->SetPen(*pen); + wxRect rect (*point_beg, *point_end); + dc->SetIdBounds(dcId, rect); dc->DrawLine(point_beg->x, point_beg->y, point_end->x, point_end->y); + } } + else { + wxPoint points[pointsScreen->GetCount()]; + for (int i = 0; i < pointsScreen->GetCount(); i++) { + wxPoint *point_beg = (wxPoint *) pointsScreen->Item(i)->GetData(); + points[i] = *point_beg; + } + dc->DrawLines(pointsScreen->GetCount(), points); + } DrawLineVerteces(line); // draw vertices DrawLineNodes(line); // draw nodes } } + delete pen; + return 1; } @@ -292,31 +303,50 @@ */ int DisplayDriver::DrawLineVerteces(int line) { - long int id; + int dcId; wxPoint *point; + wxPen *pen; - if (!settings.vertex.enabled) + if (!IsSelected(line) && !drawSegments && !settings.vertex.enabled) return -1; // determine color if (!IsSelected(line)) { - dc->SetPen(wxPen(settings.vertex.color, settings.lineWidth, wxSOLID)); - topology.vertex.push_back(line); + pen = new wxPen(settings.vertex.color, settings.lineWidth, wxSOLID); + dcId = 0; } else { - dc->SetPen(wxPen(settings.highlight, settings.lineWidth, wxSOLID)); + pen = new wxPen(settings.highlight, settings.lineWidth, wxSOLID); + if (drawSegments) { + dcId = 3; // first vertex + } + else { + dcId = 1; + dc->SetId(dcId); + } } - // set id - id = ids[line].startId + 2; - for (int i = 1; i < pointsScreen->GetCount() - 1; i++, id += 2) { + dc->SetId(dcId); /* 0 | 1 (selected) */ + dc->SetPen(*pen); + + for (int i = 1; i < pointsScreen->GetCount() - 1; i++, dcId += 2) { point = (wxPoint*) pointsScreen->Item(i)->GetData(); - //wxRect rect (*point, *point); - //dc->SetIdBounds(id, rect); - dc->SetId(id); - DrawCross(line, (const wxPoint*) pointsScreen->Item(i)->GetData()); + + if (drawSegments) { + dc->SetId(dcId); + dc->SetPen(*pen); + wxRect rect (*point, *point); + dc->SetIdBounds(dcId, rect); + } + + if (settings.vertex.enabled) { + DrawCross(line, (const wxPoint*) pointsScreen->Item(i)->GetData()); + topology.vertex++; + } } + delete pen; + return pointsScreen->GetCount() - 2; } @@ -330,13 +360,15 @@ */ int DisplayDriver::DrawLineNodes(int line) { + int dcId; int node; - long int id; double east, north, depth; - int x, y, z; + double x, y, z; int nodes [2]; bool draw; - + + wxPen *pen; + // draw nodes?? if (!settings.nodeOne.enabled && !settings.nodeTwo.enabled) return -1; @@ -356,38 +388,48 @@ // determine color if (IsSelected(line)) { - dc->SetPen(wxPen(settings.highlight, settings.lineWidth, wxSOLID)); + pen = new wxPen(settings.highlight, settings.lineWidth, wxSOLID); draw = true; + if (!drawSegments) { + dcId = 1; + } + else { + // node1, line1, vertex1, line2, vertex2, ..., node2 + if (i == 0) // first node + dcId = 1; + else // last node + dcId = 2 * points->n_points - 1; + } } - else if (!topology.recorded) { + else { + dcId = 0; if (Vect_get_node_n_lines(mapInfo, node) == 1) { - dc->SetPen(wxPen(settings.nodeOne.color, settings.lineWidth, wxSOLID)); - topology.nodeOne.push_back(line); + pen = new wxPen(settings.nodeOne.color, settings.lineWidth, wxSOLID); + topology.nodeOne++; draw = settings.nodeOne.enabled; } else { - dc->SetPen(wxPen(settings.nodeTwo.color, settings.lineWidth, wxSOLID)); - topology.nodeTwo.push_back(line); + pen = new wxPen(settings.nodeTwo.color, settings.lineWidth, wxSOLID); + topology.nodeTwo++; draw = settings.nodeTwo.enabled; } } - // node1, line1, vertex1, line2, vertex2, ..., node2 - if (i == 0) // first node - id = dcId - points->n_points * 2 + 1; - else // last node - id = dcId - 1; - wxPoint point(x, y); - // wxRect rect (point, point); - // dc->SetIdBounds(id, rect); + if (IsSelected(line) && drawSegments) { + wxRect rect (point, point); + dc->SetIdBounds(dcId, rect); + } // draw node if needed if (draw) { - dc->SetId(id); + dc->SetId(dcId); + dc->SetPen(*pen); DrawCross(line, &point); } } + + delete pen; return 1; } @@ -472,10 +514,23 @@ \return */ void DisplayDriver::Cell2Pixel(double east, double north, double depth, - int *x, int *y, int *z) + double *x, double *y, double *z) { + double n, w; + /* *x = int((east - region.map_west) / region.map_res); *y = int((region.map_north - north) / region.map_res); + */ + w = region.center_easting - (region.map_width / 2) * region.map_res; + n = region.center_northing + (region.map_height / 2) * region.map_res; + + /* + *x = int((east - w) / region.map_res); + *y = int((n - north) / region.map_res); + */ + *x = (east - w) / region.map_res; + *y = (n - north) / region.map_res; + *z = 0; return; @@ -537,7 +592,6 @@ dc->DrawLine(point->x - size, point->y, point->x + size, point->y); dc->DrawLine(point->x, point->y - size, point->x, point->y + size); - return 1; } @@ -611,47 +665,51 @@ */ void DisplayDriver::PrintIds() { - for (ids_map::const_iterator i = ids.begin(), e = ids.end(); - i != e; ++i) { - std::cerr << "line=" << i->first << ": " - << "npoints=" << i->second.npoints - << " startId=" << i->second.startId - << std::endl; - } + /* + for (ids_map::const_iterator i = ids.begin(), e = ids.end(); + i != e; ++i) { + std::cerr << "line=" << i->first << ": " + << "npoints=" << i->second.npoints + << " startId=" << i->second.startId + << std::endl; + } + */ - std::cerr << std::endl << "topology.recorded: " << topology.recorded << std::endl; - std::cerr << "topology.point: " << topology.point.size() << std::endl; - std::cerr << "topology.line: " << topology.line.size() << std::endl; + std::cerr << "topology.highlight: " << topology.highlight << std::endl; - std::cerr << "topology.boundaryNo: " << topology.boundaryNo.size() << std::endl; - std::cerr << "topology.boundaryOne: " << topology.boundaryOne.size() << std::endl; - std::cerr << "topology.boundaryTwo: " << topology.boundaryTwo.size() << std::endl; + std::cerr << "topology.point: " << topology.point << std::endl; + std::cerr << "topology.line: " << topology.line << std::endl; - std::cerr << "topology.centroidIn: " << topology.centroidIn.size() << std::endl; - std::cerr << "topology.centroidOut: " << topology.centroidOut.size() << std::endl; - std::cerr << "topology.centroidDup: " << topology.centroidDup.size() << std::endl; + std::cerr << "topology.boundaryNo: " << topology.boundaryNo << std::endl; + std::cerr << "topology.boundaryOne: " << topology.boundaryOne << std::endl; + std::cerr << "topology.boundaryTwo: " << topology.boundaryTwo << std::endl; - std::cerr << "topology.nodeOne: " << topology.nodeOne.size() << std::endl; - std::cerr << "topology.nodeTwo: " << topology.nodeTwo.size() << std::endl; + std::cerr << "topology.centroidIn: " << topology.centroidIn << std::endl; + std::cerr << "topology.centroidOut: " << topology.centroidOut << std::endl; + std::cerr << "topology.centroidDup: " << topology.centroidDup << std::endl; - std::cerr << "topology.vertex: " << topology.vertex.size() << std::endl; + std::cerr << "topology.nodeOne: " << topology.nodeOne << std::endl; + std::cerr << "topology.nodeTwo: " << topology.nodeTwo << std::endl; - std::cerr << std::endl << "nprimitives: " - << topology.point.size() + - topology.line.size() + - topology.boundaryNo.size() + - topology.boundaryOne.size() + - topology.boundaryTwo.size() + - topology.centroidIn.size() * 2 + - topology.centroidOut.size() * 2 + - topology.centroidDup.size() * 2 + - topology.nodeOne.size() * 2 + - topology.nodeTwo.size() * 2 + - topology.vertex.size() * 2 << std::endl; + std::cerr << "topology.vertex: " << topology.vertex << std::endl; + std::cerr << std::endl << "nobjects: " + << topology.point * 2 + // cross + topology.line + + topology.boundaryNo + + topology.boundaryOne + + topology.boundaryTwo + + topology.centroidIn * 2 + + topology.centroidOut * 2 + + topology.centroidDup * 2 + + topology.nodeOne * 2 + + topology.nodeTwo * 2 + + topology.vertex * 2 << std::endl; + + std::cerr << "selected: "; for (std::vector::const_iterator i = selected.begin(), e = selected.end(); i != e; ++i) - std::cerr << "selected: " << *i << " "; + std::cerr << *i << " "; std::cerr << std::endl; return; @@ -723,15 +781,26 @@ \return point on line if line found */ std::vector DisplayDriver::SelectLineByPoint(double x, double y, double thresh, - int onlyType) + int type) { long int line; - int type; + int ftype; double px, py, pz; std::vector p; + + if (type == -1) { + ftype = GV_POINTS | GV_LINES; + } + else if (type == 0) { + ftype = GV_POINTS; + } + else if (type == 1) { + ftype = GV_LINES; + } + line = Vect_find_line(mapInfo, x, y, 0.0, - GV_POINTS | GV_LINES, thresh, 0, 0); + ftype, thresh, 0, 0); if (line > 0) { selected.push_back(line); @@ -743,6 +812,8 @@ p.push_back(py); } + drawSegments = true; + return p; } @@ -777,6 +848,7 @@ void DisplayDriver::Unselect() { selected.clear(); + drawSegments = false; return; } @@ -796,6 +868,20 @@ std::vector dc_ids; long int line; + + if (!drawSegments) { + dc_ids.push_back(1); + } + else { + int npoints; + Vect_read_line(mapInfo, points, NULL, selected[0]); + npoints = points->n_points; + for (int i = 1; i < 2 * npoints; i++) { + dc_ids.push_back(i); + } + } + + /* for(std::vector::const_iterator i = selected.begin(), e = selected.end(); i != e; ++i) { line = *i; @@ -821,6 +907,7 @@ } } } + */ return dc_ids; } @@ -851,22 +938,24 @@ */ std::vector DisplayDriver::GetSelectedVertex(double x, double y) { - struct lineDesc *desc; // line desription - + int startId; int line, type; int Gid, DCid; - int vx, vy, vz; // vertex screen coordinates + double vx, vy, vz; // vertex screen coordinates double dist, minDist; std::vector returnId; // only one object can be selected - if (selected.size() != 1) + if (selected.size() != 1 || !drawSegments) return returnId; + startId = 1; line = selected[0]; - + + std::cerr << line << std::endl; + type = Vect_read_line (mapInfo, points, cats, line); // find the closest vertex (x, y) @@ -886,10 +975,11 @@ } } - desc = &(ids[line]); + // desc = &(ids[line]); // translate id - DCid = Gid * 2 + desc->startId; + // DCid = Gid * 2 + desc->startId; + DCid = Gid * 2 + 1; // add selected vertex returnId.push_back(DCid); @@ -897,9 +987,8 @@ &vx, &vy, &vz); wxRect rect (wxPoint (vx, vy), wxPoint (vx, vy)); dc->SetIdBounds(DCid, rect); - // left vertex - if (DCid == desc->startId) { + if (DCid == startId) { returnId.push_back(-1); } else { @@ -911,7 +1000,7 @@ } // right vertex - if (DCid == (desc->npoints - 1) * 2 + desc->startId) { + if (DCid == (points->n_points - 1) * 2 + startId) { returnId.push_back(-1); } else { @@ -932,23 +1021,23 @@ */ void DisplayDriver::ResetTopology() { - topology.recorded = false; - - topology.point.clear(); - topology.line.clear(); + topology.highlight = 0; - topology.boundaryNo.clear(); - topology.boundaryOne.clear(); - topology.boundaryTwo.clear(); + topology.point = 0; + topology.line = 0; - topology.centroidIn.clear(); - topology.centroidOut.clear(); - topology.centroidDup.clear(); + topology.boundaryNo = 0; + topology.boundaryOne = 0; + topology.boundaryTwo = 0; - topology.nodeOne.clear(); - topology.nodeTwo.clear(); + topology.centroidIn = 0; + topology.centroidOut = 0; + topology.centroidDup = 0; - topology.vertex.clear(); + topology.nodeOne = 0; + topology.nodeTwo = 0; + + topology.vertex = 0; return; } Modified: trunk/grassaddons/gui/display_driver/driver.h =================================================================== --- trunk/grassaddons/gui/display_driver/driver.h 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/display_driver/driver.h 2007-10-07 09:02:21 UTC (rev 1125) @@ -33,18 +33,29 @@ { private: wxPseudoDC *dc; // device content - long int dcId; // wxDC id starting + /* disabled due to expensive calling dc->SetId() + * + * currently all objects are drawn without id + * + * only selected lines with id '1' + * + * segments with unique id (starting with '1') + * are drawn only when line was selected using SelectLineByPoint() + */ + /* struct lineDesc { int npoints; long int startId; }; - + typedef std::map ids_map; - + ids_map ids; // gId : {dcIds, ...} + */ std::vector selected; // list of selected features (gId) + bool drawSegments; // draw segments of selected line struct Map_info *mapInfo; struct line_pnts *points; // east, north, depth @@ -74,7 +85,7 @@ struct _settings { wxColor highlight; - + symbol point; symbol line; @@ -96,31 +107,31 @@ } settings; struct _topology { - std::vector point; - std::vector line; + long int highlight; - std::vector boundaryNo; - std::vector boundaryOne; - std::vector boundaryTwo; + long int point; + long int line; - std::vector centroidIn; - std::vector centroidOut; - std::vector centroidDup; + long int boundaryNo; + long int boundaryOne; + long int boundaryTwo; - std::vector nodeOne; - std::vector nodeTwo; + long int centroidIn; + long int centroidOut; + long int centroidDup; - std::vector vertex; + long int nodeOne; + long int nodeTwo; - bool recorded; // topology already recorded + long int vertex; } topology; void Cell2Pixel (double east, double north, double depth, - int *x, int *y, int *z); + double *x, double *y, double *z); int DrawCross(int line, const wxPoint *point, int size=5); - int DrawLine(int line, bool inBox); + int DrawLine(int line); int DrawLineVerteces(int line); int DrawLineNodes(int line); @@ -144,7 +155,7 @@ /* select */ int SelectLinesByBox(double x1, double y1, double x2, double y2); std::vector SelectLineByPoint(double x, double y, double thresh, - int onlyType); + int type); void Unselect(); std::vector GetSelected(bool grassId); Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-07 09:02:21 UTC (rev 1125) @@ -50,6 +50,8 @@ except: print >> sys.stderr, "Digitization tool is disabled.\n" \ "Under development...\n" + +USEVEDIT = True class AbstractDigit: """ @@ -72,8 +74,8 @@ self.settings["symbolPoint"] = (True, (0, 0, 0, 255)) # black self.settings["symbolLine"] = (True, (0, 0, 0, 255)) # black self.settings["symbolBoundaryNo"] = (True, (126, 126, 126, 255)) # grey - self.settings["symbolBoundaryOne"] = (True, (255, 135, 0, 255)) # orange - self.settings["symbolBoundaryTwo"] = (True, (0, 255, 0, 255)) # green + self.settings["symbolBoundaryOne"] = (True, (0, 255, 0, 255)) # green + self.settings["symbolBoundaryTwo"] = (True, (255, 135, 0, 255)) # orange self.settings["symbolCentroidIn"] = (True, (0, 0, 255, 255)) # blue self.settings["symbolCentroidOut"] = (True, (165, 42, 42, 255)) # brown self.settings["symbolCentroidDup"] = (True, (156, 62, 206, 255)) # violet @@ -85,7 +87,7 @@ self.settings["lineWidth"] = (2, "screen pixels") # snapping - self.settings["snapping"] = (20, "screen pixels") # value, unit + self.settings["snapping"] = (10, "screen pixels") # value, unit self.settings["snapToVertex"] = False # digitize new record @@ -98,8 +100,6 @@ self.driver = CDisplayDriver(self, mapwindow) - self.threshold = self.driver.GetThreshold() - def SetCategoryNextToUse(self): """Find maximum category number in the map layer and update Digit.settings['category'] @@ -180,7 +180,7 @@ Debug.msg (4, "Vline.AddPoint(): input=%s" % addstring) - self._AddFeature (map=map, input=addstring, flags=['-s']) + self._AddFeature (map=map, input=addstring) def AddLine (self, map, type, coords): """ @@ -194,10 +194,10 @@ if type == "boundary": key = "B" - flags = ['-c', '-s'] # close boundaries + flags = ['-c'] # close boundaries else: key = "L" - flags = ['-s'] + flags = [] addstring="""%s %d 1\n""" % (key, len(coords)) for point in coords: @@ -216,7 +216,7 @@ self._AddFeature (map=map, input=addstring, flags=flags) - def _AddFeature (self, map, input, flags): + def _AddFeature (self, map, input, flags=[]): """ General method which adds feature to the vector map """ @@ -224,7 +224,8 @@ command = ["v.edit", "-n", "--q", "map=%s" % map, "tool=add", - "thresh=%f" % self.threshold] + "thresh=%f" % self.driver.GetThreshold(), + "snap=node"] # additional flags for flag in flags: @@ -283,15 +284,17 @@ Debug.msg(4, "Digit.MoveSelectedLines(): ids=%s, move=%s" % \ (ids, move)) - command = ["v.edit", "--q", "-s", # snap + command = ["v.edit", "--q", "map=%s" % self.map, "tool=%s" % tool, "ids=%s" % ids, "move=%f,%f" % (float(move[0]),float(move[1])), - "thresh=%f" % self.threshold] + "thresh=%f" % self.driver.GetThreshold(), + "snap=node"] if tool == "vertexmove": command.append("coords=%f,%f" % (float(coords[0]), float(coords[1]))) + command.append("-1") # modify only first selected # run the command vedit = cmd.Command(cmd=command) @@ -314,7 +317,7 @@ "tool=break", "ids=%s" % line, "coords=%f,%f" % (float(coords[0]),float(coords[1])), - "thresh=%f" % self.threshold] + "thresh=%f" % self.driver.GetThreshold()] # run the command vedit = cmd.Command(cmd=command) @@ -344,7 +347,7 @@ "tool=%s" % action, "ids=%s" % line, "coords=%f,%f" % (float(coords[0]),float(coords[1])), - "thresh=%f" % self.threshold] + "thresh=%f" % self.driver.GetThreshold()] # run the command vedit = cmd.Command(cmd=command) @@ -379,21 +382,56 @@ 'ids=%s' % line]) # add line - self.AddLine(self.map, "line", coords) + if len(coords) > 0: + self.AddLine(self.map, "line", coords) + # reload map (needed for v.edit) + self.driver.ReloadMap() + class VDigit(AbstractDigit): """ Prototype of digitization class based on v.digit reimplementation Under development (wxWidgets C/C++ background) """ - pass + def __init__(self, mapwindow, settings=None): + AbstractDigit.__init__(self, mapwindow, settings) -class Digit(VEdit): - """Default digit class""" - def __init__(self, mapwindow): - VEdit.__init__(self, mapwindow) + try: + from grass6_wxdriver import DigitClass + self.digit = DigitClass() + except: + self.digit = None + def DeleteSelectedLines(self): + """Delete selected vector features from the vector map""" + + selected = self.driver.GetSelected() # grassId + + if len(selected) <= 0: + return False + + ids = ",".join(["%d" % v for v in selected]) + + Debug.msg(4, "Digit.DeleteSelectedLines(): ids=%s" % \ + ids) + + self.digit.DeleteSelectedLines() + #self.driver.DrawUpdatedLines() + + return True + +if USEVEDIT: + class Digit(VEdit): + """Default digit class""" + def __init__(self, mapwindow): + VEdit.__init__(self, mapwindow) +else: + class Digit(VDigit): + """Default digit class""" + def __init__(self, mapwindow): + VDigit.__init__(self, mapwindow) + class AbstractDisplayDriver: """Abstract classs for display driver""" def __init__(self, parent, mapwindow): @@ -434,6 +472,8 @@ def __init__(self, parent, mapwindow): AbstractDisplayDriver.__init__(self, parent, mapwindow) + self.mapWindow = mapwindow + # initialize wx display driver try: self.__display = DisplayDriver(mapwindow.pdcVector) @@ -477,11 +517,10 @@ return nlines - def SelectLinesByBox(self, begin, end, onlyType=None): + def SelectLinesByBox(self, begin, end, type=None): """Select vector features by given bounding box. - Number of selected features can be decreased by 'onlyType' - ('None' for no types) + If type is given, only vector features of given type are selected. """ x1, y1 = begin @@ -493,14 +532,22 @@ return nselected - def SelectLineByPoint(self, point, onlyType=None): - """Select vector feature by coordinates of click point. - Number of selected features can be decreased by 'onlyType' - ('None' for all types)""" + def SelectLineByPoint(self, point, type=None): + """Select vector feature by coordinates of click point (in given threshold). + If type is given, only vector features of given type are selected. + """ + + ftype = -1 # all types + if type: + if type == "point": + ftype = 0 + else: + ftype = 1 # line + pointOnLine = self.__display.SelectLineByPoint(point[0], point[1], - float(self.parent.threshold), - -1); + self.GetThreshold(), + ftype); if len(pointOnLine) > 0: Debug.msg(4, "CDisplayDriver.SelectLineByPoint(): pointOnLine=%f,%f" % \ @@ -780,8 +827,8 @@ vertexSizer.Add(item=self.snapVertex, proportion=0, flag=wx.EXPAND) self.mapUnits = self.parent.MapWindow.Map.ProjInfo()['units'] self.snappingInfo = wx.StaticText(parent=panel, id=wx.ID_ANY, - label=_("Note: snapping threshold is %.1f %s") % \ - (self.parent.digit.threshold, + label=_("Snapping threshold is currently %.1f %s") % \ + (self.parent.digit.driver.GetThreshold(), self.mapUnits)) vertexSizer.Add(item=self.snappingInfo, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) @@ -891,7 +938,7 @@ """Change snapping value - update static text""" value = self.snappingValue.GetValue() threshold = self.parent.digit.driver.GetThreshold(value) - self.snappingInfo.SetLabel(_("Snapping threshold is %.1f %s") % \ + self.snappingInfo.SetLabel(_("Snapping threshold is currently %.1f %s") % \ (threshold, self.mapUnits)) Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-07 09:02:21 UTC (rev 1125) @@ -149,9 +149,8 @@ dlg.Destroy() else: # otherwise 'txt' print >> sys.stderr, "Execution failed: '%s'" % (' '.join(self.cmd)) - print >> sys.stderr, "Details:" - for err in self.errors: - print >> sys.stderr, " %s" % err + print >> sys.stderr, "Details:\n%s" % '\n'.join(errs) + else: self.returncode = None # running ? Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-07 09:02:21 UTC (rev 1125) @@ -523,6 +523,8 @@ digitToolbar.layerSelectedID != None: # set region self.parent.digit.driver.UpdateRegion() + # re-calculate threshold for digitization tool + self.parent.digit.driver.GetThreshold() # draw map self.pdcVector.Clear() self.pdcVector.RemoveAll() @@ -997,12 +999,12 @@ if digitToolbar.action in ["moveVertex", "editLine"]: if len(driver.GetSelected()) == 0: # -> move vertex (select by point) - nselected = driver.SelectLineByPoint(pos1, onlyType="line") + nselected = driver.SelectLineByPoint(pos1, type="line") elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsIds"): # collect categories - nselected = driver.SelectLineByPoint(pos1, onlyType="line") + nselected = driver.SelectLineByPoint(pos1, type="line") if nselected: qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / \ self.Map.width) @@ -1035,25 +1037,28 @@ "copyCats", "editLine"]: # -> move line || move vertex self.UpdateMap(render=False) + # get pseudoDC id of objects which should be redrawn if digitToolbar.action == "moveLine": # -> move line self.moveIds = driver.GetSelected(grassId=False) + elif digitToolbar.action == "moveVertex": # -> move vertex self.moveIds = driver.GetSelectedVertex(pos1) + elif digitToolbar.action == "editLine": # -> edit line ids = driver.GetSelected(grassId=False) for id in ids: - if id % 2: # only verteces - self.moveIds.append(id) + if id % 2: # vertex + self.moveIds.append(id) else: self.UpdateMap(render=False, renderVector=False) elif digitToolbar.action in ["splitLine", "addVertex", "removeVertex"]: pointOnLine = driver.SelectLineByPoint(pos1, - onlyType="line") + type="line") if pointOnLine: self.UpdateMap(render=False) # highlight object if digitToolbar.action in ["splitLine", "addVertex"]: @@ -1213,20 +1218,24 @@ elif digit.action in ["moveLine", "moveVertex"] and \ hasattr(self, "moveBegin"): # move vector feature - move = [self.Distance((0,0), (self.moveBegin[0], 0))[0], - self.Distance((0,0), (0, self.moveBegin[1]))[0]] # TODO d.measure + # move = [self.Distance((0,0), (self.moveBegin[0], 0))[0], + # self.Distance((0,0), (0, self.moveBegin[1]))[0]] # TODO d.measure # ES -> EN - if self.moveBegin[0] < 0.0: - move[0] *= -1.0 - if self.moveBegin[1] > 0.0: - move[1] *= -1.0 + # if self.moveBegin[0] < 0.0: + # move[0] *= -1.0 + # if self.moveBegin[1] > 0.0: + # move[1] *= -1.0 + pTo = self.Pixel2Cell(event.GetPositionTuple()) + pFrom = self.Pixel2Cell(self.moveCoords) + move = (pTo[0]-pFrom[0], pTo[1]-pFrom[1]) + if digit.action == "moveLine": # move line self.parent.digit.MoveSelectedLines(move) elif digit.action == "moveVertex": # move vertex - self.parent.digit.MoveSelectedVertex(self.Pixel2Cell(self.moveCoords), + self.parent.digit.MoveSelectedVertex(pFrom, move) else: # edit line pass @@ -1441,9 +1450,6 @@ def Cell2Pixel(self, (east, north)): """ Convert real word coordinates to image coordinates - - Input : float east, float north - Output: int x, int y """ try: @@ -1460,9 +1466,12 @@ w = self.Map.region["center_easting"] - (self.Map.width / 2) * res n = self.Map.region["center_northing"] + (self.Map.height / 2) * res - x = int((east - w) / res) - y = int((n - north) / res) + # x = int((east - w) / res) + # y = int((n - north) / res) + x = (east - w) / res + y = (n - north) / res + return (x, y) def Zoom(self, begin, end, zoomtype): Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-07 09:02:21 UTC (rev 1125) @@ -337,6 +337,7 @@ self.action = "addLine" self.type = "line" self.parent.MapWindow.mouse['box'] = 'line' + self.parent.MapWindow.polycoords = [] # reset temp line def OnAddBoundary(self, event): """Add boundary to the vector map layer""" @@ -344,6 +345,7 @@ self.action = "addLine" self.type = "boundary" self.parent.MapWindow.mouse['box'] = 'line' + self.parent.MapWindow.polycoords = [] # reset temp line def OnAddCentroid(self, event): """Add centroid to the vector map layer""" Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-05 17:07:32 UTC (rev 1124) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-07 09:02:21 UTC (rev 1125) @@ -11,9 +11,9 @@ for GIS map layer management, command console, and command parsing. AUTHORS: The GRASS Development Team - Michael Barton (Arizona State University) & + Michael Barton (Arizona State University) Jachym Cepicky (Mendel University of Agriculture) - Martin Landa + Martin Landa COPYRIGHT: (C) 2007 by the GRASS Development Team This program is free software under the GNU General Public @@ -283,7 +283,8 @@ (digit and digit.layerSelectedID != None and \ digit.layers[digit.layerSelectedID] == layer): self.popupMenu.Enable (self.popupID5, False) - self.popupMenu.Enable (self.popupID6, True) + if layer.GetMapset() == grassenv.env["MAPSET"]: + self.popupMenu.Enable (self.popupID6, True) # raster elif mltype and mltype == "raster": From neteler at grass.itc.it Mon Oct 8 21:47:15 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Mon Oct 8 21:47:15 2007 Subject: [grass-addons] r1126 - in trunk/grassaddons: . IPCC Message-ID: <200710081947.l98JlELf004234@grass.itc.it> Author: neteler Date: 2007-10-08 21:47:10 +0200 (Mon, 08 Oct 2007) New Revision: 1126 Added: trunk/grassaddons/IPCC/ trunk/grassaddons/IPCC/README trunk/grassaddons/IPCC/gcm2grass.pl Log: Script to read SRES scenarios from IPCC into GRASS Added: trunk/grassaddons/IPCC/README =================================================================== --- trunk/grassaddons/IPCC/README (rev 0) +++ trunk/grassaddons/IPCC/README 2007-10-08 19:47:10 UTC (rev 1126) @@ -0,0 +1,19 @@ +SCRIPT TO READ SRES scenarios from IPCC + +Authors: Radim Blazek and Marta Benito Garz?n + +Converts Global Circulation Model (GCM) Climate Change Scenarios +from GCM ascii format to 12 GRASS raster files (1 for each month) +and changes longitude from 0-360 + +Data + http://www.ipcc-data.org/sres/gcm_data.html + +Reference: + M. Benito Garz?n, R. Blazek, M. Neteler, R. Sanchez de Dios, H. Sainz + Ollero, and C. Furlanello, 2006: Predicting habitat suitability with + Machine Learning models: the potential area of Pinus sylvestris L. in + the Iberian Peninsula. Ecological Modelling, + 197(3-4):383-393. doi:10.1016/j.ecolmodel.2006.03.015 + http://www.uam.es/proyectosinv/Mclim/pdf/MBenito_EcoMod.pdf + Added: trunk/grassaddons/IPCC/gcm2grass.pl =================================================================== --- trunk/grassaddons/IPCC/gcm2grass.pl (rev 0) +++ trunk/grassaddons/IPCC/gcm2grass.pl 2007-10-08 19:47:10 UTC (rev 1126) @@ -0,0 +1,133 @@ +#!/usr/bin/perl +# +# Authors: Radim Blazek and Marta Benito Garz?n +# +# Converts GCM ascii format to 12 GRASS raster files (1 for each month) +# and changes longitude from 0-360 +# http://www.ipcc-data.org/sres/gcm_data.html +# +# Reference: +# M. Benito Garz?n, R. Blazek, M. Neteler, R. Sanchez de Dios, H. Sainz +# Ollero, and C. Furlanello, 2006: Predicting habitat suitability with +# Machine Learning models: the potential area of Pinus sylvestris L. in +# the Iberian Peninsula. Ecological Modelling, +# 197(3-4):383-393. doi:10.1016/j.ecolmodel.2006.03.015 +# http://www.uam.es/proyectosinv/Mclim/pdf/MBenito_EcoMod.pdf +# +################## + +for($i=0; $i<=$#ARGV; $i++){ + if( $ARGV[$i] =~ /input=(.+)/){ $input = $1; } + elsif( $ARGV[$i] =~ /output=(.+)/){ $output = $1; } +} + +if ( length($input) == 0 || length($output) == 0 ) { + die "File not specified\nParameters:\n input=\n output=\n"; +} + +open(IN, "<$input") or die "Cannot open input: $input"; + + +while ( $r = ){ + chomp $r; + + # Header 1 + $r = lc ($r); + if ( !($r =~ /ipcc data distribution centre results/) ) { die "Wrong input: $r\n"; } + + # Header 2 + $r = ; chomp $r; + $r = lc ($r); + if ( !($r =~ /grid is/) ) { die "Wrong input: $r\n"; } + ($t, $t, $cols, $t, $rows, $t, $t, $month ) = split / +/, $r; + $month = lc ( $month ); + $rows = int ($rows); + $cols = int($cols); + print "Cols = $cols Rows = $rows Month = $month\n"; + + # Header 3 + $r = ; chomp $r; + $r = lc ($r); + if ( !($r =~ /mean change values/) ) { die "Wrong input: $r\n"; } + + # Header 4 + $r = ; chomp $r; + + # Header 5 + $r = ; chomp $r; + + # Header 6 + $r = ; chomp $r; + $r = lc ($r); + if ( !($r =~ /missing/) ) { die "Wrong input: $r\n"; } + $r =~ /.* ([^ ]+)/; + $null = $1; + print "Null = $null\n"; + +$outfile = $output . $month; + print "Output file = $outfile\n"; + open ( OUT, ">$outfile") or die "Cannot open $outfile"; + print OUT "north: 90N\n"; + print OUT "south: 90S\n"; + print OUT "west: 180W\n"; + print OUT "east: 180E\n"; + print OUT "rows: $rows\n"; + print OUT "cols: $cols\n"; + print OUT "null: $null\n"; + print OUT "type: float\n"; + + $ncels = $cols * $rows; + $nread = 0; + + $col = $row = 0; + while ( $r = ){ + chomp $r; + $r =~ s/^ +//; + $r =~ s/ +/ /g; + + @value = split / /, $r; + $n = $#value; + $nread += $n + 1; + + #print OUT "$r\n"; + + for ( $i = 0; $i <= $n; $i++ ) { + #print "$row $col $value[$i]\n"; + $all[$row][$col] = $value[$i]; + + $col++; + if ( $col == $cols ) { + $col = 0; + $row++; + } + } + + if ( $nread >= $ncels ) { + for ( $r = 0; $r < $rows; $r++ ) { + $start = $cols/2; + #print "start = $start\n"; + for ( $c = $start; $c < $cols; $c++ ) { + #print "$r $c $all[$r][$c]\n"; + print OUT "$all[$r][$c] "; + } + for ( $c = 0; $c < $cols/2; $c++ ) { + #print "$r $c $all[$r][$c]\n"; + print OUT "$all[$r][$c] "; + } + print OUT "\n"; + } + close (OUT); + last; + } + } + + print "\n"; +} +close(IN); + + + + + + + Property changes on: trunk/grassaddons/IPCC/gcm2grass.pl ___________________________________________________________________ Name: svn:executable + * From neteler at grass.itc.it Tue Oct 9 10:32:49 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Tue Oct 9 10:32:50 2007 Subject: [grass-addons] r1127 - trunk/grassaddons/IPCC Message-ID: <200710090832.l998WnwI012939@grass.itc.it> Author: neteler Date: 2007-10-09 10:32:47 +0200 (Tue, 09 Oct 2007) New Revision: 1127 Modified: trunk/grassaddons/IPCC/gcm2grass.pl Log: fix author Modified: trunk/grassaddons/IPCC/gcm2grass.pl =================================================================== --- trunk/grassaddons/IPCC/gcm2grass.pl 2007-10-08 19:47:10 UTC (rev 1126) +++ trunk/grassaddons/IPCC/gcm2grass.pl 2007-10-09 08:32:47 UTC (rev 1127) @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# Authors: Radim Blazek and Marta Benito Garz?n +# Author: Radim Blazek, ITC-irst, 2005 # # Converts GCM ascii format to 12 GRASS raster files (1 for each month) # and changes longitude from 0-360 From landa at grass.itc.it Tue Oct 9 11:44:19 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 9 11:44:21 2007 Subject: [grass-addons] r1128 - in trunk/grassaddons/gui: display_driver gui_modules icons icons/silk Message-ID: <200710090944.l999iJGV014026@grass.itc.it> Author: landa Date: 2007-10-09 11:44:10 +0200 (Tue, 09 Oct 2007) New Revision: 1128 Added: trunk/grassaddons/gui/icons/silk/plugin.png Modified: trunk/grassaddons/gui/display_driver/driver.h trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py trunk/grassaddons/gui/icons/icon.py trunk/grassaddons/gui/icons/silk/__init__.py Log: Digitization tool: additional tools implemented (flip, connect, merge, copy). Copy from backround map need to be finished. Modified: trunk/grassaddons/gui/display_driver/driver.h =================================================================== --- trunk/grassaddons/gui/display_driver/driver.h 2007-10-09 08:32:47 UTC (rev 1127) +++ trunk/grassaddons/gui/display_driver/driver.h 2007-10-09 09:44:10 UTC (rev 1128) @@ -27,7 +27,7 @@ #include } -#define DEBUG +// #define DEBUG class DisplayDriver { Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-09 08:32:47 UTC (rev 1127) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-09 09:44:10 UTC (rev 1128) @@ -39,7 +39,7 @@ import wx.lib.colourselect as csel import wx.lib.mixins.listctrl as listmix -import gcmd as cmd +import gcmd import dbm from debug import Debug as Debug import select @@ -69,7 +69,7 @@ if not settings: self.settings = {} # symbology - self.settings["symbolBackground"] = (None, (255,255,255, 255)) # white +# self.settings["symbolBackground"] = (None, (255,255,255, 255)) # white self.settings["symbolHighlight"] = (None, (255, 255, 0, 255)) #yellow self.settings["symbolPoint"] = (True, (0, 0, 0, 255)) # black self.settings["symbolLine"] = (True, (0, 0, 0, 255)) # black @@ -89,6 +89,7 @@ # snapping self.settings["snapping"] = (10, "screen pixels") # value, unit self.settings["snapToVertex"] = False + self.settings["backgroundMap"] = 'a1@martin' # digitize new record self.settings["addRecord"] = True @@ -110,7 +111,7 @@ self.settings['category'] = 1 if self.map: - categoryCmd = cmd.Command(cmd=["v.category", "-g", "--q", + categoryCmd = gcmd.Command(cmd=["v.category", "-g", "--q", "input=%s" % self.map, "option=report", "layer=%d" % self.settings["layer"]]) @@ -212,7 +213,7 @@ Debug.msg (3, "Vline.AddLine(): type=%s, layer=%d, cat=%d coords=%s" % \ (key, coords)) - Debug.msg (4, "Vline.AddLine(): input=%s" % addstring) + Debug.msg (4, "VEdit.AddLine(): input=%s" % addstring) self._AddFeature (map=map, input=addstring, flags=flags) @@ -220,19 +221,31 @@ """ General method which adds feature to the vector map """ - + + if self.settings['snapping'][0] <= 0: + snap = "no" + else: + if self.settings['snapToVertex']: + snap = "vertex" + else: + snap = "node" + command = ["v.edit", "-n", "--q", "map=%s" % map, "tool=add", "thresh=%f" % self.driver.GetThreshold(), - "snap=node"] + "snap=%s" % snap] + if self.settings['backgroundMap'] != '': + command.append("bgmap=%s" % self.settings['backgroundMap']) + # additional flags for flag in flags: command.append(flag) # run the command - vedit = cmd.Command(cmd=command, stdin=input) + Debug.msg(4, "VEdit._AddFeature(): input=%s" % input) + vedit = gcmd.Command(cmd=command, stdin=input) # reload map (needed for v.edit) self.driver.ReloadMap() @@ -256,7 +269,7 @@ "ids=%s" % ids] # run the command - vedit = cmd.Command(cmd=command) + vedit = gcmd.Command(cmd=command) # reload map (needed for v.edit) self.driver.ReloadMap() @@ -284,20 +297,29 @@ Debug.msg(4, "Digit.MoveSelectedLines(): ids=%s, move=%s" % \ (ids, move)) + if self.settings['snapping'][0] <= 0: + snap = "no" + else: + if self.settings['snapToVertex']: + snap = "vertex" + else: + snap = "node" + + command = ["v.edit", "--q", "map=%s" % self.map, "tool=%s" % tool, "ids=%s" % ids, "move=%f,%f" % (float(move[0]),float(move[1])), "thresh=%f" % self.driver.GetThreshold(), - "snap=node"] + "snap=%s" % snap] if tool == "vertexmove": command.append("coords=%f,%f" % (float(coords[0]), float(coords[1]))) command.append("-1") # modify only first selected # run the command - vedit = cmd.Command(cmd=command) + vedit = gcmd.Command(cmd=command) # reload map (needed for v.edit) self.driver.ReloadMap() @@ -320,7 +342,7 @@ "thresh=%f" % self.driver.GetThreshold()] # run the command - vedit = cmd.Command(cmd=command) + vedit = gcmd.Command(cmd=command) # redraw map self.driver.ReloadMap() @@ -350,7 +372,7 @@ "thresh=%f" % self.driver.GetThreshold()] # run the command - vedit = cmd.Command(cmd=command) + vedit = gcmd.Command(cmd=command) # reload map (needed for v.edit) self.driver.ReloadMap() @@ -363,7 +385,7 @@ return False # collect cats - cmd.Command(['v.edit', + gcmd.Command(['v.edit', '--q', 'map=%s' % self.map, 'tool=catadd', @@ -375,7 +397,7 @@ def EditLine(self, line, coords): """Edit existing line""" # remove line - vEditDelete = cmd.Command(['v.edit', + vEditDelete = gcmd.Command(['v.edit', '--q', 'map=%s' % self.map, 'tool=delete', @@ -388,6 +410,110 @@ # reload map (needed for v.edit) self.driver.ReloadMap() + def __ModifyLines(self, tool): + """General method to modify selected lines""" + + ids = self.driver.GetSelected() + + if len(ids) <= 0: + return False + + vEdit = ['v.edit', + '--q', + 'map=%s' % self.map, + 'tool=%s' % tool, + 'ids=%s' % ",".join(["%d" % v for v in ids])] + + if tool in ['snap', 'connect']: + vEdit.append("thresh=%f" % self.driver.GetThreshold()) + + runCmd = gcmd.Command(vEdit) + + # reload map (needed for v.edit) + self.driver.ReloadMap() + + return True + + def FlipLine(self): + """Flip selected lines""" + + return self.__ModifyLines('flip') + + def MergeLine(self): + """Merge selected lines""" + + return self.__ModifyLines('merge') + + def SnapLine(self): + """Snap selected lines""" + + return self.__ModifyLines('snap') + + def ConnectLine(self): + """Connect selected lines""" + + return self.__ModifyLines('connect') + + def CopyLine(self, ids=None): + """Copy features from (background) vector map""" + + if not ids: + ids = self.driver.GetSelected() + + if len(ids) <= 0: + return False + + vEdit = ['v.edit', + '--q', + 'map=%s' % self.map, + 'tool=copy', + 'ids=%s' % ",".join(["%d" % v for v in ids])] + + if self.settings['backgroundMap'] != '': + vEdit.append('bgmap=%s' % self.settings['backgroundMap']) + + runCmd = gcmd.Command(vEdit) + + # reload map (needed for v.edit) + self.driver.ReloadMap() + + return True + + def SelectLinesFromBackgroundMap(self, pos1, pos2): + """Select features from background map + + pos1, pos2: bounding box defifinition + """ + + if self.settings['backgroundMap'] == '': + Debug.msg(4, "VEdit.SelectLinesFromBackgroundMap(): []") + return [] + + print "#", pos1, pos2 + x1, y1 = pos1 + x2, y2 = pos2 + + vEditCmd = gcmd.Command(['v.edit', + '--q', + 'map=%s' % self.map, + 'tool=select', + # 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1])]) + 'polygon=%f,%f,%f,%f,%f,%f,%f,%f,%f,%f' % \ + (x1, y1, x2, y1, x2, y2, x1, y2, x1, y1)]) + + try: + output = vEditCmd.ReadStdOutput()[0][0] + print "#", output + ids = output.split(',') #first line & item in list + ids = map(int, ids) # str -> int + except: + return [] + + Debug.msg(4, "VEdit.SelectLinesFromBackgroundMap(): %s" % \ + ",".join(["%d" % v for v in ids])) + + return ids + class VDigit(AbstractDigit): """ Prototype of digitization class based on v.digit reimplementation @@ -803,7 +929,7 @@ text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Snapping threshold")) self.snappingValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(50, -1), initial=self.parent.digit.settings["snapping"][0], - min=1, max=1e6) + min=0, max=1e6) self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue) self.snappingUnit = wx.ComboBox(parent=panel, id=wx.ID_ANY, size=(125, -1), choices=["screen pixels", "map units"]) @@ -815,7 +941,9 @@ # background map text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Backgroud vector map")) self.backgroundMap = select.Select(parent=panel, id=wx.ID_ANY, size=(200,-1), - type="vector") + type="vector") + self.backgroundMap.SetValue(self.parent.digit.settings["backgroundMap"]) + self.backgroundMap.Bind(wx.EVT_TEXT, self.OnChangeBackgroundMap) flexSizer2.Add(text, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL) flexSizer2.Add(self.backgroundMap, proportion=1, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) #flexSizer.Add(self.snappingUnit, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) @@ -899,7 +1027,7 @@ """ return ( - ("Background", "symbolBackground"), + # ("Background", "symbolBackground"), ("Highlight", "symbolHighlight"), ("Point", "symbolPoint"), ("Line", "symbolLine"), @@ -961,6 +1089,12 @@ event.Skip() + def OnChangeBackgroundMap(self, event): + """Change background map""" + map = self.backgroundMap.GetValue() + + self.parent.digit.settings['backgroundMap'] = map + def OnOK(self, event): """Button 'OK' clicked""" self.UpdateSettings() @@ -1239,7 +1373,7 @@ Return True line found or False if not found""" - cmdWhat = cmd.Command(cmd=['v.what', + cmdWhat = gcmd.Command(cmd=['v.what', '--q', 'map=%s' % self.map, 'east_north=%f,%f' % \ @@ -1296,7 +1430,7 @@ 'cats=%s' % catList, 'id=%d' % self.line] - cmd.Command(vEditCmd) + gcmd.Command(vEditCmd) self.cats_orig = copy.deepcopy(self.cats) Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-09 08:32:47 UTC (rev 1127) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-09 09:44:10 UTC (rev 1128) @@ -58,7 +58,7 @@ import menuform import select import disp_print -import gcmd as cmd +import gcmd import dbm import defaultfont as defaultfont import histogram as histogram @@ -212,10 +212,12 @@ # platforms at initialization, but little harm done. self.OnSize(None) - # create a PseudoDC for map decorations like scales and legends + # create PseudoDC used for background map, map decorations like scales and legends self.pdc = wx.PseudoDC() # used for digitization tool self.pdcVector = None + # pseudoDC for temporal objects (select box, measurement tool, etc.) + self.pdcTmp = wx.PseudoDC() # will store an off screen empty bitmap for saving to file self._Buffer = '' @@ -395,6 +397,9 @@ if self.pdcVector: self.pdcVector.DrawToDCClipped(dc, rgn) + # draw temporal object on the foreground + self.pdcTmp.DrawToDCClipped(dc, rgn) + def OnSize(self, event): """ Scale map image so that it is @@ -496,10 +501,12 @@ self.resize = False # - # clear pseudodc + # clear pseudoDcs # self.pdc.Clear() self.pdc.RemoveAll() + self.pdcTmp.Clear() + self.pdcTmp.RemoveAll() # @@ -551,7 +558,7 @@ self.resize = False # - # render region border + # render region border (to self.pdcTmp) # if hasattr(self, "regionCoords"): reg = self.Map.GetWindow() @@ -564,7 +571,7 @@ self.regionCoords.append(c2p((reg['west'],reg['south']))) self.regionCoords.append(c2p((reg['west'],reg['north']))) # draw region extent - self.DrawLines(polycoords=self.regionCoords) + self.DrawLines(pdc=self.pdcTmp, polycoords=self.regionCoords) # # update statusbar @@ -638,22 +645,25 @@ self.RefreshRect(r, False) self.lastpos = (event.GetX(),event.GetY()) - def MouseDraw(self): + def MouseDraw(self, pdc=None): """ Mouse zoom rectangles and lines """ + if not pdc: + return + Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s" % \ (self.mouse['use'], self.mouse['box'])) if self.mouse['box'] == "box": boxid = wx.ID_NEW mousecoords = [self.mouse['begin'][0], self.mouse['begin'][1], \ self.mouse['end'][0], self.mouse['end'][1]] - r = self.pdc.GetIdBounds(boxid) + r = pdc.GetIdBounds(boxid) r.Inflate(4,4) - self.pdc.ClearId(boxid) + pdc.ClearId(boxid) self.RefreshRect(r, False) - self.pdc.SetId(boxid) - self.Draw(self.pdc, drawid=boxid, pdctype='box', coords=mousecoords) + pdc.SetId(boxid) + self.Draw(pdc, drawid=boxid, pdctype='box', coords=mousecoords) elif self.mouse['box'] == "line": self.lineid = wx.ID_NEW mousecoords = [self.mouse['begin'][0], self.mouse['begin'][1], \ @@ -665,19 +675,19 @@ r = wx.Rect(x1,y1,x2-x1,y2-y1) r.Inflate(4,4) try: - self.pdc.ClearId(self.lineid) + pdc.ClearId(self.lineid) except: pass self.RefreshRect(r, False) - self.pdc.SetId(self.lineid) + pdc.SetId(self.lineid) - self.Draw(self.pdc, drawid=self.lineid, pdctype='line', coords=mousecoords) + self.Draw(pdc, drawid=self.lineid, pdctype='line', coords=mousecoords) def DrawLines(self, pdc=None, polycoords=None): """Draw polylines in PseudoDC""" if not pdc: - pdc = self.pdc + return if not polycoords: polycoords = self.polycoords @@ -760,7 +770,7 @@ # dragging anything else - rubber band box or line else: self.mouse['end'] = event.GetPositionTuple()[:] - self.MouseDraw() + self.MouseDraw(pdc=self.pdcTmp) # double click elif event.ButtonDClick(): @@ -799,7 +809,7 @@ self.mouse['end'] = self.mouse['begin'] self.polycoords.append(self.mouse['begin']) - self.ClearLines() + self.ClearLines(pdc=self.pdcTmp) else: self.mouse['begin'] = self.mouse['end'] @@ -853,7 +863,7 @@ for sql in addRecordDlg.GetSQLString(): sqlfile.file.write(sql + ";\n") sqlfile.file.flush() - executeCommand = cmd.Command(cmd=["db.execute", + executeCommand = gcmd.Command(cmd=["db.execute", "--q", "input=%s" % sqlfile.name]) @@ -861,7 +871,7 @@ # add new point to the line self.polycoords.append(event.GetPositionTuple()[:]) self.mouse['begin'] = self.polycoords[-1] - self.DrawLines() + self.DrawLines(pdc=self.pdcTmp) elif digitToolbar.action == "editLine" and hasattr(self, "moveIds"): coords=self.polycoords[-2:] @@ -872,7 +882,7 @@ idNode = wx.NewId() self.pdcVector.SetIdBounds(idNode, (coords[1][0], coords[1][1], coords[1][0], coords[1][1])) - self.moveIds.insert(-1, idNode) + self.moveIds.append(idNode) elif digitToolbar.action == "deleteLine": pass @@ -912,7 +922,7 @@ for sql in sqlCommands: sqlfile.file.write(sql + ";\n") sqlfile.file.flush() - executeCommand = cmd.Command(cmd=["db.execute", + executeCommand = gcmd.Command(cmd=["db.execute", "--q", "input=%s" % sqlfile.name]) else: # displayCategories @@ -941,6 +951,8 @@ else: self.copyCatsIds = [] self.mouse['box'] = 'box' + elif digitToolbar.action == "copyLine": + self.copyIds = None else: # get decoration id self.lastpos = self.mouse['begin'] @@ -980,7 +992,7 @@ try: self.polycoords.append(self.mouse['end']) self.pdc.ClearId(self.lineid) - self.DrawLines() + self.DrawLines(pdc=self.pdcTmp) except: pass @@ -993,12 +1005,14 @@ pos2 = self.Pixel2Cell(self.mouse['end']) if digitToolbar.action in ["deleteLine", "moveLine", "moveVertex", - "copyCats", "editLine"]: + "copyCats", "editLine", "flipLine", + "mergeLine", "snapLine", "connectLine"]: nselected = 0 # -> delete line || move line || move vertex if digitToolbar.action in ["moveVertex", "editLine"]: if len(driver.GetSelected()) == 0: # -> move vertex (select by point) + # return vertex coordinates (tuple) nselected = driver.SelectLineByPoint(pos1, type="line") elif digitToolbar.action == "copyCats": @@ -1008,7 +1022,7 @@ if nselected: qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / \ self.Map.width) - vWhat = cmd.Command(['v.what', + vWhat = gcmd.Command(['v.what', '--q', 'map=%s' % self.parent.digit.map, 'east_north=%f,%f' % \ @@ -1022,12 +1036,13 @@ else: # collect ids driver.Unselect() + # return number of selected features nselected = driver.SelectLinesByBox(pos1, pos2) if nselected > 0: self.copyCatsIds = driver.GetSelected() else: - # -> moveLine || deleteLine (select by box) + # -> moveLine || deleteLine, etc. (select by box) nselected = driver.SelectLinesByBox(pos1, pos2) if nselected > 0: @@ -1049,10 +1064,15 @@ elif digitToolbar.action == "editLine": # -> edit line + # get id of selected vertex (last or first node) + selVertex = driver.GetSelectedVertex(pos1)[0] ids = driver.GetSelected(grassId=False) for id in ids: if id % 2: # vertex - self.moveIds.append(id) + self.moveIds.append(id) + if selVertex < ids[-1] / 2: + # choose first or last node of line + self.moveIds.reverse() else: self.UpdateMap(render=False, renderVector=False) @@ -1071,7 +1091,19 @@ self.pdcVector.RemoveId(id) self.DrawCross(pdc=self.pdcVector, coords=(x, y), size=5) + elif digitToolbar.action == "copyLine": + if self.parent.digit.settings['backgroundMap'] == '': + # no background map -> copy from current vector map layer + nselected = driver.SelectLinesByBox(pos1, pos2) + if nselected > 0: + # highlight selected features + self.UpdateMap(render=False) + else: + # copy features from background map + self.copyIds = self.parent.digit.SelectLinesFromBackgroundMap(pos1, pos2) + self.UpdateMap(render=False, renderVector=False) + elif self.dragid != None: # end drag of overlay decoration self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid) @@ -1091,7 +1123,7 @@ if self.mouse["use"] == "measure": # measure - self.ClearLines() + self.ClearLines(pdc=self.pdcTmp) self.polycoords = [] self.mouse['use'] = 'pointer' self.mouse['box'] = 'point' @@ -1207,7 +1239,7 @@ for sql in addRecordDlg.GetSQLString(): sqlfile.file.write(sql + ";\n") sqlfile.file.flush() - executeCommand = cmd.Command(cmd=["db.execute", + executeCommand = gcmd.Command(cmd=["db.execute", "--q", "input=%s" % sqlfile.name]) # clean up saved positions @@ -1263,13 +1295,24 @@ elif digit.action == "editLine" and hasattr(self, "moveBegin"): line = self.parent.digit.driver.GetSelected() coords = [] - for id in self.moveIds[0:-1]: + for id in self.moveIds: # avoid last point x, y = self.pdcVector.GetIdBounds(id)[0:2] coords.append(self.Pixel2Cell((x, y))) self.parent.digit.EditLine(line, coords) del self.moveBegin del self.moveCoords del self.moveIds + elif digit.action == "flipLine": + self.parent.digit.FlipLine() + elif digit.action == "mergeLine": + self.parent.digit.MergeLine() + elif digit.action == "snapLine": + self.parent.digit.SnapLine() + elif digit.action == "connectLine": + self.parent.digit.ConnectLine() + elif digit.action == "copyLine": + self.parent.digit.CopyLine(self.copyIds) + del self.copyIds if digit.action != "addLine": self.parent.digit.driver.Unselect() @@ -1296,16 +1339,20 @@ if digit.action == "editLine" and len(self.moveIds) > 0: # remove last vertex & line - self.pdcVector.RemoveId(self.moveIds[-1]) + self.pdcVector.RemoveId(self.moveIds[-1]) # remove last vertex + if self.moveIds[-1] > self.moveIds[-2]: + self.pdcVector.RemoveId(self.moveIds[-1] - 1) # remove last segment + else: + self.pdcVector.RemoveId(self.moveIds[-1] + 1) # remove last segment self.moveIds.pop() - self.pdcVector.RemoveId(self.moveIds[-1] -1) - self.ClearLines() + self.ClearLines(pdc=self.pdcTmp) self.UpdateMap(render=False, renderVector=False) - self.DrawLines() + self.DrawLines(pdc=self.pdcTmp) elif digit.action in ["deleteLine", "moveLine", "splitLine", "addVertex", "removeVertex", "moveVertex", - "copyCats"]: + "copyCats", "flipLine", "mergeLine", + "snapLine", "connectLine", "copyLine"]: # varios tools -> unselected selected features self.parent.digit.driver.Unselect() if digit.action in ["moveLine", "moveVertex", "editLine"] and \ @@ -1320,6 +1367,9 @@ del self.copyCatsIds except: pass + elif digit.action == "copyLine": + del self.copyIds + self.UpdateMap(render=False) # render map def OnMouseMoving(self, event): @@ -1333,7 +1383,7 @@ digit.type in ["line", "boundary"]: if len(self.polycoords) > 0: # draw mouse moving - self.MouseDraw() + self.MouseDraw(self.pdcTmp) elif digit.action in ["moveLine", "moveVertex", "editLine"] \ and hasattr(self, "moveBegin"): dx = self.mouse['end'][0] - self.mouse['begin'][0] @@ -1367,19 +1417,19 @@ self.polycoords.append((x, y)) else: # edit line # self.pdcVector.TranslateId(self.moveIds[-1], dx, dy) - self.pdcVector.RemoveId(self.moveIds[-1]) # last vertex - self.pdcVector.RemoveId(self.moveIds[-1] - 1) # line + # self.pdcVector.RemoveId(self.moveIds[-1]) # last vertex + # self.pdcVector.RemoveId(self.moveIds[-1] - 1) # line try: - if self.moveIds[-2] > 0: # previous vertex - x, y = self.pdcVector.GetIdBounds(self.moveIds[-2])[0:2] + if self.moveIds[-1] > 0: # previous vertex + x, y = self.pdcVector.GetIdBounds(self.moveIds[-1])[0:2] self.polycoords.append((x, y)) self.polycoords.append(self.mouse['end']) except: # no line self.pdcVector.RemoveId(self.moveIds[-1]) self.moveIds = [] - self.ClearLines() - self.DrawLines() + self.ClearLines(pdc=self.pdcTmp) + self.DrawLines(pdc=self.pdcTmp) self.Refresh() # TODO: use RefreshRect() self.mouse['begin'] = self.mouse['end'] @@ -1392,7 +1442,7 @@ """ if not pdc: - pdc = self.pdc + return exit = True @@ -1587,7 +1637,7 @@ return # get map extents using g.region and update display - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.returncode == 0: output = p.module_stdout.read().split('\n') @@ -1633,7 +1683,7 @@ "rows=%f" % new['rows'], "cols=%f" % new['cols']] - p = cmd.Command(cmdRegion) + p = gcmd.Command(cmdRegion) if tmpreg: os.environ["GRASS_REGION"] = tmpreg @@ -1657,7 +1707,7 @@ wind = dlg.wind - p = cmd.Command (["g.region", "-ugp", "region=%s" % wind]) + p = gcmd.Command (["g.region", "-ugp", "region=%s" % wind]) if p.returncode == 0: output = p.module_stdout.read().split('\n') @@ -1723,7 +1773,7 @@ tmpreg = os.getenv("GRASS_REGION") os.unsetenv("GRASS_REGION") - p = cmd.Command(cmdRegion) + p = gcmd.Command(cmdRegion) if tmpreg: os.environ["GRASS_REGION"] = tmpreg @@ -1817,7 +1867,7 @@ # Add statusbar # self.statusbar = self.CreateStatusBar(number=3, style=0) - self.statusbar.SetStatusWidths([-2, -5, -1]) + self.statusbar.SetStatusWidths([-5, -2, -1]) self.toggleStatus = wx.Choice(self.statusbar, wx.ID_ANY, choices = ["Coordinates", "Extent", @@ -1848,7 +1898,7 @@ # "%s,%s" % (None, None)] # for i in range(len(map_frame_statusbar_fields)): # self.statusbar.SetStatusText(map_frame_statusbar_fields[i], i) - self.statusbar.SetStatusText("None,None", 1) + self.statusbar.SetStatusText("None,None", 0) self.StatusbarReposition() # reposition checkbox # @@ -2012,7 +2062,7 @@ # update statusbar if required e, n = self.MapWindow.Pixel2Cell(event.GetPositionTuple()) if self.statusText == "Coordinates": - self.statusbar.SetStatusText("%.2f,%.2f" % (e, n), 1) + self.statusbar.SetStatusText("%.2f,%.2f" % (e, n), 0) event.Skip() @@ -2100,7 +2150,7 @@ self.Map.getRegion() self.Map.getResolution() self.UpdateMap() -# event.Skip() + # event.Skip() def OnAlignRegion(self, event): """ @@ -2110,7 +2160,7 @@ self.Map.alignRegion = True else: self.Map.alignRegion = False -# event.Skip() + # event.Skip() def OnToggleRender(self, event): """Enable/disable auto-rendering""" @@ -2135,17 +2185,17 @@ self.statusText = event.GetString() if self.statusText == "Coordinates": - self.statusbar.SetStatusText("None,None", 1) + self.statusbar.SetStatusText("None,None", 0) self.showRegion.Hide() elif self.statusText == "Extent": self.statusbar.SetStatusText("%.2f-%.2f,%.2f-%.2f" % (self.Map.region["w"], self.Map.region["e"], - self.Map.region["n"], self.Map.region["s"]), 1) + self.Map.region["n"], self.Map.region["s"]), 0) self.showRegion.Show() elif self.statusText == "Geometry": self.statusbar.SetStatusText("rows=%d;cols=%d;nsres=%.2f;ewres=%.2f" % (self.Map.region["rows"], self.Map.region["cols"], - self.Map.region["nsres"], self.Map.region["ewres"]), 1) + self.Map.region["nsres"], self.Map.region["ewres"]), 0) self.showRegion.Hide() else: self.statusbar.SetStatusText("", 1) @@ -2153,12 +2203,12 @@ def StatusbarReposition(self): """Reposition checkbox in statusbar""" # reposition checkbox - widgets = {0: self.toggleStatus, - 1: self.showRegion, + widgets = {0: self.showRegion, + 1: self.toggleStatus, 2: self.autoRender} for idx, win in widgets.iteritems(): rect = self.statusbar.GetFieldRect(idx) - if idx == 1: # show region + if idx == 0: # show region wWin, hWin = win.GetBestSize() x, y = rect.x + rect.width - wWin, rect.y-1 w, h = wWin, rect.height+2 @@ -2210,15 +2260,15 @@ point = wx.GetMousePosition() printmenu = wx.Menu() # Add items to the menu - setup = wx.MenuItem(printmenu, -1,'Page setup') + setup = wx.MenuItem(printmenu, wx.ID_ANY,'Page setup') printmenu.AppendItem(setup) self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup) - preview = wx.MenuItem(printmenu, -1,'Print preview') + preview = wx.MenuItem(printmenu, wx.ID_ANY,'Print preview') printmenu.AppendItem(preview) self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview) - doprint = wx.MenuItem(printmenu, -1,'Print display') + doprint = wx.MenuItem(printmenu, wx.ID_ANY,'Print display') printmenu.AppendItem(doprint) self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint) @@ -2330,17 +2380,17 @@ point = wx.GetMousePosition() toolsmenu = wx.Menu() # Add items to the menu - measure = wx.MenuItem(toolsmenu, -1, Icons["measure"].GetLabel()) + measure = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["measure"].GetLabel()) measure.SetBitmap(Icons["measure"].GetBitmap(self.iconsize)) toolsmenu.AppendItem(measure) self.Bind(wx.EVT_MENU, self.OnMeasure, measure) - profile = wx.MenuItem(toolsmenu, -1, Icons["profile"].GetLabel()) + profile = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["profile"].GetLabel()) profile.SetBitmap(Icons["profile"].GetBitmap(self.iconsize)) toolsmenu.AppendItem(profile) self.Bind(wx.EVT_MENU, self.Profile, profile) - histogram = wx.MenuItem(toolsmenu, -1, Icons["histogram"].GetLabel()) + histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["histogram"].GetLabel()) histogram.SetBitmap(Icons["histogram"].GetBitmap(self.iconsize)) toolsmenu.AppendItem(histogram) self.Bind(wx.EVT_MENU, self.Histogram, histogram) @@ -2487,17 +2537,17 @@ point = wx.GetMousePosition() decmenu = wx.Menu() # Add items to the menu - addscale = wx.MenuItem(decmenu, -1, Icons["addbarscale"].GetLabel()) + addscale = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addbarscale"].GetLabel()) addscale.SetBitmap(Icons["addbarscale"].GetBitmap(self.iconsize)) decmenu.AppendItem(addscale) self.Bind(wx.EVT_MENU, self.AddBarscale, addscale) - AddLegend = wx.MenuItem(decmenu, -1, Icons["addlegend"].GetLabel()) + AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addlegend"].GetLabel()) AddLegend.SetBitmap(Icons["addlegend"].GetBitmap(self.iconsize)) decmenu.AppendItem(AddLegend) self.Bind(wx.EVT_MENU, self.AddLegend, AddLegend) - addtext = wx.MenuItem(decmenu, -1, Icons["addtext"].GetLabel()) + addtext = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addtext"].GetLabel()) addtext.SetBitmap(Icons["addtext"].GetBitmap(self.iconsize)) decmenu.AppendItem(addtext) self.Bind(wx.EVT_MENU, self.AddText, addtext) @@ -2698,28 +2748,28 @@ def OnZoomMenu(self, event): """ - Decorations overlay menu + Zoom menu """ point = wx.GetMousePosition() zoommenu = wx.Menu() # Add items to the menu - zoommap = wx.MenuItem(zoommenu, -1,'Zoom to selected map') + zoommap = wx.MenuItem(zoommenu, wx.ID_ANY,'Zoom to selected map') zoommenu.AppendItem(zoommap) self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToMap, zoommap) - zoomwind = wx.MenuItem(zoommenu, -1,'Zoom to computational region (set with g.region)') + zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY,'Zoom to computational region (set with g.region)') zoommenu.AppendItem(zoomwind) self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToWind, zoomwind) - savewind = wx.MenuItem(zoommenu, -1,'Set computational region from display') + savewind = wx.MenuItem(zoommenu, wx.ID_ANY,'Set computational region from display') zoommenu.AppendItem(savewind) self.Bind(wx.EVT_MENU, self.MapWindow.DisplayToWind, savewind) - zoomsaved = wx.MenuItem(zoommenu, -1,'Zoom to saved region') + zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY,'Zoom to saved region') zoommenu.AppendItem(zoomsaved) self.Bind(wx.EVT_MENU, self.MapWindow.ZoomToSaved, zoomsaved) - savezoom = wx.MenuItem(zoommenu, -1,'Save display geometry to named region') + savezoom = wx.MenuItem(zoommenu, wx.ID_ANY,'Save display geometry to named region') zoommenu.AppendItem(savezoom) self.Bind(wx.EVT_MENU, self.MapWindow.SaveDisplayRegion, savezoom) @@ -2767,11 +2817,11 @@ sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) box = wx.BoxSizer(wx.HORIZONTAL) - label = wx.StaticText(self, -1, ("Drag %s with mouse in pointer mode\nto position. Double-click to change options" % ctrltxt)) + label = wx.StaticText(self, wx.ID_ANY, ("Drag %s with mouse in pointer mode\nto position. Double-click to change options" % ctrltxt)) box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + line = wx.StaticLine(self, wx.ID_ANY, size=(20,-1), style=wx.LI_HORIZONTAL) sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) btnsizer = wx.StdDialogButtonSizer() Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-09 08:32:47 UTC (rev 1127) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-09 09:44:10 UTC (rev 1128) @@ -280,6 +280,7 @@ self.addPoint = self.addLine = self.addBoundary = self.addCentroid = None self.moveVertex = self.addVertex = self.removeVertex = None self.splitLine = self.editLine = self.moveLine = self.deleteLine = None + self.additioanlTools = None return ((self.addPoint, "digAddPoint", Icons["digAddPoint"].GetBitmap(), wx.ITEM_RADIO, Icons["digAddPoint"].GetLabel(), Icons["digAddPoint"].GetDesc(), @@ -322,7 +323,11 @@ self.OnCopyCats), (self.displayAttr, "digDispAttr", Icons["digDispAttr"].GetBitmap(), wx.ITEM_RADIO, Icons["digDispAttr"].GetLabel(), Icons["digDispAttr"].GetDesc(), - self.OnDisplayAttr)) + self.OnDisplayAttr), + (self.additioanlTools, "digAdditionalTools", Icons["digAdditionalTools"].GetBitmap(), + wx.ITEM_NORMAL, Icons["digAdditionalTools"].GetLabel(), + Icons["digAdditionalTools"].GetDesc(), + self.OnAdditionalToolMenu)) def OnAddPoint(self, event): """Add point to the vector map Laier""" @@ -432,6 +437,66 @@ DigitSettingsDialog(parent=self.parent, title=_("Digitization settings"), style=wx.DEFAULT_DIALOG_STYLE).Show() + def OnAdditionalToolMenu(self, event): + """Menu for additional tools""" + point = wx.GetMousePosition() + toolMenu = wx.Menu() + # Add items to the menu + copy = wx.MenuItem(toolMenu, wx.ID_ANY, 'Copy features from (background) vector map') + toolMenu.AppendItem(copy) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnCopy, copy) + + flip = wx.MenuItem(toolMenu, wx.ID_ANY, 'Flip selected lines/boudaries') + toolMenu.AppendItem(flip) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnFlip, flip) + + merge = wx.MenuItem(toolMenu, wx.ID_ANY, 'Merge selected lines/boundaries') + toolMenu.AppendItem(merge) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnMerge, merge) + + snap = wx.MenuItem(toolMenu, wx.ID_ANY, 'Snap selected lines/boundaries') + toolMenu.AppendItem(snap) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnSnap, snap) + + connect = wx.MenuItem(toolMenu, wx.ID_ANY, 'Connect selected two lines/boundaries') + toolMenu.AppendItem(connect) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnConnect, connect) + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.parent.MapWindow.PopupMenu(toolMenu) + toolMenu.Destroy() + + def OnCopy(self, event): + """Copy selected features from (background) vector map""" + Debug.msg(2, "Digittoolbar.OnCopy():") + self.action="copyLine" + self.parent.MapWindow.mouse['box'] = 'box' + + def OnFlip(self, event): + """Flip selected lines/boundaries""" + Debug.msg(2, "Digittoolbar.OnFlip():") + self.action="flipLine" + self.parent.MapWindow.mouse['box'] = 'box' + + def OnMerge(self, event): + """Merge selected lines/boundaries""" + Debug.msg(2, "Digittoolbar.OnMerge():") + self.action="mergeLine" + self.parent.MapWindow.mouse['box'] = 'box' + + def OnSnap(self, event): + """Snap selected features""" + Debug.msg(2, "Digittoolbar.OnSnap():") + self.action="snapLine" + self.parent.MapWindow.mouse['box'] = 'box' + + def OnConnect(self, event): + """Connect selected lines/boundaries""" + Debug.msg(2, "Digittoolbar.OnConnect():") + self.action="connectLine" + self.parent.MapWindow.mouse['box'] = 'box' + def OnSelectMap (self, event): """ Select vector map layer for editing @@ -473,7 +538,8 @@ self.mapcontent.ChangeLayerActive(mapLayer, False) # change cursor - self.parent.MapWindow.SetCursor(self.parent.cursors["cross"]) + if self.parent.MapWindow.mouse['use'] == 'pointer': + self.parent.MapWindow.SetCursor(self.parent.cursors["cross"]) # create pseudoDC for drawing the map self.parent.MapWindow.pdcVector = wx.PseudoDC() Modified: trunk/grassaddons/gui/icons/icon.py =================================================================== --- trunk/grassaddons/gui/icons/icon.py 2007-10-09 08:32:47 UTC (rev 1127) +++ trunk/grassaddons/gui/icons/icon.py 2007-10-09 09:44:10 UTC (rev 1128) @@ -61,6 +61,7 @@ "digDispAttr" : 'display.attributes.gif', ## general "digSettings" : 'settings.gif', + "digAdditionalTools" : wx.ART_ERROR, "digExit" : 'exit.gif', # gis manager "newdisplay" : 'gui-startmon.gif', @@ -242,15 +243,15 @@ "digAddVertex": MetaIcon (img=icons_img["digAddVertex"], label="Add new vertex", desc="Left: Select; Middle: Unselect; Right: Confirm"), "digCopyCats": MetaIcon (img=icons_img["digCopyCats"], label="Copy categories", - desc="Not implemented yet"), + desc="Left: Select; Middle: Unselect; Right: Confirm"), "digDeleteLine": MetaIcon (img=icons_img["digDeleteLine"], label="Delete line", desc="Left: Select; Middle: Unselect; Right: Confirm"), "digDispAttr": MetaIcon (img=icons_img["digDispAttr"], label="Display/update attributes", - desc="Display attributes of given feature"), + desc="Left: Select"), "digDispCats": MetaIcon (img=icons_img["digDispCats"], label="Display/update categories", - desc="Not implemented yet"), + desc="Left: Select"), "digEditLine": MetaIcon (img=icons_img["digEditLine"], label="Edit line", - desc="Not implemented yet"), + desc="Left: new point; Middle: undo last point; Right: close line"), "digMoveLine": MetaIcon (img=icons_img["digMoveLine"], label="Move line", desc="Left: Select; Middle: Unselect; Right: Confirm"), "digMoveVertex": MetaIcon (img=icons_img["digMoveVertex"], label="Move vertex", @@ -262,6 +263,9 @@ "digSplitLine": MetaIcon (img=icons_img["digSplitLine"], label="Split line", desc="Left: Select; Middle: Unselect; Right: Confirm"), "digExit" : MetaIcon (img=icons_img["digExit"], label="Quit digitization tool"), + "digAdditionalTools" : MetaIcon (img=icons_img["digAdditionalTools"], label="Additional tools " \ + "(copy, flip, connect, etc.)", + desc="Left: Select; Middle: Unselect; Right: Confirm"), # analyze raster "analyze" : MetaIcon (img=icons_img["analyze"], label="Analyze map"), "measure" : MetaIcon (img=icons_img["measure"], label="Measure distance"), Modified: trunk/grassaddons/gui/icons/silk/__init__.py =================================================================== --- trunk/grassaddons/gui/icons/silk/__init__.py 2007-10-09 08:32:47 UTC (rev 1127) +++ trunk/grassaddons/gui/icons/silk/__init__.py 2007-10-09 09:44:10 UTC (rev 1128) @@ -53,6 +53,7 @@ "digDispAttr" : 'table.png', ## general "digSettings" : 'color_swatch.png', + "digAdditionalTools" : 'plugin.png', "digExit" : 'door_in.png', # gis manager "newdisplay" : 'application_add.png', Added: trunk/grassaddons/gui/icons/silk/plugin.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/icons/silk/plugin.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream From neteler at grass.itc.it Tue Oct 9 12:33:54 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Tue Oct 9 12:33:58 2007 Subject: [grass-addons] r1129 - in trunk/grassaddons: . r.sun_horizon r.sun_horizon/r.horizon r.sun_horizon/r.sun2 Message-ID: <200710091033.l99AXsA9014200@grass.itc.it> Author: neteler Date: 2007-10-09 12:33:54 +0200 (Tue, 09 Oct 2007) New Revision: 1129 Added: trunk/grassaddons/r.sun_horizon/ trunk/grassaddons/r.sun_horizon/r.horizon/ trunk/grassaddons/r.sun_horizon/r.horizon/Makefile trunk/grassaddons/r.sun_horizon/r.horizon/TODO trunk/grassaddons/r.sun_horizon/r.horizon/description.html trunk/grassaddons/r.sun_horizon/r.horizon/local_proto.h trunk/grassaddons/r.sun_horizon/r.horizon/main.c trunk/grassaddons/r.sun_horizon/r.sun2/ trunk/grassaddons/r.sun_horizon/r.sun2/Makefile trunk/grassaddons/r.sun_horizon/r.sun2/README trunk/grassaddons/r.sun_horizon/r.sun2/TODO trunk/grassaddons/r.sun_horizon/r.sun2/description.html trunk/grassaddons/r.sun_horizon/r.sun2/local_proto.h trunk/grassaddons/r.sun_horizon/r.sun2/main.c trunk/grassaddons/r.sun_horizon/r.sun2/rsunglobals.h trunk/grassaddons/r.sun_horizon/r.sun2/rsunlib.c trunk/grassaddons/r.sun_horizon/r.sun2/sunradstruct.h Log: new r.sun/r.horizon from JRC Added: trunk/grassaddons/r.sun_horizon/r.horizon/Makefile =================================================================== --- trunk/grassaddons/r.sun_horizon/r.horizon/Makefile (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.horizon/Makefile 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,11 @@ +MODULE_TOPDIR = ../.. + +PGM = r.horizon + +LIBES = $(GPROJLIB) $(GISLIB) +DEPENDENCIES = $(GPROJDEP) $(GISDEP) +EXTRA_INC = $(PROJINC) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd Added: trunk/grassaddons/r.sun_horizon/r.horizon/TODO =================================================================== --- trunk/grassaddons/r.sun_horizon/r.horizon/TODO (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.horizon/TODO 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,9 @@ +Probably the sun position calculation shouldbe replaced +with + + G_calc_solar_position() + +currently used in r.sunmask. G_calc_solar_position() is based on +solpos.c from NREL and very precise. + +MN 4/2001 Added: trunk/grassaddons/r.sun_horizon/r.horizon/description.html =================================================================== --- trunk/grassaddons/r.sun_horizon/r.horizon/description.html (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.horizon/description.html 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,179 @@ +

DESCRIPTION

+ +

r.horizon computes the angular height of terrain horizon in +radians. It reads a raster of elevation data and outputs the horizon +outline in one of two modes: + +

    +
  • single point: as a series of horizon +heights in the specified directions from the given point. The results are +written to the stdout. +
  • raster: in this case the output is +one or more rasters, with each point in a raster giving the horizon +height in a specific direction. One raster is created for each direction. +
+ +

The directions are given as azimuthal angles (in degrees), with +the angle starting with 0 towards East and moving counterclockwise +(North is 90, etc.). The calculation takes into account the actual +projection, so the angles are corrected for direction distortions +imposed by it. The directions are thus aligned to those of the +geographic projection and not the coordinate system given by the rows +and columns of the raster file. This correction implies that the +resulting cardinal directions represent true orientation towards the +East, North, West and South. The only exception of this feature is +LOCATION with x,y coordinate system, where this correction is +not applied. + + +

+ +

Flags:

+
+
-d +
Output horizon height in degrees (the default is radians)
+ + +

Input parameters:

+

The elevin parameter is an input elevation raster file. If +the buffer options are used (see below), this raster should extend +over the area that accommodate the presently defined region plus +defined buffer zones. +

+

The step parameter gives the angle step (in degrees) +between successive azimuthal directions for the calculation of the +horizon. Thus, a value of 5 for the step will give a total of +360/5=72 directions (72 rasters if used in the raster mode). +

+

The direction parameter gives the initial direction of the +first output. This parameter acts as an direction angle offset. For +example, if you want to get horizon angles for directions 45 and 225 +degrees, the direction should be set to 45 and step to +180. If you only want one single direction, use this parameter to +specify desired direction of horizon angle, and set the step +size to 0 degrees. +

+

The dist controls the sampling distance step size for the +search for horizon along the line of sight. The default value is 1.0 +meaning that the step size will be taken from the raster resolution. +Setting the value below 1.0 might slightly improve results for +directions apart from the cardinal ones, but increasing the +processing load of the search algorithm. +

+

The maxdistance value gives a maximum distance to move away +from the origin along the line of sight in order to search for the +horizon height. The smaller this value the faster the calculation but +the higher the risk that you may miss a terrain feature that can +contribute significantly to the horizon outline.

+

The coord parameter takes a pair of easting-northing values +and calculates the values of angular height of the horizon around this point. To +achieve the consistency of the results, the point coordinate is +aligned to the midpoint of the closest elevation raster cell. +

+

If an analyzed point (or raster cell) lies close to the edge of +the defined region, the horizon calculation may not be realistic, +since it may not see some significant terrain features which could +have contributed to the horizon, because these features are outside +the region. There are to options how to set the size of the buffer +that is used to increase the area of the horizon analysis. The +bufferzone parameter allows you to specify the same size of +buffer for all cardinal directions and the parameters e_buff, +n_buff, s_buff, and w_buff allow you to specify +a buffer size individually for each of the four directions. The +buffer parameters influence only size of the read elevation file, +while the analysis in the raster mode will be done only for the +area specified by the current region definition.

+

The horizon parameter gives the prefix of the output +horizon raster files. The raster name of each horizon direction +raster will be constructed as horizon_NNN , where NNN counts +upwards from 0 to total number of directions. If you use r.horizon +in the single point mode this option will be ignored. +

+ +

+At the moment the elevation and maximum distance must be measured in meters, +even if you use geographical coordinates (longitude/latitude). If your +projection is based on distance (easting and northing), these too must +be in meters. The buffer parameters must be in the same units as the +raster coordinates. +

+ +

METHOD

+

The calculation method is based on the method used in r.sun +to calculate shadows. It starts at a very shallow angle and walks +along the line of sight and asks at each step whether the line of +sight "hits" the terrain. If so, the angle is increased to +allow the line of sight to pass just above the terrain at that point. +This is continued until the line of sight reaches a height that is +higher than any point in the region or until it reaches the border of +the region (see also the bufferzone,e_buff, n_buff, +s_buff, and w_buff). The the number of lines of sight (azimuth +directions) is determined from the direction and +step parameters. The method takes into account the curvature +of the Earth whereby remote features will seem to be lower than they +actually are. It also accounts for the changes of angles towards +cardinal directions caused by the projection (see above). +

+ +

EXAMPLE

+ +
+r.horizon elevin=DEM step=30 direction=15 bufferzone=200 coord=47.302,7.365 dist=0.7 > horizon.out
+
+ + +

raster mode:

+ +
+r.horizon elevin=DEM step=30 e_buff=20 horizon=horangle dist=0.7 maxdistance=2000
+
+ + +

SEE ALSO

+ +r.sun, +r.los + +

REFERENCES

+

Hofierka J., 1997. Direct solar radiation modelling within an +open GIS environment. Proceedings of JEC-GI'97 conference in Vienna, +Austria, IOS Press Amsterdam, 575-584 +

+

Hofierka J., Huld T., Cebecauer T., Suri M., 2007. Open Source Solar +Radiation Tools for Environmental and Renewable Energy Applications, +International Symposium on +Environmental Software Systems, Prague, 2007

+

Neteler M., Mitasova H., 2004. Open Source GIS: A GRASS GIS +Approach, Kluwer +Academic Publishers/Springer, Boston. ISBN: 1-4020-8064-6, 2nd +Edition 2004 (reprinted 2005), 424 pages +

+

Project PVGIS, European +Commission, DG Joint Research Centre 2001-2007

+

Suri M., Hofierka J., 2004. +A New GIS-based Solar Radiation Model and Its Application for +Photovoltaic Assessments. Transactions +in GIS, 8(2), 175-190

+ +

AUTHORS

+Thomas Huld, Joint Research Centre of +the European Commission, Ispra, Italy +
+Tomas Cebecauer, Joint Research Centre +of the European Commission, Ispra, Italy +
+Jaroslav Hofierka, GeoModel s.r.o., +Bratislava, Slovakia
Marcel Suri, Joint Research Centre of the +European Commission, Ispra, Italy

+© 2007, Thomas Huld, Tomas Cebecauer, Jaroslav Hofierka, Marcel Suri +

+ + +
Thomas.Huld@jrc.it +Tomas.Cebecauer@jrc.it +hofierka@geomodel.sk +Marcel.Suri@jrc.it +
+ +

Last changed: $Date: 2007/05/16 16:22:04 $ +

Added: trunk/grassaddons/r.sun_horizon/r.horizon/local_proto.h =================================================================== --- trunk/grassaddons/r.sun_horizon/r.horizon/local_proto.h (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.horizon/local_proto.h 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,23 @@ +/* sun11.c */ +int INPUT(void); +int OUTGR(void); +double amax1(double, double); +double amin1(double, double); +int min(int, int); +int max(int, int); +void com_par(void); +double lumcline2(void); +double joules2(void); +int quadrant(void); +double coef_of_line(void); +void new_point_x(int, double *, double *, double *); +void new_point_y(int, double *, double *, double *); +void which_one(double, double, double, double, double, double); +int combine_x(int, int, int, int); +int combine_y(int, int, int, int); +int vertex(int, int); +int mesh_vertex(void); +int mesh_line(void); +void calculate(void); +double com_sol_const(void); +double com_declin(int); Added: trunk/grassaddons/r.sun_horizon/r.horizon/main.c =================================================================== --- trunk/grassaddons/r.sun_horizon/r.horizon/main.c (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.horizon/main.c 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,1274 @@ +/******************************************************************************* +r.horizon: This module does one of two things: + +1) Using a map of the terrain elevation it calculates for a set of points +the angle height of the horizon for each point, using an angle interval given +by the user. + +2) For a given minimum angle it calculates one or more raster map giving the mazimum +distance to a point on the horizon. + +This program was written in 2006 by Tfomas Huld and Tomas Cebecauer, +Joint Research Centre of the European Commission, based on bits of the r.sun module by Jaro Hofierka + + +*******************************************************************************/ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define WHOLE_RASTER 1 +#define SINGLE_POINT 0 +#define RAD (180. / M_PI) +#define DEG ((M_PI)/180.) +#define EARTHRADIUS 6371000. +#define UNDEF 0. /* undefined value for terrain aspect*/ +#define UNDEFZ -9999. /* undefined value for elevation */ +#define BIG 1.e20 +#define SMALL 1.e-20 +#define EPS 1.e-4 +#define DIST "1.0" +#define DEGREEINMETERS 111120. +#define TANMINANGLE 0.008727 /* tan of minimum horizon angle (0.5 deg) */ + +#define AMAX1(arg1, arg2) ((arg1) >= (arg2) ? (arg1) : (arg2)) +#define DISTANCE1(x1, x2, y1, y2) (sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2))) + + +FILE *fw; + +const double rad2deg = 180./M_PI; +const double deg2rad = M_PI/180.; +const double pihalf=M_PI*0.5; +const double twopi=2.*M_PI; +const double invEarth=1./EARTHRADIUS; + +const double minAngle=DEG; + +char *elevin; +char *latin = NULL; +char *horizon = NULL; +char *mapset = NULL; +char *per; +char shad_filename[256]; + +struct Cell_head cellhd; +struct Key_value *in_proj_info, *in_unit_info; +struct pj_info iproj; +struct pj_info oproj; + +struct Cell_head new_cellhd; +double bufferZone=0., ebufferZone=0., wbufferZone=0., nbufferZone=0., sbufferZone=0.; + +int INPUT(void); +int OUTGR(int numrows, int numcols); +double amax1(double, double); +double amin1(double, double); +int min(int, int); +int max(int, int); +void com_par(double angle); +int is_shadow(void); +double horizon_height(void); +void calculate_shadow(); +double calculate_shadow_onedirection(double shadow_angle); + +int new_point(); +double searching(); +int test_low_res(); +/*void where_is_point(); +void cube(int, int); +*/ + +void calculate(double xcoord, double ycoord, int buffer_e, int buffer_w, int buffer_s, int buffer_n); + + +int ip, jp, ip100, jp100; +int n, m, m100, n100; +int degreeOutput=0; +float **z, **z100, **horizon_raster; +double stepx, stepy, stepxhalf, stepyhalf, stepxy, xp, yp, op, dp, xg0, xx0, yg0, yy0,deltx,delty; +double invstepx, invstepy, distxy; +double offsetx, offsety; +double single_direction; + +/*int arrayNumInt;*/ +double xmin, xmax, ymin, ymax,zmax=0.; +int d, day, tien=0; + +double length, maxlength=BIG, zmult=1.0, step=0.0,dist; +double fixedMaxLength=BIG; +char *tt,*lt; +double z_orig,zp; +double h0, tanh0, angle; +double stepsinangle, stepcosangle, sinangle, cosangle, distsinangle, distcosangle; +double TOLER; + +int mode; +int isMode() + { + return mode; + } +void setMode(int val) + { + mode = val; + } + +int ll_correction=0; +double coslatsq; + +double distance(double x1, double x2, double y1, double y2) + { + if(ll_correction) + { + return DEGREEINMETERS*sqrt(coslatsq*(x1-x2)*(x1-x2) + +(y1-y2)*(y1-y2)); + } + else + { + return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)); + } + } + + + +int main(int argc, char *argv[]) +{ + double xcoord, ycoord; + + + struct GModule *module; + struct + { + struct Option *elevin,*dist,*coord,*direction,*horizon,*step,*bufferzone,*e_buff,*w_buff,*n_buff,*s_buff, *maxdistance; + } parm; + + struct + { + struct Flag *degreeOutput; + } + flag; + + G_gisinit (argv[0]); + module = G_define_module(); + + module->keywords = _("raster"); + module->label = _("Horizon angle computation from a digital elevation model."); + module->description = + _("Computes horizon angle height from a digital elevation model. The module has two" + " different modes of operation: " + "1. Computes the entire horizon around a single point whose coordinates are" + " given on withe the 'coord' option. The horizon height (in radians). " + "2. Computes one or more raster maps of the horizon height in a single direction. " + " The input for this is the angle (in degrees), which is measured " + " counterclockwise with east=0, north=90 etc. The output is the horizon height in radians."); + + if(G_get_set_window(&cellhd)==-1) G_fatal_error("G_get_set_window() failed"); + stepx = cellhd.ew_res; + stepy = cellhd.ns_res; + stepxhalf = stepx/2.; + stepyhalf = stepy/2.; + invstepx = 1./stepx; + invstepy = 1./stepy; + /* + offsetx = 2. * invstepx; + offsety = 2. * invstepy; + offsetx = 0.5*stepx; + offsety = 0.5*stepy; + */ + offsetx = 0.5; + offsety = 0.5; + + n/*n_cols*/ = cellhd.cols; + m/*n_rows*/ = cellhd.rows; + + n100=ceil(n/100.); + m100=ceil(m/100.); + + xmin = cellhd.west; + ymin = cellhd.south; + xmax = cellhd.east; + ymax = cellhd.north; + deltx = fabs(cellhd.east - cellhd.west); + delty = fabs(cellhd.north - cellhd.south); + + parm.elevin = G_define_option(); + parm.elevin->key = "elevin"; + parm.elevin->type = TYPE_STRING; + parm.elevin->required = YES; + parm.elevin->gisprompt = "old,cell,raster"; + parm.elevin->description = _("Name of the input elevation raster map [meters]"); + parm.elevin->guisection = _("Input_options"); + + + parm.direction = G_define_option(); + parm.direction->key = "direction"; + parm.direction->type = TYPE_DOUBLE; + parm.direction->required = NO; + parm.direction->description = _("Direction in which you want to know the horizon height"); + parm.direction->guisection = _("Input_options"); + + parm.step = G_define_option(); + parm.step->key = "step"; + parm.step->type = TYPE_DOUBLE; + parm.step->required = NO; + parm.step->description = _("For multidirectional horizon: the step size in degrees"); + parm.step->guisection = _("Input_options"); + + parm.bufferzone = G_define_option(); + parm.bufferzone->key = "bufferzone"; + parm.bufferzone->type = TYPE_DOUBLE; + parm.bufferzone->required = NO; + parm.bufferzone->description = _("For horizon rasters, read from the DEM an extra buffer around the present region"); + parm.bufferzone->guisection = _("Input_options"); + + parm.e_buff = G_define_option(); + parm.e_buff->key = "e_buff"; + parm.e_buff->type = TYPE_DOUBLE; + parm.e_buff->required = NO; + parm.e_buff->description = _("For horizon rasters, read from the DEM an extra buffer eastward the present region"); + parm.e_buff->guisection = _("Input_options"); + + parm.w_buff = G_define_option(); + parm.w_buff->key = "w_buff"; + parm.w_buff->type = TYPE_DOUBLE; + parm.w_buff->required = NO; + parm.w_buff->description = _("For horizon rasters, read from the DEM an extra buffer westward the present region"); + parm.w_buff->guisection = _("Input_options"); + + parm.n_buff = G_define_option(); + parm.n_buff->key = "n_buff"; + parm.n_buff->type = TYPE_DOUBLE; + parm.n_buff->required = NO; + parm.n_buff->description = _("For horizon rasters, read from the DEM an extra buffer northward the present region"); + parm.n_buff->guisection = _("Input_options"); + + parm.s_buff = G_define_option(); + parm.s_buff->key = "s_buff"; + parm.s_buff->type = TYPE_DOUBLE; + parm.s_buff->required = NO; + parm.s_buff->description = _("For horizon rasters, read from the DEM an extra buffer southward the present region"); + parm.s_buff->guisection = _("Input_options"); + + parm.maxdistance = G_define_option(); + parm.maxdistance->key = "maxdistance"; + parm.maxdistance->type = TYPE_DOUBLE; + parm.maxdistance->required = NO; + parm.maxdistance->description = _("The maximum distance to consider when finding the horizon height"); + parm.maxdistance->guisection = _("Input_options"); + + + parm.horizon = G_define_option(); + parm.horizon->key = "horizon"; + parm.horizon->type = TYPE_STRING; + parm.horizon->required = NO; + parm.horizon->gisprompt = "old,cell,raster"; + parm.horizon->description = _("Name of the horizon raster output"); + parm.horizon->guisection = _("Output_options"); + + + parm.coord = G_define_option(); + parm.coord->key = "coord"; + parm.coord->type = TYPE_STRING; + parm.coord->required = NO; + parm.coord->description = _("Coordinate for which you want to calculate the horizon"); + parm.coord->guisection = _("Output_options"); + + parm.dist = G_define_option(); + parm.dist->key = "dist"; + parm.dist->type = TYPE_DOUBLE; + parm.dist->answer = DIST; + parm.dist->required = NO; + parm.dist->description = _("Sampling distance step coefficient (0.5-1.5)"); + parm.dist->guisection = _("Output_options"); + + + flag.degreeOutput = G_define_flag(); + flag.degreeOutput->key = 'd'; + flag.degreeOutput->description = + _("Write output in degrees (default is radians)"); + + + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); + + degreeOutput = flag.degreeOutput->answer; + + + elevin = parm.elevin->answer; + + if(parm.coord->answer==NULL) + { + setMode(WHOLE_RASTER); + } + else + { + setMode(SINGLE_POINT); + if(sscanf(parm.coord->answer,"%lf,%lf", &xcoord, &ycoord)!=2) + { + G_fatal_error + ("Can't read the coordinates from the \"coord\" option."); + + } + + /* Transform the coordinates to row/column */ + +/* + xcoord = (int) ((xcoord-xmin)/stepx); + ycoord = (int) ((ycoord-ymin)/stepy); +*/ + } + + if(parm.direction->answer!=NULL) sscanf(parm.direction->answer, "%lf", &single_direction); + + + if(isMode(WHOLE_RASTER)) + { + if((parm.direction->answer==NULL) && (parm.step->answer==NULL)) + { + G_fatal_error + (_("You didn't specify a direction value or step size. Aborting.")); + } + + + if(parm.horizon->answer==NULL) + { + G_fatal_error + (_("You didn't specify a horizon raster name. Aborting.")); + + } + horizon = parm.horizon->answer; + if(parm.step->answer!=NULL) sscanf(parm.step->answer, "%lf", &step); + } + else + { + + if(parm.step->answer==NULL) + { + G_fatal_error + (_("You didn't specify an angle step size. Aborting.")); + + } + sscanf(parm.step->answer, "%lf", &step); + + + } + + if(step==0.0) + { + step=360.; + } + + if(parm.bufferzone->answer!=NULL) + { + if(sscanf(parm.bufferzone->answer, "%lf", &bufferZone)!=1) + { + G_fatal_error + (_("Could not read bufferzone size. Aborting.")); + } + } + + if(parm.e_buff->answer!=NULL) + { + if(sscanf(parm.e_buff->answer, "%lf", &ebufferZone)!=1) + { + G_fatal_error + (_("Could not read east bufferzone size. Aborting.")); + } + } + + if(parm.w_buff->answer!=NULL) + { + if(sscanf(parm.w_buff->answer, "%lf", &wbufferZone)!=1) + { + G_fatal_error + (_("Could not read west bufferzone size. Aborting.")); + } + } + + if(parm.s_buff->answer!=NULL) + { + if(sscanf(parm.s_buff->answer, "%lf", &sbufferZone)!=1) + { + G_fatal_error + (_("Could not read south bufferzone size. Aborting.")); + } + } + + + + if(parm.n_buff->answer!=NULL) + { + if(sscanf(parm.n_buff->answer, "%lf", &nbufferZone)!=1) + { + G_fatal_error + (_("Could not read north bufferzone size. Aborting.")); + } + } + + if(parm.maxdistance->answer!=NULL) + { + if(sscanf(parm.maxdistance->answer, "%lf", &fixedMaxLength)!=1) + { + G_fatal_error + (_("Could not read maximum distance. Aborting.")); + } + } + + + sscanf(parm.dist->answer, "%lf", &dist); + + stepxy = dist * 0.5 * (stepx + stepy); + distxy = dist; + TOLER = stepxy * EPS; + + if(bufferZone>0. || ebufferZone>0. || wbufferZone>0. || sbufferZone>0. || nbufferZone>0.) + { + new_cellhd=cellhd; + + if (ebufferZone==0.) ebufferZone=bufferZone; + if (wbufferZone==0.) wbufferZone=bufferZone; + if (sbufferZone==0.) sbufferZone=bufferZone; + if (nbufferZone==0.) nbufferZone=bufferZone; + + new_cellhd.rows+=(int) ((nbufferZone+sbufferZone)/stepy); + new_cellhd.cols+=(int) ((ebufferZone+wbufferZone)/stepx); + + new_cellhd.north+=nbufferZone; + new_cellhd.south-=sbufferZone; + new_cellhd.east+=ebufferZone; + new_cellhd.west-=wbufferZone; + + xmin = new_cellhd.west; + ymin = new_cellhd.south; + xmax = new_cellhd.east; + ymax = new_cellhd.north; + deltx = fabs(new_cellhd.east - new_cellhd.west); + delty = fabs(new_cellhd.north - new_cellhd.south); + + n/*n_cols*/ = new_cellhd.cols; + m/*n_rows*/ = new_cellhd.rows; +/*printf("%lf %lf %lf %lf \n",ymax, ymin, xmin,xmax); +*/ + n100=ceil(n/100.); + m100=ceil(m/100.); + + if(G_set_window(&new_cellhd)==-1) exit(EXIT_FAILURE); + } + + struct Key_Value *in_proj_info, *in_unit_info; + + if ((in_proj_info = G_get_projinfo()) == NULL) + G_fatal_error + (_("Can't get projection info of current location: please set latitude via 'lat' or 'latin' option!")); + + if ((in_unit_info = G_get_projunits()) == NULL) + G_fatal_error(_("Can't get projection units of current location")); + + if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0) + G_fatal_error + (_("Can't get projection key values of current location")); + + G_free_key_value(in_proj_info); + G_free_key_value(in_unit_info); + + /* Set output projection to latlong w/ same ellipsoid */ + oproj.zone = 0; + oproj.meters = 1.; + sprintf(oproj.proj, "ll"); + if ((oproj.pj = pj_latlong_from_proj(iproj.pj)) == NULL) + G_fatal_error(_("Unable to set up lat/long projection parameters")); + + + + +/**********end of parser - ******************************/ + + + + INPUT(); + calculate(xcoord, ycoord, (int) (ebufferZone/stepx), (int) (wbufferZone/stepx), (int) (sbufferZone/stepy), (int) (nbufferZone/stepy)); + + if(bufferZone>0.) + { + /* Set the region window back to the original */ + if(G_set_window(&cellhd)==-1) exit(EXIT_FAILURE); + } + +/*sorry, I've moved OUTGR to calculate() - into the loop*/ +/* if(isMode(WHOLE_RASTER)) + { + OUTGR(cellhd.rows,cellhd.cols); + } +*/ + if(G_set_window(&cellhd)==-1) exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); +} + +/**********************end of main.c*****************/ + +int INPUT(void) + +{ + FCELL *cell1; + int fd1, row, row_rev; + int l,i,j,k; + int lmax,kmax; + + cell1=G_allocate_f_raster_buf(); + + z = (float **)malloc(sizeof(float *)*(m)); + z100 = (float **)malloc(sizeof(float *)*(m100)); + + for(l=0;lm) lmax=m; + + for (j=0; jn) kmax=n; + for (l=(i*100); l=arg2) { + res = arg1; + } + else { + res = arg2; + } + return res; +} + +double amin1(arg1,arg2) + double arg1; + double arg2; +{ + double res; + if (arg1<=arg2) { + res = arg1; + } + else { + res = arg2; + } + return res; +} + + +int min(arg1,arg2) + int arg1; + int arg2; +{ + int res; + if (arg1 <= arg2) + { + res = arg1; + } + else + { + res = arg2; + } + return res; +} + +int max(arg1,arg2) + int arg1; + int arg2; +{ + int res; + if (arg1>=arg2) { + res = arg1; + } + else { + res = arg2; + } + return res; +} + + + +/**********************************************************/ + +void com_par(double angle) +{ + sinangle=sin(angle); + if (fabs(sinangle)<0.0000001) {sinangle=0.;} + cosangle=cos(angle); + if (fabs(cosangle)<0.0000001) {cosangle=0.;} + distsinangle=32000; + distcosangle=32000; + + if (sinangle != 0.) + { distsinangle = 100./(distxy*sinangle);} + if (cosangle != 0.) + { distcosangle = 100./(distxy*cosangle);} + + stepsinangle = stepxy*sinangle; + stepcosangle = stepxy*cosangle; +} + +double horizon_height(void) +{ + double height; + + tanh0 = 0.; + length = 0; + + height = searching(); + + xx0 = xg0; yy0 = yg0; + + return height; +} + + +double calculate_shadow_onedirection(double shadow_angle) +{ + + shadow_angle = horizon_height(); + + return shadow_angle; +} + + + +void calculate_shadow() +{ + double dfr_rad; + + int i; + int printCount; + double shadow_angle; + double printangle; + double sx, sy; + double xp, yp; + double latitude, longitude; + double delt_lat, delt_lon; + double delt_east, delt_nor; + double delt_dist; + + double angle; + + printCount=360./fabs(step); + + + if(printCount<1) + printCount=1; + + + dfr_rad = step*deg2rad ; + + xp = xmin + xx0; + yp = ymin + yy0; + + angle = (single_direction*deg2rad)+pihalf; + + + maxlength=fixedMaxLength; + + for(i=0;i=360.) + printangle-=360; + + printf("%lf, %lf\n", printangle, shadow_angle); + + angle += dfr_rad; + + if(angle<0.) + angle+=twopi; + else if(angle>twopi) + angle-=twopi; + } /* end of for loop over angles */ + } +/*//////////////////////////////////////////////////////////////////////*/ + + +int new_point() +{ + int iold, jold; + int succes = 1, succes2 = 1; + double sx, sy; + double dx, dy; + + iold=ip; jold=jp; + + while (succes) + { + yy0 += stepsinangle; + xx0 += stepcosangle; + + + /* offset 0.5 cell size to get the right cell i, j */ + sx = xx0 * invstepx + offsetx; + sy = yy0 * invstepy + offsety; + ip = (int)sx; jp = (int)sy; + + /* test outside of raster*/ + if ((ip < 0) || (ip >= n) || (jp < 0) || (jp >= m)) return (3); + + if ((ip!=iold) || (jp!=jold)) + { + dx = (double)ip *stepx; + dy = (double)jp *stepy; + + length = distance(xg0, dx, yg0, dy); /* dist from orig. grid point to the current grid point */ + succes2=test_low_res(); + if (succes2 ==1) + { + zp = z[jp][ip]; + return(1); + } + } + } + return -1; +} + + +int test_low_res() +{ + int iold100, jold100; + double sx, sy; + int delx, dely, mindel; + double zp100, z2, curvature_diff; + + iold100=ip100; jold100=jp100; + ip100 = floor(ip/100.); jp100 = floor(jp/100.); + /*test the new position with low resolution*/ + if ((ip100!=iold100) || (jp100!=jold100)) + { +//printf("%d %d %d %d\n",ip,jp, iold100,jold100); +/* replace with approximate version + curvature_diff = EARTHRADIUS*(1.-cos(length/EARTHRADIUS)); +*/ + curvature_diff = 0.5*length*length*invEarth; + z2 = z_orig + curvature_diff + length * tanh0; + zp100=z100[jp100][ip100]; +//printf("%d %d %lf %lf \n",ip,jp,z2,zp100); + + if (zp100 <= z2) + /*skip to the next lowres cell*/ + { + delx=32000; + dely=32000; + if (cosangle>0.) { + sx = xx0 * invstepx + offsetx; + delx=floor(fabs((ceil(sx/100.) - (sx/100.))*distcosangle)); + } + if (cosangle<0.) { + sx = xx0 * invstepx + offsetx; + delx=floor(fabs((floor(sx/100.) - (sx/100.))*distcosangle)); + } + if (sinangle>0.) { + sy = yy0 * invstepy + offsety; + dely=floor(fabs((ceil(sy/100.) - (sy/100.))*distsinangle)); + } + else if (sinangle<0.) { + sy = yy0 * invstepy + offsety; + dely=floor(fabs((floor(jp/100.) - (sy/100.))*distsinangle)); + } + + mindel=min(delx,dely); +//printf("%d %d %d %lf %lf\n",ip, jp, mindel,xg0, yg0); + + yy0 = yy0 + (mindel*stepsinangle); + xx0 = xx0 + (mindel*stepcosangle); +//printf(" %lf %lf\n",xx0,yy0); + + return(3); + } + else + { + return(1); /*change of low res array - new cell is reaching limit for high resolution processing*/ + } + } + else + { + return(1); /*no change of low res array*/ + } +} + + +double searching() + { + double z2; + double curvature_diff; + int succes = 1; + + if(zp==UNDEFZ) + return 0; + + while(1) + { + succes = new_point(); + + if(succes!=1) + { + break; + } +/* + curvature_diff = EARTHRADIUS*(1.-cos(length/EARTHRADIUS)); +*/ + curvature_diff = 0.5*length*length*invEarth; + + z2 = z_orig + curvature_diff + length * tanh0; + + if (z2 < zp) + { + tanh0 = (zp-z_orig-curvature_diff)/length; + } + + + if( z2 >= zmax) + { + break; + } + + if( length >= maxlength) + { + break; + } + + } + + return atan(tanh0); +} + + + +/*//////////////////////////////////////////////////////////////////////*/ + +void calculate(double xcoord, double ycoord, int buffer_e, int buffer_w, int buffer_s, int buffer_n) +{ + int i, j, l, k=0; + int numDigits; + + int xindex, yindex; + double shadow_angle; + double coslat; + + double latitude,longitude; + double xp, yp; + double inputAngle; + double delt_lat, delt_lon; + double delt_east, delt_nor; + double delt_dist; + + char formatString[10]; + + + int hor_row_start=buffer_s; + int hor_row_end= m - buffer_n; + + int hor_col_start= buffer_w; + int hor_col_end= n - buffer_e; + + int hor_numrows = m - (buffer_s+buffer_n); + int hor_numcols = n - (buffer_e+buffer_w); + +/* char shad_filename[256];*/ + int arrayNumInt; + double dfr_rad; + + fprintf(stderr,"\n\n"); + + + xindex = (int) ((xcoord-xmin)/stepx); + yindex = (int) ((ycoord-ymin)/stepy); + + if ((G_projection() == PROJECTION_LL)) + { + ll_correction=1; + } + + + if(isMode()==SINGLE_POINT) + { + /* Calculate the horizon for one single point */ + +/* + xg0 = xx0 = (double)xcoord * stepx; + yg0 = yy0 = (double)ycoord * stepy; + xg0 = xx0 = xcoord -0.5*stepx -xmin; + yg0 = yy0 = ycoord -0.5*stepy-ymin; + xg0 = xx0 = xindex*stepx -0.5*stepx; + yg0 = yy0 = yindex*stepy -0.5*stepy; +*/ + xg0 = xx0 = xindex*stepx; + yg0 = yy0 = yindex*stepy; + + + if(ll_correction) + { + coslat=cos(deg2rad*(ymin + yy0)); + coslatsq = coslat*coslat; + } + + z_orig= zp = z[yindex][xindex]; + + calculate_shadow(); + + } + else + { + + + + /****************************************************************/ + /* The loop over raster points starts here! */ + /****************************************************************/ + + + if (horizon != NULL) + { + horizon_raster = (float **)malloc(sizeof(float *)*(hor_numrows)); + for( l=0; l=twopi)?inputAngle-twopi:inputAngle; + + + delt_lat = -0.0001*cos(inputAngle); /* Arbitrary small distance in latitude */ + delt_lon = 0.0001*sin(inputAngle)/cos(latitude); + + latitude = (latitude+delt_lat)*rad2deg; + longitude = (longitude+delt_lon)*rad2deg; + + if ((G_projection() != PROJECTION_LL)) + { + if (pj_do_proj(&longitude, &latitude, &oproj, &iproj) <0) + { + G_fatal_error("Error in pj_do_proj"); + } + } + + delt_east=longitude-xp; + delt_nor=latitude-yp; + + delt_dist=sqrt(delt_east*delt_east+delt_nor*delt_nor); + + sinangle=delt_nor/delt_dist; + if (fabs(sinangle)<0.0000001) {sinangle=0.;} + cosangle=delt_east/delt_dist; + if (fabs(cosangle)<0.0000001) {cosangle=0.;} + distsinangle=32000; + distcosangle=32000; + + if (sinangle != 0.) + { distsinangle = 100./(distxy*sinangle);} + if (cosangle != 0.) + { distcosangle = 100./(distxy*cosangle);} + + stepsinangle = stepxy*sinangle; + stepcosangle = stepxy*cosangle; + + + z_orig= zp = z[j][i]; + maxlength=(zmax-z_orig)/TANMINANGLE; + maxlength=(maxlength0.) + { + if(G_set_window(&new_cellhd)==-1) exit(0); + } + } + + } + +} + + + Added: trunk/grassaddons/r.sun_horizon/r.sun2/Makefile =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/Makefile (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/Makefile 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,11 @@ +MODULE_TOPDIR = ../.. + +PGM = r.sun2 + +LIBES = $(GPROJLIB) $(GISLIB) +DEPENDENCIES = $(GPROJDEP) $(GISDEP) +EXTRA_INC = $(PROJINC) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd Added: trunk/grassaddons/r.sun_horizon/r.sun2/README =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/README (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/README 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,75 @@ +Thomas Huld: + +I'm sending the r.sun sources to you here, even though the description is not +yet up to date. I think it works OK now, though I haven't tried all possible +combinations of options. For instance, I haven't ever used the incidence +angle or insolation time outputs. There's no reason why they should have +stopped working but there are always changes that break something unexpected. + +The main changes are: + +- possibility to read in horizon rasters to use with the shadow calculation. + +- Calculation of the shadowing effect should now also work in lat/lon +projection. + +- There was a bug in r.sun whereby the shadowing effect was calculated wrong +when the left-right and up-down directions in the projection are different +from east-west and north-south, as is the case in the projection we use +(Lambert Azimuthal) when moving away from the point of origin. This has been +fixed now though only checked with Lambert Azimuthal. + +- I'm not sure if this went in already in a previous version, but the +algorithm now also takes into account the curvature of the earth when +calculating shadows. + +- new output possibility: glob_rad, which is the sum of the three radiation +components + +- new input parameter: civiltime. When this parameter is given, the +single time calculation will calculate the irradiance at the *same* time for +the entire raster instead of using the local solar time. The value of +civiltime is the timezone, relative to GMT. (+1 for central Europe) + +- new input parameter numpartitions No change in the calculation +methods, but the program will read the input rasters and do the calculations +in a number of chunks, instead of reading in everything at the start. Output +is still only at the very end. This is only to save memory. It will not work +if you try to calculate shadows without the horizon information, and the +program will tell you so. + +- I reorganized the source code quite a lot. In particular, I spun off several +functions into a separate source file called rsunlib.c. I also organized many +of the global variables into struct's for an easier overview. I did +this because we work here with several derivatives of r.sun: + + * r.sunyear which calculates the optimum inclination angle for maximum +insolation + * r.pv which calculates the PV output taking into account also temperature +effects + * r.sun.2axis which is r.sun for a moving plane, whose normal always points +to the sun (two-axis tracking solar energy systems). + +Splitting the source code made it easier to reuse bits for these r.sun +derivatives. I haven't updated the Makefile to account for these changes yet. +Look at the little script "compdebug" in the source directory. + + +There may be other changes that I've forgotten about but nothing dramatic. + +Have fun! + + +Thomas + + + +-- +-------------------------------------------------- +Thomas Huld +Joint Research Centre of the European Commission +T.P. 450 +I-21020 Ispra, Italy +phone: +39 0332785273 +e-mail: Thomas.Huld@jrc.it +-------------------------------------------------- Added: trunk/grassaddons/r.sun_horizon/r.sun2/TODO =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/TODO (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/TODO 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,89 @@ +From Thomas.Huld jrc.it Thu Jul 26 11:01:44 2007 +To: Markus Neteler +CC: Jaro Hofierka , "marcel.suri jrc.it" + , Tomas Cebecauer +Date: Thu, 26 Jul 2007 11:01:44 +0200 +Subject: Re: r.horizon source code +Lines: 1533 + +I'm sending the r.sun sources to you here, even though the description is not +yet up to date. I think it works OK now, though I haven't tried all possible +combinations of options. For instance, I haven't ever used the incidence +angle or insolation time outputs. There's no reason why they should have +stopped working but there are always changes that break something unexpected. + +The main changes are: + +- possibility to read in horizon rasters to use with the shadow calculation. + +- Calculation of the shadowing effect should now also work in lat/lon projection. + +- There was a bug in r.sun whereby the shadowing effect was calculated wrong +when the left-right and up-down directions in the projection are different +from east-west and north-south, as is the case in the projection we use +(Lambert Azimuthal) when moving away from the point of origin. This has been +fixed now though only checked with Lambert Azimuthal. + +- I'm not sure if this went in already in a previous version, but the +algorithm now also takes into account the curvature of the earth when +calculating shadows. + +- new output possibility: glob_rad, which is the sum of the three radiation +components + +- new input parameter: civiltime. When this parameter is given, the +single time calculation will calculate the irradiance at the *same* time for +the entire raster instead of using the local solar time. The value of +civiltime is the timezone, relative to GMT. (+1 for central Europe) + +- new input parameter numpartitions No change in the calculation +methods, but the program will read the input rasters and do the calculations +in a number of chunks, instead of reading in everything at the start. Output +is still only at the very end. This is only to save memory. It will not work +if you try to calculate shadows without the horizon information, and the +program will tell you so. + +- I reorganized the source code quite a lot. In particular, I spun off several +functions into a separate source file called rsunlib.c. I also organized many +of the global variables into struct's for an easier overview. I did +this because we work here with several derivatives of r.sun: + + * r.sunyear which calculates the optimum inclination angle for maximum +insolation + * r.pv which calculates the PV output taking into account also temperature +effects + * r.sun.2axis which is r.sun for a moving plane, whose normal always points +to the sun (two-axis tracking solar energy systems). + +Splitting the source code made it easier to reuse bits for these r.sun +derivatives. I haven't updated the Makefile to account for these changes yet. +Look at the little script "compdebug" in the source directory. + + +There may be other changes that I've forgotten about but nothing dramatic. + +Have fun! + + +Thomas + +-- +-------------------------------------------------- +Thomas Huld +Joint Research Centre of the European Commission +T.P. 450 +I-21020 Ispra, Italy +phone: +39 0332785273 +e-mail: Thomas.Huld@jrc.it +-------------------------------------------------- + +###################################################################### +Probably the sun position calculation shouldbe replaced +with + + G_calc_solar_position() + +currently used in r.sunmask. G_calc_solar_position() is based on +solpos.c from NREL and very precise. + +MN 4/2001 Added: trunk/grassaddons/r.sun_horizon/r.sun2/description.html =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/description.html (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/description.html 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,248 @@ +

DESCRIPTION

+ +r.sun computes beam (direct), diffuse and ground reflected solar +irradiation raster maps for given day, latitude, surface and atmospheric +conditions. Solar parameters (e.g. time of sunrise and sunset, declination, +extraterrestrial irradiance, daylight length) are stored in the resultant maps' +history files. Alternatively, the local time can be specified to compute solar +incidence angle and/or irradiance raster maps. The shadowing effect of the +topography is optionally incorporated. This can be done either by calculating +the shadowing effect directly from the digital elevation model or using rasters +of the horizon height which is much faster. The horizon rasters can be +constructed using +r.horizon. + +

+The solar geometry of the model is based on the works of Krcho (1990), later +improved by Jenco (1992). The equations describing Sun – Earth position as +well as an interaction of the solar radiation with atmosphere were originally +based on the formulas suggested by Kitler and Mikler (1986). This component +was considerably updated by the results and suggestions of the working group +co-ordinated by Scharmer and Greif (2000) (this algorithm might be replaced +by SOLPOS algorithm-library included in GRASS within +r.sunmask + command). The model computes all three components of global radiation (beam, +diffuse and reflected) for the clear sky conditions, i.e. not taking into +consideration the spatial and temporal variation of clouds. The extent and +spatial resolution of the modelled area, as well as integration over time, +are limited only by the memory and data storage resources. The model is built +to fulfil user needs in various fields of science (hydrology, climatology, +ecology and environmental sciences, photovoltaics, engineering, etc.) for +continental, regional up to the landscape scales. +

As an option the model considers a shadowing effect of the local topography. +The r.sun program works in two modes. In the first mode it calculates for the set +local time a solar incidence angle [degrees] and solar irradiance values [W.m-2]. +In the second mode daily sums of solar radiation [Wh.m-2.day-1] are computed +within a set day. By a scripting the two modes can be used separately or +in a combination to provide estimates for any desired time interval. The +model accounts for sky obstruction by local relief features. Several solar +parameters are saved in the resultant maps' history files, which may be viewed +with the r.info command. +

+

The solar incidence angle raster map incidout is computed specifying +elevation raster map elevin, aspect raster map aspin, slope +steepness raster map slopin, given the day day and local time +time. There is no need to define latitude for locations with known +and defined projection/coordinate system (check it with the +g.proj + command). If you have undefined projection, (x,y) system, etc. then the latitude +can be defined explicitely for large areas by input raster map latin + with interpolated latitude values or, for smaller areas, a single region +latitude value lat can be used instead. All input raster maps must +be floating point (FCELL) raster maps. Null data in maps are excluded from +the computation (and also speeding-up the computation), so each output raster +map will contain null data in cells according to all input raster maps. The +user can use r.null + command to create/reset null file for your input raster maps.
+The specified day day is the number of the day of the general year +where January 1 is day no.1 and December 31 is 365. Time time must +be a local (solar) time (i.e. NOT a zone time, e.g. GMT, CET) in decimal system, +e.g. 7.5 (= 7h 30m A.M.), 16.1 = 4h 6m P.M..

+

Setting the solar declination declin by user is an option to override +the value computed by the internal routine for the day of the year. The value +of geographical latitude can be set as a constant for the whole computed +region or, as an option, a grid representing spatially distributed values +over a large region. The geographical latitude must be also in decimal system +with positive values for northern hemisphere and negative for southern one. +In similar principle the Linke turbidity factor (linkein, lin +) and ground albedo (albedo, alb) can be set.

+

Besides clear-sky radiations, the user can compute a real-sky radiation (beam, +diffuse) using coefbh and coefdh input raster maps defining +the fraction of the respective clear-sky radiations reduced by atmospheric +factors (e.g. cloudiness). The value is between 0-1. Usually these +coefficients can be obtained from a long-terms meteorological measurements.

+

The solar irradiation or irradiance raster maps beam_rad, diff_rad +, refl_rad are computed for a given day day, latitude lat +(latin), elevation elevin, slope slopein and aspect +aspin raster files. For convenience, the output raster given as glob_rad will output the sum of the three radiation components. The program uses the Linke atmosphere turbidity factor +and ground albedo coefficient. A default, single value of Linke factor is +lin=3.0 and is near the annual average for rural-city areas. The Linke +factor for an absolutely clear atmosphere is lin=1.0. See notes below +to learn more about this factor. The incidence solar angle is the angle between +horizon and solar beam vector. The solar radiation maps for given day are +computed integrating the relevant irradiance between sunrise and sunset times +for given day. The user can set finer or coarser time step step used +for all-day radiation calculations. A default value of step is 0.5 +hour. Larger steps (e.g. 1.0-2.0) can speed-up calculations but produce less +reliable results. The output units are in Wh per squared meter per given +day [Wh/(m*m)/day]. The incidence angle and irradiance/irradiation maps can +be computed without shadowing influence of relief by default or they can +be computed with this influence using the flag -s. In mountainous areas +this can lead to very different results! The user should be aware that taken +into account the shadowing effect of relief can slow +down the speed of computing especially when the sun altitude is low. + When considering shadowing effect (flag -s) speed and precision computing +can be controlled by a parameter dist which defines the sampling density +at which the visibility of a grid cell is computed in the direction of a +path of the solar flow. It also defines the method by which the obstacle's +altitude is computed. When choosing dist less than 1.0 (i.e. sampling +points will be computed at dist * cellsize distance), r.sun takes +altitude from the nearest grid point. Values above 1.0 will use the maximum +altitude value found in the nearest 4 surrounding grid points. The default +value dist=1.0 should give reasonable results for most cases (e.g. +on DEM). Dist value defines a multiplying coefficient for sampling +distance. This basic sampling distance equals to the arithmetic average of +both cell sizes. The reasonable values are in the range 0.5-1.5. The values +below 0.5 will decrease and values above 1.0 will increase the computing +speed. Values greater than 2.0 may produce estimates with lower accuracy +in highly dissected relief. The fully shadowed areas are written to the ouput +maps as zero values. Areas with NULL data are considered as no barrier with +shadowing effect .

+

The maps' history files are generated containing the following listed +parameters used in the computation:
+- Solar constant 1367 W.m-2
+- Extraterrestrial irradiance on a plane perpendicular to the solar beam +[W.m-2]
+- Day of the year
+- Declination [radians]
+- Decimal hour (Alternative 1 only)
+- Sunrise and sunset (min-max) over a horizontal plane
+- Daylight lengths
+- Geographical latitude (min-max)
+- Linke turbidity factor (min-max)
+- Ground albedo (min-max)

+

The user can use a nice shellcript with variable +day to compute radiation for some time interval within the year (e.g. vegetation +or winter period). Elevation, aspect and slope input values should not be +reclassified into coarser categories. This could lead to incorrect results. +

+ +

OPTIONS

+

Currently, there are two modes of r.sun. +In the first mode it calculates solar incidence angle and solar irradiance +raster maps using the set local time. In the second mode daily sums of solar +irradiation [kWh.m-2.day-1] are computed for a specified day.

+ +

+NOTES

+ +Solar energy is an important input parameter in different models concerning +energy industry, landscape, vegetation, evapotranspiration, snowmelt or remote +sensing. Solar rays incidence angle maps can be effectively used in radiometric +and topographic corrections in mountainous and hilly terrain where very accurate +investigations should be performed. +

+The clear-sky solar radiation model applied in the r.sun is based on the +work undertaken for development of European Solar Radiation Atlas (Scharmer +and Greif 2000, Page et al. 2001, Rigollier 2001). The clear sky model estimates +the global radiation from the sum of its beam, diffuse and reflected components. +The main difference between solar radiation models for inclined surfaces +in Europe is the treatment of the diffuse component. In the European climate +this component is often the largest source of estimation error. Taking into +consideration the existing models and their limitation the European Solar +Radiation Atlas team selected the Muneer (1990) model as it has a sound theoretical +basis and thus more potential for later improvement.

+

+Details of underlying equations used in this program can be found in the +reference literature cited below or book published by Neteler and Mitasova: +Open Source GIS: A GRASS GIS Approach (published in Kluwer Academic Publishers +in 2002).

+

+Average monthly values of the Linke turbidity coefficient for a mild climate +(see reference literature for your study area):

+
+Month      Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec  annual
+mountains  1.5  1.6  1.8  1.9  2.0  2.3  2.3  2.3  2.1  1.8  1.6  1.5  1.90  
+rural      2.1  2.2  2.5  2.9  3.2  3.4  3.5  3.3  2.9  2.6  2.3  2.2  2.75  
+city       3.1  3.2  3.5  4.0  4.2  4.3  4.4  4.3  4.0  3.6  3.3  3.1  3.75  
+industrial 4.1  4.3  4.7  5.3  5.5  5.7  5.8  5.7  5.3  4.9  4.5  4.2  5.00 +
+

+Planned improvements include the use of the SOLPOS algorithm for solar +geometry calculations and internal computation of aspect and slope. + +

Shadow maps

+A map of shadows can be extracted from the solar incidence angle map +(incidout). Areas with zero values are shadowed. The -s flag +has to be used. + +

SEE ALSO

+r.slope.aspect, +r.sunmask, +g.proj, +r.null, +v.surf.rst + + +

REFERENCES

+ +Hofierka, J., Suri, M. (2002): The solar radiation model for Open source +GIS: implementation and applications. Manuscript submitted to the International +GRASS users conference in Trento, Italy, September 2002. +

+Hofierka, J. (1997). Direct solar radiation modelling within an open GIS +environment. Proceedings of JEC-GI'97 conference in Vienna, Austria, IOS +Press Amsterdam, 575-584.

+

+Jenco, M. (1992). Distribution of direct solar radiation on georelief and +its modelling by means of complex digital model of terrain (in Slovak). Geograficky +casopis, 44, 342-355.

+

+Kasten, F. (1996). The Linke turbidity factor based on improved values of +the integral Rayleigh optical thickness. Solar Energy, 56 (3), 239-244.

+

+Kasten, F., Young, A. T. (1989). Revised optical air mass tables and approximation +formula. Applied Optics, 28, 4735-4738.

+

+Kittler, R., Mikler, J. (1986): Basis of the utilization of solar radiation +(in Slovak). VEDA, Bratislava, p. 150.

+

+Krcho, J. (1990). Morphometric analysis and digital models of georelief. VEDA, +Bratislava (in Slovak).

+

+Muneer, T. (1990). Solar radiation model for Europe. Building services engineering +research and technology, 11, 4, 153-163.

+

+Neteler, M., Mitasova, H. (2002): Open Source GIS: A GRASS GIS Approach, Kluwer +Academic Publishers.

+

+Page, J. ed. (1986). Prediction of solar radiation on inclined surfaces. Solar +energy R&D in the European Community, series F – Solar radiation data, +Dordrecht (D. Reidel), 3, 71, 81-83.

+

+Page, J., Albuisson, M., Wald, L. (2001). The European solar radiation atlas: +a valuable digital tool. Solar Energy, 71, 81-83.

+

+Rigollier, Ch., Bauer, O., Wald, L. (2000). On the clear sky model of the +ESRA - European Solar radiation Atlas - with respect to the Heliosat method. +Solar energy, 68, 33-48.

+

+Scharmer, K., Greif, J., eds., (2000). The European solar radiation atlas, +Vol. 2: Database and exploitation software. Paris (Les Presses de l’ École +des Mines).

+ +

Joint Research Centre: GIS solar radiation database for Europe

+ +

AUTHORS

+ +Jaroslav Hofierka, GeoModel, s.r.o. Bratislava, Slovakia
+ +Marcel Suri, GeoModel, s.r.o. Bratislava, Slovakia
+ +© 2007, Jaroslav Hofierka, Marcel Suri +
+hofierka@geomodel.sk +suri@geomodel.sk +
+ +

Last changed: $Date: 2005/03/06 12:33:04 $

Added: trunk/grassaddons/r.sun_horizon/r.sun2/local_proto.h =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/local_proto.h (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/local_proto.h 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,65 @@ +/* main.c */ + + +void where_is_point(double *length, struct SunGeometryVarDay *sunVarGeom, + struct GridGeometry *gridGeom); +int searching(double *length, struct SunGeometryVarDay *sunVarGeom, + struct GridGeometry *gridGeom); + +int useCivilTime(); +void setUseCivilTime(int val); +int useShadow(); +void setUseShadow(int val); +int useShadowData(); +void setUseShadowData(int val); +int useHorizonData(); +void setUseHorizonData(int val); +double getTimeOffset(); +void setTimeOffset(double val); +double getHorizonInterval(); +void setHorizonInterval(double val); +void setAngularLossDenominator(); + + +void cube(int, int); + +double com_sol_const(int no_of_day); + + +double brad(double, double *bh, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar); +double drad(double, double bh, double *rr, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar); + + +double brad_angle_loss(double, double *bh, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar); +double drad_angle_loss(double, double bh, double *rr, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar); + + +void com_par( struct SunGeometryConstDay *sungeom, + struct SunGeometryVarDay *sunVarGeom, + struct GridGeometry *gridGeom, + double latitude, double longitude); +void com_par_const(double longitTime, struct SunGeometryConstDay *sungeom, + struct GridGeometry *gridGeom); +double lumcline2(struct SunGeometryConstDay *sungeom, + struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct GridGeometry *gridGeom, + unsigned char *horizonpointer); + + +typedef double (*BeamRadFunc)(double sh, double *bh, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar); + +typedef double (*DiffRadFunc)(double sh, double bh, double *rr, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar); + Added: trunk/grassaddons/r.sun_horizon/r.sun2/main.c =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/main.c (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/main.c 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,2131 @@ +/******************************************************************************* +r.sun: This program was writen by Jaro Hofierka in Summer 1993 and re-engineered +in 1996-1999. In cooperation with Marcel Suri and Thomas Huld from JRC in Ispra +a new version of r.sun was prepared using ESRA solar radiation formulas. +See manual pages for details. +(C) 2002 Copyright Jaro Hofierka, Gresaka 22, 085 01 Bardejov, Slovakia, + and GeoModel, s.r.o., Bratislava, Slovakia +email: hofierka@geomodel.sk,marcel.suri@jrc.it,suri@geomodel.sk +*******************************************************************************/ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*v. 2.0 July 2002, NULL data handling, JH */ +/*v. 2.1 January 2003, code optimization by Thomas Huld, JH */ + +#define NUM_PARTITIONS "1" +#define SKIP "1" +#define BIG 1.e20 +#define LINKE "3.0" +#define SLOPE "0.0" +#define ASPECT "270" +#define ALB "0.2" +#define STEP "0.5" +#define BSKY 1.0 +#define DSKY 1.0 +#define DIST "1.0" + +#define SCALING_FACTOR 150. +const double invScale=1./SCALING_FACTOR; + +#define AMAX1(arg1, arg2) ((arg1) >= (arg2) ? (arg1) : (arg2)) +#define AMIN1(arg1, arg2) ((arg1) <= (arg2) ? (arg1) : (arg2)) +#define DISTANCE1(x1, x2, y1, y2) (sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2))) +#define DISTANCE2(x00, y00) ((xx0 - x00)*(xx0 - x00) + (yy0 - y00)*(yy0 - y00)) + +#include +#include +#include +#include +#include +#include +#include "sunradstruct.h" +#include "local_proto.h" +#include "rsunglobals.h" + + + +const double pihalf = M_PI*0.5; +const double pi2 = M_PI*2.; +const double deg2rad = M_PI/180.; +const double rad2deg = 180./M_PI; + + + +FILE *felevin,*faspin,*fslopein,*flinkein,*falbedo,*flatin; +FILE *fincidout,*fbeam_rad,*finsol_time,*fdiff_rad,*frefl_rad; +FILE *fw; + + +char *elevin; +char *aspin; +char *slopein; +char *civiltime = NULL; +char *linkein = NULL; +char *albedo = NULL; +char *latin = NULL; +char *coefbh = NULL; +char *coefdh = NULL; +char *incidout = NULL; +char *longin = NULL; +char *horizon = NULL; +char *beam_rad = NULL; +char *insol_time = NULL; +char *diff_rad = NULL; +char *refl_rad = NULL; +char *glob_rad = NULL; +char *mapset = NULL; +char *per; +char *shade; +char mapname[1024]; + +struct Cell_head cellhd; +struct pj_info iproj; +struct pj_info oproj; +struct History hist; + + +int INPUT_part(int offset, double *zmax); +int OUTGR(void); +int min(int, int); +int max(int, int); + +void cube(int, int); +void (*func) (int, int); + +void joules2(struct SunGeometryConstDay *sunGeom, + struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar, + struct GridGeometry *gridGeom, + unsigned char *horizonpointer, + double latitude, double longitude); + + +void calculate(double singleSlope, double singleAspect, + double singleAlbedo, double singleLinke, + struct GridGeometry gridGeom); +double com_declin(int); + +int n, m, ip, jp; +int d, day; +int saveMemory, numPartitions=1; +int shadowoffset=0; +int varCount_global=0; +int bitCount_global=0; +int arrayNumInt = 1; +float **z=NULL, **o=NULL, **s=NULL, **li=NULL, **a=NULL, **la=NULL, **longitArray, + **cbhr=NULL, **cdhr=NULL; +double op, dp; +double invstepx, invstepy; +double sr_min = 24., sr_max = 0., ss_min = 24., ss_max = 0.; + +float **lumcl, **beam, **insol, **diff, **refl, **globrad; +unsigned char *horizonarray=NULL; +double civilTime; +/* +double startTime, endTime; +*/ +double xmin, xmax, ymin, ymax; +double declin, step, dist; +double li_max = 0., li_min = 100., al_max = 0., al_min = 1.0, la_max = -90., + la_min = 90.; + double offsetx=0.5, offsety=0.5; +char *tt, *lt; +/* +double slope; +*/ +double o_orig, z1; +/* +double lum_C11, lum_C13, lum_C22, lum_C31, lum_C33; +double sinSolarAltitude; */ + +/* Sine of the solar altitude (angle above horizon) +*/ +/* +double sunrise_time, sunset_time; +double solarAltitude; +double tanSolarAlt, solarAzimuth; +double stepsinangle, stepcosangle; +double angle; +*/ +double horizonStep; +double ltime, tim, timo; +double declination; /* Contains the negative of the declination at the chosen day*/ +/* +double lum_C31_l, lum_C33_l; +*/ +double beam_e, diff_e, refl_e, rr, insol_t; +double cbh, cdh; +double TOLER; + +int main(int argc, char *argv[]) +{ + double singleSlope; + double singleAspect; + double singleAlbedo; + double singleLinke; + + struct GModule *module; + struct + { + struct Option *elevin,*aspin,*aspect,*slopein,*slope,*linkein,*lin,*albedo,*longin, + *alb,*latin,*lat,*coefbh, *coefdh, *incidout,*beam_rad, + *insol_time,*diff_rad,*refl_rad,*glob_rad,*day,*step, *declin,*ltime,*dist,*horizon,*horizonstep, + *numPartitions, *civilTime; + } + parm; + + struct + { + struct Flag *shade, *saveMemory; + } + flag; + + struct GridGeometry gridGeom; + + + G_gisinit(argv[0]); + module = G_define_module(); + + module->description = + _("Computes direct (beam), diffuse and reflected solar irradiation raster " + "maps for given day, latitude, surface and atmospheric conditions. Solar " + "parameters (e.g. sunrise, sunset times, declination, extraterrestrial " + "irradiance, daylight length) are saved in a local text file. " + "Alternatively, a local time can be specified to compute solar " + "incidence angle and/or irradiance raster maps. The shadowing effect of " + "the topography is optionally incorporated."); + + if(G_get_set_window(&cellhd)==-1) G_fatal_error("G_get_set_window() failed"); + gridGeom.stepx = cellhd.ew_res; + gridGeom.stepy = cellhd.ns_res; + invstepx = 1. / gridGeom.stepx; + invstepy = 1. / gridGeom.stepy; + n /*n_cols */ = cellhd.cols; + m /*n_rows */ = cellhd.rows; + xmin = cellhd.west; + ymin = cellhd.south; + xmax = cellhd.east; + ymax = cellhd.north; + gridGeom.deltx = fabs(cellhd.east - cellhd.west); + gridGeom.delty = fabs(cellhd.north - cellhd.south); + + parm.elevin = G_define_option(); + parm.elevin->key = "elevin"; + parm.elevin->type = TYPE_STRING; + parm.elevin->required = YES; + parm.elevin->gisprompt = "old,cell,raster"; + parm.elevin->description = _("Name of the elevation raster file"); + + parm.aspin = G_define_option(); + parm.aspin->key = "aspin"; + parm.aspin->type = TYPE_STRING; + parm.aspin->required = NO; + parm.aspin->gisprompt = "old,cell,raster"; + parm.aspin->description = _("Name of the aspect raster file"); + + parm.aspect = G_define_option(); + parm.aspect->key = "aspect"; + parm.aspect->type = TYPE_DOUBLE; + parm.aspect->answer = ASPECT; + parm.aspect->required = NO; + parm.aspect->description = _("A single value of the orientation (aspect), 270 is south"); + + parm.slopein = G_define_option(); + parm.slopein->key = "slopein"; + parm.slopein->type = TYPE_STRING; + parm.slopein->required = NO; +/* parm.slopein->gisprompt = "old,cell,raster"; +*/ + parm.slopein->description = _("Name of the slope raster file"); + + parm.slope = G_define_option(); + parm.slope->key = "slope"; + parm.slope->type = TYPE_DOUBLE; + parm.slope->answer = SLOPE; + parm.slope->required = NO; + parm.slope->description = _("A single value of inclination (slope)"); + + parm.linkein = G_define_option(); + parm.linkein->key = "linkein"; + parm.linkein->type = TYPE_STRING; + parm.linkein->required = NO; + parm.linkein->gisprompt = "old,cell,raster"; + parm.linkein->description = + _("Name of the Linke turbidity coefficient raster file"); + + if (parm.linkein->answer == NULL) { + parm.lin = G_define_option(); + parm.lin->key = "lin"; + parm.lin->type = TYPE_DOUBLE; + parm.lin->answer = LINKE; + parm.lin->required = NO; + parm.lin->description = + _("A single value of the Linke turbidity coefficient"); + } + + parm.albedo = G_define_option(); + parm.albedo->key = "albedo"; + parm.albedo->type = TYPE_STRING; + parm.albedo->required = NO; + parm.albedo->gisprompt = "old,cell,raster"; + parm.albedo->description = _("Name of the albedo coefficient raster file"); + + if (parm.albedo->answer == NULL) { + parm.alb = G_define_option(); + parm.alb->key = "alb"; + parm.alb->type = TYPE_DOUBLE; + parm.alb->answer = ALB; + parm.alb->required = NO; + parm.alb->description = _("A single value of the albedo coefficient"); + } + + parm.latin = G_define_option(); + parm.latin->key = "latin"; + parm.latin->type = TYPE_STRING; + parm.latin->required = NO; + parm.latin->gisprompt = "old,cell,raster"; + parm.latin->description = _("Name of the latitude raster file"); + + if (parm.latin->answer == NULL) { + parm.lat = G_define_option(); + parm.lat->key = "lat"; + parm.lat->type = TYPE_DOUBLE; + parm.lat->required = NO; + parm.lat->description = _("A single value of latitude"); + } + + parm.longin = G_define_option(); + parm.longin->key = "longin"; + parm.longin->type = TYPE_STRING; + parm.longin->required = NO; + parm.longin->gisprompt = "old,cell,raster"; + parm.longin->description = _("Name of the longitude raster file"); + + + parm.coefbh = G_define_option(); + parm.coefbh->key = "coefbh"; + parm.coefbh->type = TYPE_STRING; + parm.coefbh->required = NO; + parm.coefbh->gisprompt = "old,cell,raster"; + parm.coefbh->description = _("The real-sky beam radiation coefficient file"); + + parm.coefdh = G_define_option(); + parm.coefdh->key = "coefdh"; + parm.coefdh->type = TYPE_STRING; + parm.coefdh->required = NO; + parm.coefdh->gisprompt = "old,cell,raster"; + parm.coefdh->description = + _("The real-sky diffuse radiation coefficient file"); + + + parm.horizon = G_define_option(); + parm.horizon->key = "horizon"; + parm.horizon->type = TYPE_STRING; + parm.horizon->required = NO; + parm.horizon->gisprompt = "old,cell,raster"; + parm.horizon->description = _("The horizon information file prefix"); + + parm.horizonstep = G_define_option(); + parm.horizonstep->key = "horizonstep"; + parm.horizonstep->type = TYPE_DOUBLE; + parm.horizonstep->required = NO; + parm.horizonstep->description = _("Angle step size for the horizon information (degrees)"); + + parm.incidout = G_define_option(); + parm.incidout->key = "incidout"; + parm.incidout->type = TYPE_STRING; + parm.incidout->required = NO; + parm.incidout->gisprompt = "old,cell,raster"; + parm.incidout->description = _("Output incidence angle file (raster)"); + + parm.beam_rad = G_define_option(); + parm.beam_rad->key = "beam_rad"; + parm.beam_rad->type = TYPE_STRING; + parm.beam_rad->required = NO; + parm.beam_rad->gisprompt = "old,cell,raster"; + parm.beam_rad->description = + _("Output direct (beam) irradiance/irradiation file (raster)"); + + parm.insol_time = G_define_option(); + parm.insol_time->key = "insol_time"; + parm.insol_time->type = TYPE_STRING; + parm.insol_time->required = NO; + parm.insol_time->gisprompt = "old,cell,raster"; + parm.insol_time->description = _("Output insolation time file (raster)"); + + parm.diff_rad = G_define_option(); + parm.diff_rad->key = "diff_rad"; + parm.diff_rad->type = TYPE_STRING; + parm.diff_rad->required = NO; + parm.diff_rad->gisprompt = "old,cell,raster"; + parm.diff_rad->description = + _("Output diffuse irradiance/irradiation file (raster)"); + + parm.refl_rad = G_define_option(); + parm.refl_rad->key = "refl_rad"; + parm.refl_rad->type = TYPE_STRING; + parm.refl_rad->required = NO; + parm.refl_rad->gisprompt = "old,cell,raster"; + parm.refl_rad->description = + _("Output reflected irradiance/irradiation file (raster)"); + + parm.glob_rad = G_define_option(); + parm.glob_rad->key = "glob_rad"; + parm.glob_rad->type = TYPE_STRING; + parm.glob_rad->required = NO; + parm.glob_rad->gisprompt = "old,cell,raster"; + parm.glob_rad->description = _("Output global (total) irradiance/irradiation file (raster)"); + + + parm.day = G_define_option(); + parm.day->key = "day"; + parm.day->type = TYPE_INTEGER; + parm.day->required = YES; + parm.day->description = _("No. of day of the year (1-365)"); + + parm.step = G_define_option(); + parm.step->key = "step"; + parm.step->type = TYPE_DOUBLE; + parm.step->answer = STEP; + parm.step->required = NO; + parm.step->description = _("Time step computing all-day radiation"); + + parm.declin = G_define_option(); + parm.declin->key = "declin"; + parm.declin->type = TYPE_DOUBLE; + parm.declin->required = NO; + parm.declin->description = + _("Required declination value (overriding the internal value)"); + + parm.ltime = G_define_option(); + parm.ltime->key = "time"; + parm.ltime->type = TYPE_DOUBLE; + /* parm.ltime->answer = TIME; */ + parm.ltime->required = NO; + parm.ltime->description = _("Local (solar) time [decimal hours]"); + +/* + parm.startTime = G_define_option(); + parm.startTime->key = "starttime"; + parm.startTime->type = TYPE_DOUBLE; + parm.startTime->required = NO; + parm.startTime->description = _("Starting time for calculating results for several different times."); + + parm.endTime = G_define_option(); + parm.endTime->key = "endtime"; + parm.endTime->type = TYPE_DOUBLE; + parm.endTime->required = NO; + parm.endTime->description = _("End time for calculating results for several different times.)"; +*/ + + parm.dist = G_define_option(); + parm.dist->key = "dist"; + parm.dist->type = TYPE_DOUBLE; + parm.dist->answer = DIST; + parm.dist->required = NO; + parm.dist->description = _("Sampling distance step coefficient (0.5-1.5)"); + + parm.numPartitions = G_define_option(); + parm.numPartitions->key = "numpartitions"; + parm.numPartitions->type = TYPE_INTEGER; + parm.numPartitions->answer = NUM_PARTITIONS; + parm.numPartitions->required = NO; + parm.numPartitions->description = _("Read the input files in this number of chunks"); + + parm.civilTime = G_define_option(); + parm.civilTime->key = "civiltime"; + parm.civilTime->type = TYPE_DOUBLE; + parm.civilTime->required = NO; + parm.civilTime->description = _("(optional) The civil time zone value, if none, the time will be local solar time"); + + + flag.shade = G_define_flag(); + flag.shade->key = 's'; + flag.shade->description = + _("Do you want to incorporate the shadowing effect of terrain (y/n)"); + + flag.saveMemory = G_define_flag(); + flag.saveMemory->key = 'm'; + flag.saveMemory->description = _("Do you want to use the low-memory version of the program (y/n)"); + + + if(G_parser(argc,argv)) + exit(EXIT_FAILURE); + + + setUseShadow(flag.shade->answer); + +/* + if(shd) + { + + } +*/ + saveMemory=flag.saveMemory->answer; + civiltime = parm.civilTime->answer; + + + elevin = parm.elevin->answer; + aspin = parm.aspin->answer; + slopein = parm.slopein->answer; + linkein = parm.linkein->answer; + albedo = parm.albedo->answer; + latin = parm.latin->answer; + + + if(civiltime != NULL) + { + setUseCivilTime(1); + longin = parm.longin->answer; + + if(longin == NULL) + { + G_fatal_error(_("You must give the longitude raster if you use civil time")); + + } + sscanf(parm.civilTime->answer, "%lf", &civilTime); + + /* Normalize if somebody should be weird enough to give more than +- 12 + hours offset. */ + + civilTime -= 24*((int) (civilTime/24.)); + if(civilTime<-12.) + { + civilTime +=24.; + } + else if(civilTime>12.) + { + civilTime-=24; + } + + } + else + { + setUseCivilTime(0); + } + coefbh = parm.coefbh->answer; + coefdh = parm.coefdh->answer; + incidout = parm.incidout->answer; + horizon = parm.horizon->answer; + setUseHorizonData(horizon!=NULL); + beam_rad = parm.beam_rad->answer; + insol_time = parm.insol_time->answer; + diff_rad = parm.diff_rad->answer; + refl_rad = parm.refl_rad->answer; + glob_rad = parm.glob_rad->answer; + + if((insol_time != NULL) && (incidout != NULL)) + G_fatal_error(_("insol_time and incidout are incompatible options")); + + sscanf(parm.day->answer, "%d", &day); + sscanf(parm.step->answer, "%lf", &step); + + if(parm.step->answer!=NULL) + { + if(sscanf(parm.step->answer, "%lf", &step)!=1) + G_fatal_error(_("Error reading time step size")); + } + if(parm.horizonstep->answer!=NULL) + { + if(sscanf(parm.horizonstep->answer, "%lf", &horizonStep)!=1) + G_fatal_error(_("Error reading horizon step size")); + setHorizonInterval(deg2rad* horizonStep); + } + + + tt = parm.ltime->answer; + if (parm.ltime->answer != NULL) { + if(insol_time != NULL) G_fatal_error(_("time and insol_time are incompatible options")); + G_message ( _("Mode 1: instantaneous solar incidence angle & irradiance using a set local time")); + sscanf(parm.ltime->answer, "%lf", &timo); + } + else { + if(incidout != NULL) G_fatal_error(_("incidout requres time parameter to be set")); + G_message ( _("Mode 2: integrated daily irradiation")); + } + +/* + if (parm.startTime->answer != NULL) sscanf(parm.startTime->answer, "%lf", &startTime); + if (parm.endTime->answer != NULL) sscanf(parm.endTime->answer, "%lf", &endTime); + + if((parm.startTime->answer != NULL) ||(parm.endTime->answer != NULL)) + { +*/ + /* The start and end times should only be defined if the single + time is not defined, and if the step size *is* defined. */ +/* + if(parm.step->answer==NULL) + { + printf("If you want to use a time interval you must also define a step size.\n"); + exit(1); + } + if(parm.ltime->answer!=NULL) + { + printf("If you want to use a time interval you can't define a single time value.\n"); + exit(1); + } + if((parm.startTime->answer==NULL)||(parm.endTime->answer==NULL)) + { + printf("If you want to use a time interval\n"); + printf("both the start and end times must be defined.\n"); + exit(1); + } + } +*/ + if (parm.linkein->answer == NULL) + sscanf(parm.lin->answer, "%lf", &singleLinke); + if (parm.albedo->answer == NULL) + sscanf(parm.alb->answer, "%lf", &singleAlbedo); + lt = parm.lat->answer; +/* + if (parm.lat->answer != NULL) + sscanf(parm.lat->answer, "%lf", &latitude); +*/ + if (parm.slopein->answer == NULL) + sscanf(parm.slope->answer, "%lf", &singleSlope); + singleSlope *= deg2rad; + + if (parm.aspin->answer == NULL) + sscanf(parm.aspect->answer, "%lf", &singleAspect); + singleAspect *= deg2rad; + + if (parm.coefbh->answer == NULL) + cbh = BSKY; + if (parm.coefdh->answer == NULL) + cdh = DSKY; + sscanf(parm.dist->answer, "%lf", &dist); + + if(parm.numPartitions->answer != NULL) + { + sscanf(parm.numPartitions->answer, "%d", &numPartitions); + if(useShadow()&&(!useHorizonData())&&(numPartitions!=1)) + { + /* If you calculate shadows on the fly, the number of partitions + must be one. + */ + G_fatal_error(_("If you use -s and no horizon rasters, numpartitions must be =1")); + + } + + } + + gridGeom.stepxy = dist * 0.5 * (gridGeom.stepx + gridGeom.stepy); + TOLER = gridGeom.stepxy * EPS; + + /* The save memory scheme will not work if you want to calculate shadows + on the fly. If you calculate without shadow effects or if you have the + shadows pre-calculated, there is no problem. */ + + if(saveMemory && useShadow() && (!useHorizonData())) + G_fatal_error(_("If you want to save memory and to use shadows, you must use pre-calculated horizons.")); + + if (parm.declin->answer == NULL) + declination = com_declin(day); + else { + sscanf(parm.declin->answer, "%lf", &declin); + declination = -declin; + } + + +/* + if (lt != NULL) + latitude = -latitude * deg2rad; +*/ + if(tt!=0) + { + /* Shadow for just one time during the day */ + if(horizon==NULL) + { + arrayNumInt = 1; + } + else if (useHorizonData()) + { + arrayNumInt = (int)(360. / horizonStep); + + } + } + else + { + if (useHorizonData()) + { +/* Number of bytes holding the horizon information */ + arrayNumInt = (int)(360. / horizonStep); + } + } + + if (tt != NULL) { + + tim = (timo - 12) * 15; + /* converting to degrees */ + /* Jenco (12-timeAngle) * 15 */ + if (tim < 0) + tim += 360; + tim = M_PI * tim / 180; + /* conv. to radians */ + } + + /* Set up parameters for projection to lat/long if necessary */ + + + struct Key_Value *in_proj_info, *in_unit_info; + + if ((in_proj_info = G_get_projinfo()) == NULL) + G_fatal_error + (_("Can't get projection info of current location: please set latitude via 'lat' or 'latin' option!")); + + if ((in_unit_info = G_get_projunits()) == NULL) + G_fatal_error(_("Can't get projection units of current location")); + + if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0) + G_fatal_error + (_("Can't get projection key values of current location")); + + G_free_key_value(in_proj_info); + G_free_key_value(in_unit_info); + + /* Set output projection to latlong w/ same ellipsoid */ + oproj.zone = 0; + oproj.meters = 1.; + sprintf(oproj.proj, "ll"); + if ((oproj.pj = pj_latlong_from_proj(iproj.pj)) == NULL) + G_fatal_error(_("Unable to set up lat/long projection parameters")); + + +/**********end of parser - ******************************/ + + calculate(singleSlope, singleAspect, singleAlbedo, + singleLinke,gridGeom); + OUTGR(); + + return 1; +} + + +int INPUT_part(int offset, double *zmax) + +{ + int finalRow, rowrevoffset; + int numRows; + FCELL *cell1=NULL, *cell2=NULL; + FCELL *cell3=NULL, *cell4=NULL, *cell5=NULL, *cell6=NULL, *cell7=NULL; + FCELL *rast1=NULL, *rast2=NULL; + static FCELL **horizonbuf; + char* horizonpointer; + int fd1=-1, fd2=-1, fd3=-1, fd4=-1, fd5=-1, fd6=-1, fd7=-1, row, row_rev; + static int *fd_shad; + int fr1=-1, fr2=-1; + int l, i, j; + char shad_filename[256]; + + finalRow = m- offset -m/numPartitions; + if(finalRow<0) + { + finalRow = 0; + } + + numRows = m/numPartitions; + + cell1=G_allocate_f_raster_buf(); + + if(z==NULL) + { + z = (float **)malloc(sizeof(float *)*(numRows)); + + + for(l=0;l=finalRow; row--) + { + + row_rev = m - row - 1; + rowrevoffset = row_rev-offset; + G_get_f_raster_row(fd_shad[i],horizonbuf[i],row); + horizonpointer = horizonarray + arrayNumInt*n*rowrevoffset; + for (j=0; j=finalRow; row--) + { + G_get_f_raster_row(fd1,cell1,row); + if(aspin != NULL) G_get_f_raster_row(fd2,cell2,row); + if(slopein != NULL) G_get_f_raster_row(fd3,cell3,row); + if(linkein != NULL) G_get_f_raster_row(fd4,cell4,row); + if(albedo != NULL) G_get_f_raster_row(fd5,cell5,row); + if(latin != NULL) G_get_f_raster_row(fd6,cell6,row); + if(longin != NULL) G_get_f_raster_row(fd7,cell7,row); + if(coefbh != NULL) G_get_f_raster_row(fr1,rast1,row); + if(coefdh != NULL) G_get_f_raster_row(fr2,rast2,row); + + + + row_rev = m - row - 1; + rowrevoffset = row_rev-offset; + + for (j=0; j= arg2) { + res = arg1; + } + else { + res = arg2; + } + return res; +} +*/ + + + +/**********************************************************/ + + +void joules2(struct SunGeometryConstDay *sunGeom, + struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar, + struct GridGeometry *gridGeom, unsigned char *horizonpointer, + double latitude, double longitude) + { + + double s0, dfr, dfr_rad; + double ra, dra; + int ss = 1; + double firstTime; + double firstAngle, lastAngle; + int srStepNo; + double bh; + double rr; + + beam_e = 0.; + diff_e = 0.; + refl_e = 0.; + insol_t = 0.; + + + com_par(sunGeom, sunVarGeom,gridGeom,latitude,longitude); + + if (tt != NULL) { /*irradiance */ + + s0 = lumcline2(sunGeom,sunVarGeom,sunSlopeGeom,gridGeom, + horizonpointer); + + if (sunVarGeom->solarAltitude > 0.) { + if ((!sunVarGeom->isShadow) && (s0 > 0.)) { + ra = brad(s0,&bh, sunVarGeom,sunSlopeGeom,sunRadVar); /* beam radiation */ + beam_e += ra; + } + else { + beam_e = 0.; + bh = 0.; + } + + if((diff_rad != NULL) || (glob_rad!=NULL)) { + dra = drad(s0,bh, &rr, sunVarGeom,sunSlopeGeom,sunRadVar); /* diffuse rad. */ + diff_e += dra; + } + if((refl_rad != NULL) || (glob_rad!=NULL)) { + if ((diff_rad == NULL) && (glob_rad == NULL)) + drad(s0,bh, &rr, sunVarGeom,sunSlopeGeom,sunRadVar); + refl_e += rr; /* reflected rad. */ + } + } /* solarAltitude */ + } + else { + /* all-day radiation */ + + srStepNo = (int) (sunGeom->sunrise_time/step); + + if((sunGeom->sunrise_time-srStepNo*step)>0.5*step) + { + firstTime = (srStepNo+1.5)*step; + } + else + { + firstTime = (srStepNo+0.5)*step; + } + + + firstAngle = (firstTime - 12)*HOURANGLE; + lastAngle = (sunGeom->sunset_time - 12)*HOURANGLE; + + + + + dfr_rad = step * HOURANGLE; + + sunGeom->timeAngle = firstAngle; + + varCount_global=0; + + + dfr = step; + + while (ss == 1) { + + com_par(sunGeom,sunVarGeom,gridGeom,latitude,longitude); + s0 = lumcline2(sunGeom,sunVarGeom,sunSlopeGeom,gridGeom, + horizonpointer); + + if (sunVarGeom->solarAltitude > 0.) + { + + if ((!sunVarGeom->isShadow) && (s0 > 0.)) + { + insol_t += dfr; + ra = brad(s0,&bh,sunVarGeom,sunSlopeGeom,sunRadVar); + beam_e += dfr * ra; + ra=0.; + } + else + { + bh = 0.; + } + if((diff_rad != NULL) || (glob_rad!=NULL)) + { + dra = drad(s0,bh, &rr, sunVarGeom,sunSlopeGeom,sunRadVar); + diff_e += dfr * dra; + dra=0.; + } + if((refl_rad != NULL) || (glob_rad!=NULL)) + { + if ((diff_rad == NULL) && (glob_rad == NULL)) + { + drad(s0,bh, &rr, sunVarGeom,sunSlopeGeom,sunRadVar); + } + refl_e += dfr * rr; + rr = 0.; + } + } /* illuminated */ + + + sunGeom->timeAngle = sunGeom->timeAngle + dfr_rad; + + if (sunGeom->timeAngle > lastAngle) { + ss = 0; /* we've got the sunset */ + } + } /* end of while */ + } /* all-day radiation */ + +} +/*//////////////////////////////////////////////////////////////////////*/ + + + + +/* +void where_is_point(void) +{ + double sx, sy; + double dx, dy; + double adx, ady; + int i, j; + + sx = xx0 * invstepx + TOLER; + sy = yy0 * invstepy + TOLER; + + i = (int)sx; + j = (int)sy; + if (i < n - 1 && j < m - 1) { + + dx = xx0 - (double)i *stepx; + dy = yy0 - (double)j *stepy; + + adx = fabs(dx); + ady = fabs(dy); + + if ((adx > TOLER) && (ady > TOLER)) { + cube(j, i); + return; + } + else if ((adx > TOLER) && (ady < TOLER)) { + line_x(j, i); + return; + } + else if ((adx < TOLER) && (ady > TOLER)) { + line_y(j, i); + return; + } + else if ((adx < TOLER) && (ady < TOLER)) { + vertex(j, i); + return; + } + + + } + else { + func = NULL; + } +} + +*/ + +void where_is_point(double *length , struct SunGeometryVarDay *sunVarGeom, + struct GridGeometry *gridGeom) +{ + double sx, sy; + double dx, dy; +/* double adx, ady;*/ + int i, j; + + sx = gridGeom->xx0 * invstepx + offsetx; /* offset 0.5 cell size to get the right cell i, j */ + sy = gridGeom->yy0 * invstepy + offsety; + + i = (int)sx; j = (int)sy; + +/* if (i < n-1 && j < m-1) { to include last row/col*/ + if (i <= n-1 && j <= m-1) { + + dx = (double)i *gridGeom->stepx; + dy = (double)j *gridGeom->stepy; + + *length = DISTANCE1(gridGeom->xg0, dx, gridGeom->yg0, dy); /* dist from orig. grid point to the current grid point */ + + sunVarGeom->zp = z[j][i]; + +/* + cube(j, i); +*/ + } +} + +/* +void vertex(jmin, imin) + int jmin, imin; +{ + zp = z[jmin][imin]; + if ((zp == UNDEFZ)) + func = NULL; +} +void line_x(jmin, imin) + int jmin, imin; +{ + double c1, c2; + double d1, d2, e1, e2; + e1 = (double)imin *stepx; + e2 = (double)(imin + 1) * stepx; + + c1 = z[jmin][imin]; + c2 = z[jmin][imin + 1]; + if (!((c1 == UNDEFZ) || (c2 == UNDEFZ))) { + + if (dist <= 1.0) { + d1 = (xx0 - e1) / (e2 - e1); + d2 = 1 - d1; + if (d1 < d2) + zp = c1; + else + zp = c2; + } + + if (dist > 1.0) + zp = AMAX1(c1, c2); + } + else + func = NULL; +} + + +void line_y(jmin, imin) + int jmin, imin; +{ + double c1, c2; + double d1, d2, e1, e2; + e1 = (double)jmin *stepy; + e2 = (double)(jmin + 1) * stepy; + + c1 = z[jmin][imin]; + c2 = z[jmin + 1][imin]; + if (!((c1 == UNDEFZ) || (c2 == UNDEFZ))) { + + if (dist <= 1.0) { + d1 = (yy0 - e1) / (e2 - e1); + d2 = 1 - d1; + if (d1 < d2) + zp = c1; + else + zp = c2; + } + + if (dist > 1.0) + zp = AMAX1(c1, c2); + + } + else + func = NULL; + +} + +void cube(jmin, imin) + int jmin, imin; +{ + int i, ig = 0; + double x1, x2, y1, y2; + double v[4], vmin = BIG; + double c[4], cmax = -BIG; + + x1 = (double)imin *stepx; + x2 = x1 + stepx; + + y1 = (double)jmin *stepy; + y2 = y1 + stepy; + + v[0] = DISTANCE2(x1, y1); + + if (v[0] < vmin) { + ig = 0; + vmin = v[0]; + } + v[1] = DISTANCE2(x2, y1); + + if (v[1] < vmin) { + ig = 1; + vmin = v[1]; + } + + v[2] = DISTANCE2(x2, y2); + if (v[2] < vmin) { + ig = 2; + vmin = v[2]; + } + + v[3] = DISTANCE2(x1, y2); + if (v[3] < vmin) { + ig = 3; + vmin = v[3]; + } + + c[0] = z[jmin][imin]; + c[1] = z[jmin][imin + 1]; + c[2] = z[jmin + 1][imin + 1]; + c[3] = z[jmin + 1][imin]; + + + if (dist <= 1.0) { + + if (c[ig] != UNDEFZ) + zp = c[ig]; + else + func = NULL; + return; + } + + if (dist > 1.0) { + for (i = 0; i < 4; i++) { + if (c[i] != UNDEFZ) { + cmax = AMAX1(cmax, c[i]); + zp = cmax; + } + else + func = NULL; + } + } +} +*/ + +/* +void cube(jmin, imin) +int jmin, imin; +{ + zp = z[jmin][imin]; + +} +*/ + +void cube(jmin, imin) +{} + + +/*////////////////////////////////////////////////////////////////////// */ + +void calculate(double singleSlope, double singleAspect, double singleAlbedo, double singleLinke, + struct GridGeometry gridGeom) +{ + int i, j, l; + /* double energy; */ + int someRadiation; + int numRows; + int arrayOffset; + double lum, q1; + double dayRad; + double latid_l, cos_u, cos_v, sin_u, sin_v; + double sin_phi_l, tan_lam_l; + double zmax; + double longitTime=0.; + double locTimeOffset; + double latitude, longitude; + + + struct SunGeometryConstDay sunGeom; + struct SunGeometryVarDay sunVarGeom; + struct SunGeometryVarSlope sunSlopeGeom; + struct SolarRadVar sunRadVar; + + sunSlopeGeom.slope=singleSlope; + sunSlopeGeom.aspect=singleAspect; + sunRadVar.alb=singleAlbedo; + sunRadVar.linke=singleLinke; + sunRadVar.cbh = 1.0; + sunRadVar.cdh = 1.0; + + sunGeom.sindecl = sin(declination); + sunGeom.cosdecl = cos(declination); + + + someRadiation = (beam_rad != NULL) || (insol_time != NULL) || (diff_rad != NULL) || + (refl_rad != NULL)|| (glob_rad != NULL); + + + fprintf(stderr, "\n\n"); + + if (incidout != NULL) { + lumcl = (float **)malloc(sizeof(float *) * (m)); + for (l = 0; l < m; l++) { + lumcl[l] = (float *)malloc(sizeof(float) * (n)); + } + for (j = 0; j < m; j++) { + for (i = 0; i < n; i++) + lumcl[j][i] = UNDEFZ; + } + } + + if (beam_rad != NULL) { + beam = (float **)malloc(sizeof(float *) * (m)); + for (l = 0; l < m; l++) { + beam[l] = (float *)malloc(sizeof(float) * (n)); + } + + for (j = 0; j < m; j++) { + for (i = 0; i < n; i++) + beam[j][i] = UNDEFZ; + } + } + + if (insol_time != NULL) { + insol = (float **)malloc(sizeof(float *) * (m)); + for (l = 0; l < m; l++) { + insol[l] = (float *)malloc(sizeof(float) * (n)); + } + + for (j = 0; j < m; j++) { + for (i = 0; i < n; i++) + insol[j][i] = UNDEFZ; + } + } + + if (diff_rad != NULL) { + diff = (float **)malloc(sizeof(float *) * (m)); + for (l = 0; l < m; l++) { + diff[l] = (float *)malloc(sizeof(float) * (n)); + } + + for (j = 0; j < m; j++) { + for (i = 0; i < n; i++) + diff[j][i] = UNDEFZ; + } + } + + if (refl_rad != NULL) { + refl = (float **)malloc(sizeof(float *) * (m)); + for (l = 0; l < m; l++) { + refl[l] = (float *)malloc(sizeof(float) * (n)); + } + + for (j = 0; j < m; j++) { + for (i = 0; i < n; i++) + refl[j][i] = UNDEFZ; + } + } + + if (glob_rad != NULL) + { + globrad = (float **)malloc(sizeof(float *)*(m)); + for( l=0; l day + 5) + return 0; + else + return 1; +} Added: trunk/grassaddons/r.sun_horizon/r.sun2/rsunglobals.h =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/rsunglobals.h (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/rsunglobals.h 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,62 @@ +/******************************************************************************* +r.sun: rsunglobals.h. This program was writen by Jaro Hofierka in Summer 1993 and re-engineered +in 1996-1999. In cooperation with Marcel Suri and Thomas Huld from JRC in Ispra +a new version of r.sun was prepared using ESRA solar radiation formulas. +See manual pages for details. +(C) 2002 Copyright Jaro Hofierka, Gresaka 22, 085 01 Bardejov, Slovakia, + and GeoModel, s.r.o., Bratislava, Slovakia +email: hofierka@geomodel.sk,marcel.suri@jrc.it,suri@geomodel.sk +*******************************************************************************/ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*v. 2.0 July 2002, NULL data handling, JH */ +/*v. 2.1 January 2003, code optimization by Thomas Huld, JH */ + +#define EARTHRADIUS 6371000. +/* undefined value for terrain aspect */ +#define UNDEF 0. +/* internal undefined value for NULL */ +#define UNDEFZ -9999. + +/* Constant for calculating angular loss */ +#define a_r 0.155 + +extern int varCount_global; +extern int bitCount_global; +extern int arrayNumInt; + +/* +extern double xp; +extern double yp; +*/ + +extern double angular_loss_denom; + +extern const double invScale; +extern const double pihalf; +extern const double pi2; +extern const double deg2rad; +extern const double rad2deg; + +extern struct pj_info iproj; +extern struct pj_info oproj; + + +extern void (*func) (int, int); + Added: trunk/grassaddons/r.sun_horizon/r.sun2/rsunlib.c =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/rsunlib.c (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/rsunlib.c 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,699 @@ +/******************************************************************************* +r.sun: rsunlib.c. This program was writen by Jaro Hofierka in Summer 1993 and re-engineered +in 1996-1999. In cooperation with Marcel Suri and Thomas Huld from JRC in Ispra +a new version of r.sun was prepared using ESRA solar radiation formulas. +See manual pages for details. +(C) 2002 Copyright Jaro Hofierka, Gresaka 22, 085 01 Bardejov, Slovakia, + and GeoModel, s.r.o., Bratislava, Slovakia +email: hofierka@geomodel.sk,marcel.suri@jrc.it,suri@geomodel.sk +*******************************************************************************/ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*v. 2.0 July 2002, NULL data handling, JH */ +/*v. 2.1 January 2003, code optimization by Thomas Huld, JH */ + +#include +#include +#include +#include +#include +#include "sunradstruct.h" +#include "local_proto.h" +#include "rsunglobals.h" + + +int civilTimeFlag; +int useCivilTime() + { + return civilTimeFlag; + } +void setUseCivilTime(int val) + { + civilTimeFlag=val; + } + + +double angular_loss_denom; + +void setAngularLossDenominator() +{ + angular_loss_denom=1./(1-exp(-1./a_r)); + +} + + +int useShadowFlag; +int useShadow() + { + return useShadowFlag; + } +void setUseShadow(int val) + { + useShadowFlag=val; + } + + + +int useHorizonDataFlag; +int useHorizonData() + { + return useHorizonDataFlag; + } +void setUseHorizonData(int val) + { + useHorizonDataFlag=val; + } + +double timeOffset; +double getTimeOffset() + { + return timeOffset; + } +void setTimeOffset(double val) + { + timeOffset=val; + } + +double horizonInterval; +double getHorizonInterval() + { + return horizonInterval; + } +void setHorizonInterval(double val) + { + horizonInterval=val; + } + + + +double com_sol_const(int no_of_day) + { + double I0, d1; + + /* v W/(m*m) */ + d1 = pi2 * no_of_day / 365.25; + I0 = 1367. * (1 + 0.03344 * cos(d1 - 0.048869)); + + return I0; + } + + + + +void com_par_const(double longitTime, struct SunGeometryConstDay *sungeom, + struct GridGeometry *gridGeom) + { + double pom; + double totOffsetTime; + + sungeom->lum_C11 = gridGeom->sinlat * sungeom->cosdecl; + sungeom->lum_C13 = -gridGeom->coslat * sungeom->sindecl; + sungeom->lum_C22 = sungeom->cosdecl; + sungeom->lum_C31 = gridGeom->coslat * sungeom->cosdecl; + sungeom->lum_C33 = gridGeom->sinlat * sungeom->sindecl; + + if (fabs(sungeom->lum_C31) >= EPS) { + totOffsetTime = timeOffset + longitTime; + + if(useCivilTime()) + { + sungeom->timeAngle -= totOffsetTime*HOURANGLE; + } + pom = -sungeom->lum_C33 / sungeom->lum_C31; + if (fabs(pom) <= 1) { + pom = acos(pom); + pom = (pom * 180) / M_PI; + sungeom->sunrise_time = (90 - pom) / 15 + 6; + sungeom->sunset_time = (pom - 90) / 15 + 18; + } + else { + if (pom < 0) { + /* printf("\n Sun is ABOVE the surface during the whole day\n"); */ + sungeom->sunrise_time = 0; + sungeom->sunset_time = 24; + } + else { + /* printf("\n The sun is BELOW the surface during the whole day\n"); */ + if (fabs(pom) - 1 <= EPS) { + sungeom->sunrise_time = 12; + sungeom->sunset_time = 12; + } + } + } + } + +} + + + + + +void com_par( struct SunGeometryConstDay *sungeom, + struct SunGeometryVarDay *sunVarGeom, struct GridGeometry *gridGeom, + double latitude, double longitude) +{ + double pom, xpom, ypom; + + double costimeAngle; + double lum_Lx, lum_Ly; + + double newLatitude, newLongitude; + double inputAngle; + double delt_lat, delt_lon; + double delt_east, delt_nor; + double delt_dist; + + + costimeAngle = cos(sungeom->timeAngle); + + + + lum_Lx = -sungeom->lum_C22 * sin(sungeom->timeAngle); + lum_Ly = sungeom->lum_C11 * costimeAngle + sungeom->lum_C13; + sunVarGeom->sinSolarAltitude = sungeom->lum_C31 * costimeAngle + sungeom->lum_C33; + + if (fabs(sungeom->lum_C31) < EPS) + { + if (fabs(sunVarGeom->sinSolarAltitude) >= EPS) + { + if (sunVarGeom->sinSolarAltitude > 0) + { + /* printf("\tSun is ABOVE area during the whole day\n"); */ + sungeom->sunrise_time = 0; + sungeom->sunset_time = 24; + } + else + { + sunVarGeom->solarAltitude = 0.; + sunVarGeom->solarAzimuth = UNDEF; + return; + } + } + else + { + /* printf("\tThe Sun is ON HORIZON during the whole day\n"); */ + sungeom->sunrise_time = 0; + sungeom->sunset_time = 24; + } + } + + sunVarGeom->solarAltitude = asin(sunVarGeom->sinSolarAltitude); /* vertical angle of the sun */ + /* sinSolarAltitude is sin(solarAltitude) */ + + xpom = lum_Lx * lum_Lx; + ypom = lum_Ly * lum_Ly; + pom = sqrt(xpom + ypom); + + + if (fabs(pom) > EPS) + { + sunVarGeom->solarAzimuth = lum_Ly / pom; + sunVarGeom->solarAzimuth = acos(sunVarGeom->solarAzimuth); /* horiz. angle of the Sun */ + /* solarAzimuth *= RAD; */ + if (lum_Lx < 0) + sunVarGeom->solarAzimuth = pi2 - sunVarGeom->solarAzimuth; + } + else + { + sunVarGeom->solarAzimuth = UNDEF; + } + + + + if (sunVarGeom->solarAzimuth < 0.5 * M_PI) + sunVarGeom->sunAzimuthAngle = 0.5 * M_PI - sunVarGeom->solarAzimuth; + else + sunVarGeom->sunAzimuthAngle = 2.5 * M_PI - sunVarGeom->solarAzimuth; + + + inputAngle=sunVarGeom->sunAzimuthAngle+pihalf; + inputAngle=(inputAngle>=pi2)?inputAngle-pi2:inputAngle; + + + delt_lat = -0.0001*cos(inputAngle); /* Arbitrary small distance in latitude */ + delt_lon = 0.0001*sin(inputAngle)/cos(latitude); + + newLatitude = (latitude+delt_lat)*rad2deg; + newLongitude = (longitude+delt_lon)*rad2deg; + + + if ((G_projection() != PROJECTION_LL)) + { + if (pj_do_proj(&newLongitude, &newLatitude, &oproj, &iproj) <0) + { + G_fatal_error("Error in pj_do_proj"); + } + } + + delt_east=newLongitude-gridGeom->xp; + delt_nor=newLatitude-gridGeom->yp; + + delt_dist=sqrt(delt_east*delt_east+delt_nor*delt_nor); + + + + sunVarGeom->stepsinangle = gridGeom->stepxy*delt_nor/delt_dist; + sunVarGeom->stepcosangle = gridGeom->stepxy*delt_east/delt_dist; + +/* + sunVarGeom->stepsinangle = stepxy * sin(sunVarGeom->sunAzimuthAngle); + sunVarGeom->stepcosangle = stepxy * cos(sunVarGeom->sunAzimuthAngle); +*/ + sunVarGeom->tanSolarAltitude = tan(sunVarGeom->solarAltitude); + + return; + +} + + +int searching(double *length, struct SunGeometryVarDay *sunVarGeom, + struct GridGeometry *gridGeom) +{ + double z2; + double curvature_diff; + int succes = 0; + + if (sunVarGeom->zp == UNDEFZ) + return 0; + + + gridGeom->yy0 += sunVarGeom->stepsinangle; + gridGeom->xx0 += sunVarGeom->stepcosangle; + if (((gridGeom->xx0+(0.5*gridGeom->stepx)) < 0) + || ((gridGeom->xx0+(0.5*gridGeom->stepx)) > gridGeom->deltx) + || ((gridGeom->yy0+(0.5*gridGeom->stepy)) < 0) + || ((gridGeom->yy0+(0.5*gridGeom->stepy)) > gridGeom->delty)) + succes=3; + else + succes=1; + + + if (succes == 1) + { + where_is_point(length, sunVarGeom,gridGeom); + if (func == NULL) + { + gridGeom->xx0 = gridGeom->xg0; + gridGeom->yy0 = gridGeom->yg0; + return (3); + } + curvature_diff = EARTHRADIUS*(1.-cos(*length/EARTHRADIUS)); + + z2 = sunVarGeom->z_orig + curvature_diff + *length * sunVarGeom->tanSolarAltitude; + if (z2 < sunVarGeom->zp) + succes = 2; /* shadow */ + if (z2 > sunVarGeom->zmax) + succes = 3; /* no test needed all visible */ + } + + if(succes!=1) + { + gridGeom->xx0 = gridGeom->xg0; + gridGeom->yy0 = gridGeom->yg0; + } + return (succes); +} + + + + +double lumcline2( + struct SunGeometryConstDay *sungeom, + struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct GridGeometry *gridGeom, + unsigned char *horizonpointer) + { + double s = 0; + double length; + int r = 0; + + int lowPos, highPos; + double timeoffset, horizPos; + double horizonHeight; + + func = cube; + sunVarGeom->isShadow = 0; + + if (useShadow()) + { + length = 0; + + if(useHorizonData()) + { + /* Start is due east, sungeom->timeangle = -pi/2 */ +/* + timeoffset = sungeom->timeAngle+pihalf; +*/ + timeoffset = sunVarGeom->sunAzimuthAngle; + +/* + if(timeoffset<0.) + timeoffset+=pi2; + else if(timeoffset>pi2) + timeoffset-=pi2; + horizPos = arrayNumInt - timeoffset/horizonInterval; +*/ + + horizPos = timeoffset/getHorizonInterval(); + + + lowPos = (int)horizPos; + highPos=lowPos+1; + if(highPos==arrayNumInt) + { + highPos=0; + } + horizonHeight = invScale*( + (1.-(horizPos-lowPos))*horizonpointer[lowPos] + +(horizPos-lowPos) + *horizonpointer[highPos]); + sunVarGeom->isShadow = (horizonHeight>sunVarGeom->solarAltitude); + + if (!sunVarGeom->isShadow) + { +/* + if (z_orig != UNDEFZ) + { + s = sunSlopeGeom->lum_C31_l * cos(-sungeom->timeAngle - sunSlopeGeom->longit_l) + sunSlopeGeom->lum_C33_l; + + } + else + { + s = sunVarGeom->sinSolarAltitude; + } +*/ + s = sunSlopeGeom->lum_C31_l * cos(-sungeom->timeAngle - sunSlopeGeom->longit_l) + sunSlopeGeom->lum_C33_l; /* Jenco */ + } + + + } /* End if useHorizonData() */ + else + { + while ((r = searching(&length, sunVarGeom, gridGeom)) == 1) + { + if (r == 3) + break; /* no test is needed */ + } + + + + + if (r == 2) + { + sunVarGeom->isShadow = 1; /* shadow */ + } + else + { + +/* + if (z_orig != UNDEFZ) + { + + s = sunSlopeGeom->lum_C31_l * cos(-sungeom->timeAngle - sunSlopeGeom->longit_l) + sunSlopeGeom->lum_C33_l; + } + else + { + s = sunVarGeom->sinSolarAltitude; + } +*/ + s = sunSlopeGeom->lum_C31_l * cos(-sungeom->timeAngle - sunSlopeGeom->longit_l) + sunSlopeGeom->lum_C33_l; /* Jenco */ + } + } + } + else + { + /* + if (z_orig != UNDEFZ) + { + s = sunSlopeGeom->lum_C31_l * cos(-sungeom->timeAngle - sunSlopeGeom->longit_l) + sunSlopeGeom->lum_C33_l; + } + else + { + s = sunVarGeom->sinSolarAltitude; + } +*/ + s = sunSlopeGeom->lum_C31_l * cos(-sungeom->timeAngle - sunSlopeGeom->longit_l) + sunSlopeGeom->lum_C33_l; /* Jenco */ + + + } + + if (s < 0) return 0.; + return (s); + } + + + +double brad(double sh, double *bh, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar) +{ + double opticalAirMass, airMass2Linke, rayl, br; + double drefract, temp1, temp2, h0refract; + double elevationCorr; + + double locSolarAltitude; + + locSolarAltitude=sunVarGeom->solarAltitude; + + + elevationCorr = exp(-sunVarGeom->z_orig / 8434.5); + temp1 = 0.1594 + locSolarAltitude * (1.123 + 0.065656 * locSolarAltitude); + temp2 = 1. + locSolarAltitude * (28.9344 + 277.3971 * locSolarAltitude); + drefract = 0.061359 * temp1 / temp2; /* in radians */ + h0refract = locSolarAltitude + drefract; + opticalAirMass = elevationCorr / (sin(h0refract) + + 0.50572 * pow(h0refract * rad2deg + 6.07995, -1.6364)); + airMass2Linke = 0.8662 * sunRadVar->linke; + if (opticalAirMass <= 20.) + { + rayl = 1. / (6.6296 + + opticalAirMass * (1.7513 + + opticalAirMass * (-0.1202 + opticalAirMass * (0.0065 - opticalAirMass * 0.00013)))); + } + else + { + rayl = 1. / (10.4 + 0.718 * opticalAirMass); + } + *bh = sunRadVar->cbh * sunRadVar->G_norm_extra * sunVarGeom->sinSolarAltitude * exp(-rayl * opticalAirMass * airMass2Linke); + if (sunSlopeGeom->aspect != UNDEF && sunSlopeGeom->slope != 0.) + br = *bh * sh / sunVarGeom->sinSolarAltitude; + else + br = *bh; + + return (br); +} + +double brad_angle_loss(double sh, double *bh, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar) +{ + double p, opticalAirMass, airMass2Linke, rayl, br; + double drefract, temp1, temp2, h0refract; + + double locSolarAltitude; + + locSolarAltitude=sunVarGeom->solarAltitude; + + + p = exp(-sunVarGeom->z_orig / 8434.5); + temp1 = 0.1594 + locSolarAltitude * (1.123 + 0.065656 * locSolarAltitude); + temp2 = 1. + locSolarAltitude * (28.9344 + 277.3971 * locSolarAltitude); + drefract = 0.061359 * temp1 / temp2; /* in radians */ + h0refract = locSolarAltitude + drefract; + opticalAirMass = p / (sin(h0refract) + + 0.50572 * pow(h0refract * rad2deg + 6.07995, -1.6364)); + airMass2Linke = 0.8662 * sunRadVar->linke; + if (opticalAirMass <= 20.) + rayl = + 1. / (6.6296 + + opticalAirMass * (1.7513 + + opticalAirMass * (-0.1202 + opticalAirMass * (0.0065 - opticalAirMass * 0.00013)))); + else + rayl = 1. / (10.4 + 0.718 * opticalAirMass); + *bh = sunRadVar->cbh * sunRadVar->G_norm_extra * sunVarGeom->sinSolarAltitude * exp(-rayl * opticalAirMass * airMass2Linke); + if (sunSlopeGeom->aspect != UNDEF && sunSlopeGeom->slope != 0.) + br = *bh * sh / sunVarGeom->sinSolarAltitude; + else + br = *bh; + + br *= (1-exp(-sh/a_r))*angular_loss_denom; + + return (br); +} + + + +double drad(double sh, double bh, double *rr, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar) +{ + double tn, fd, fx = 0., A1, A2, A3, A1b; + double r_sky, kb, dr, gh, a_ln, ln, fg; + double dh; + double cosslope, sinslope; + double locSinSolarAltitude; + double locLinke; + + locLinke = sunRadVar->linke; + locSinSolarAltitude=sunVarGeom->sinSolarAltitude; + + cosslope = cos(sunSlopeGeom->slope); + sinslope = sin(sunSlopeGeom->slope); + + tn = -0.015843 + locLinke * (0.030543 + 0.0003797 * locLinke); + A1b = 0.26463 + locLinke * (-0.061581 + 0.0031408 * locLinke); + if (A1b * tn < 0.0022) + A1 = 0.0022 / tn; + else + A1 = A1b; + A2 = 2.04020 + locLinke * (0.018945 - 0.011161 * locLinke); + A3 = -1.3025 + locLinke * (0.039231 + 0.0085079 * locLinke); + + fd = A1 + A2 * locSinSolarAltitude + A3 * locSinSolarAltitude * locSinSolarAltitude; + dh = sunRadVar->cdh * sunRadVar->G_norm_extra * fd * tn; + gh = bh + dh; + if (sunSlopeGeom->aspect != UNDEF && sunSlopeGeom->slope != 0.) { + kb = bh / (sunRadVar->G_norm_extra * locSinSolarAltitude); + r_sky = (1. + cosslope) / 2.; + a_ln = sunVarGeom->solarAzimuth - sunSlopeGeom->aspect; + ln = a_ln; + if (a_ln > M_PI) + ln = a_ln - pi2; + else if (a_ln < -M_PI) + ln = a_ln + pi2; + a_ln = ln; + fg = sinslope - sunSlopeGeom->slope * cosslope - + M_PI * sin(0.5*sunSlopeGeom->slope) * sin(0.5*sunSlopeGeom->slope); + if ((sunVarGeom->isShadow == 1) || sh <= 0.) + fx = r_sky + fg * 0.252271; + else if (sunVarGeom->solarAltitude >= 0.1) { + fx = ((0.00263 - kb * (0.712 + 0.6883 * kb)) * fg + r_sky) * (1. - + kb) + + kb * sh / locSinSolarAltitude; + } + else if (sunVarGeom->solarAltitude < 0.1) + fx = ((0.00263 - 0.712 * kb - 0.6883 * kb * kb) * fg + + r_sky) * (1. - kb) + kb * sinslope * cos(a_ln) / (0.1 - + 0.008 * + sunVarGeom->solarAltitude); + dr = dh * fx; + /* refl. rad */ + *rr = sunRadVar->alb * gh * (1 - cosslope) / 2.; + } + else { /* plane */ + dr = dh; + *rr = 0.; + } + return (dr); +} + +#define c2 -0.074 + +double drad_angle_loss(double sh, double bh, double *rr, struct SunGeometryVarDay *sunVarGeom, + struct SunGeometryVarSlope *sunSlopeGeom, + struct SolarRadVar *sunRadVar) +{ + double dh; + double tn, fd, fx = 0., A1, A2, A3, A1b; + double r_sky, kb, dr, gh, a_ln, ln, fg; + double cosslope, sinslope; + + double diff_coeff_angleloss; + double refl_coeff_angleloss; + double c1; + double diff_loss_factor, refl_loss_factor; + double locSinSolarAltitude; + double locLinke; + + locSinSolarAltitude=sunVarGeom->sinSolarAltitude; + locLinke = sunRadVar->linke; + cosslope = cos(sunSlopeGeom->slope); + sinslope = sin(sunSlopeGeom->slope); + + + tn = -0.015843 + locLinke * (0.030543 + 0.0003797 * locLinke); + A1b = 0.26463 + locLinke * (-0.061581 + 0.0031408 * locLinke); + if (A1b * tn < 0.0022) + A1 = 0.0022 / tn; + else + A1 = A1b; + A2 = 2.04020 + locLinke * (0.018945 - 0.011161 * locLinke); + A3 = -1.3025 + locLinke * (0.039231 + 0.0085079 * locLinke); + + fd = A1 + A2 * locSinSolarAltitude + A3 * locSinSolarAltitude * locSinSolarAltitude; + dh = sunRadVar->cdh * sunRadVar->G_norm_extra * fd * tn; + gh = bh + dh; + if (sunSlopeGeom->aspect != UNDEF && sunSlopeGeom->slope != 0.) { + kb = bh / (sunRadVar->G_norm_extra * locSinSolarAltitude); + r_sky = (1. + cosslope) / 2.; + a_ln = sunVarGeom->solarAzimuth - sunSlopeGeom->aspect; + ln = a_ln; + if (a_ln > M_PI) + ln = a_ln - pi2; + else if (a_ln < -M_PI) + ln = a_ln + pi2; + a_ln = ln; + fg = sinslope - sunSlopeGeom->slope * cosslope - + M_PI * sin(sunSlopeGeom->slope / 2.) * sin(sunSlopeGeom->slope / 2.); + if ((sunVarGeom->isShadow) || (sh <= 0.)) + fx = r_sky + fg * 0.252271; + else if (sunVarGeom->solarAltitude >= 0.1) { + fx = ((0.00263 - kb * (0.712 + 0.6883 * kb)) * fg + r_sky) * (1. - + kb) + + kb * sh / locSinSolarAltitude; + } + else if (sunVarGeom->solarAltitude < 0.1) + fx = ((0.00263 - 0.712 * kb - 0.6883 * kb * kb) * fg + + r_sky) * (1. - kb) + kb * sinslope * cos(a_ln) / (0.1 - + 0.008 * + sunVarGeom->solarAltitude); + dr = dh * fx; + /* refl. rad */ + *rr = sunRadVar->alb * gh * (1 - cosslope) / 2.; + } + else { /* plane */ + dr = dh; + *rr = 0.; + } + + c1 = 4./(3.*M_PI); + diff_coeff_angleloss = sinslope + + (M_PI-sunSlopeGeom->slope-sinslope)/(1+cosslope); + refl_coeff_angleloss = sinslope + + (sunSlopeGeom->slope-sinslope)/(1-cosslope); + + diff_loss_factor + = 1. - exp(-(c1*diff_coeff_angleloss + +c2*diff_coeff_angleloss*diff_coeff_angleloss) + /a_r); + refl_loss_factor + = 1. - exp(-(c1*refl_coeff_angleloss + +c2*refl_coeff_angleloss*refl_coeff_angleloss) + /a_r); + + dr *= diff_loss_factor; + *rr *= refl_loss_factor; + + + + return (dr); +} + + Added: trunk/grassaddons/r.sun_horizon/r.sun2/sunradstruct.h =================================================================== --- trunk/grassaddons/r.sun_horizon/r.sun2/sunradstruct.h (rev 0) +++ trunk/grassaddons/r.sun_horizon/r.sun2/sunradstruct.h 2007-10-09 10:33:54 UTC (rev 1129) @@ -0,0 +1,109 @@ +/******************************************************************************* +r.sun: sunradstruct.h. This program was writen by Jaro Hofierka in Summer 1993 and re-engineered +in 1996-1999. In cooperation with Marcel Suri and Thomas Huld from JRC in Ispra +a new version of r.sun was prepared using ESRA solar radiation formulas. +See manual pages for details. +(C) 2002 Copyright Jaro Hofierka, Gresaka 22, 085 01 Bardejov, Slovakia, + and GeoModel, s.r.o., Bratislava, Slovakia +email: hofierka@geomodel.sk,marcel.suri@jrc.it,suri@geomodel.sk +*******************************************************************************/ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*v. 2.0 July 2002, NULL data handling, JH */ +/*v. 2.1 January 2003, code optimization by Thomas Huld, JH */ + +#define EPS 1.e-4 +#define HOURANGLE M_PI/12. + + +struct SunGeometryConstDay + { + double lum_C11; + double lum_C13; + double lum_C22; + double lum_C31; + double lum_C33; + double sunrise_time; + double sunset_time; + double timeAngle; + double sindecl; + double cosdecl; + + }; + + +struct SunGeometryVarDay + { + int isShadow; + double z_orig; + double zmax; + double zp; + double solarAltitude; + double sinSolarAltitude; + double tanSolarAltitude; + double solarAzimuth; + double sunAzimuthAngle; + double stepsinangle; + double stepcosangle; + + }; + + +struct SunGeometryVarSlope + { + double longit_l; /* The "longitude" difference between the inclined */ + /* and orientated plane and the instantaneous solar position */ + double lum_C31_l; + double lum_C33_l; + double slope; + double aspect; + + }; + + + +struct SolarRadVar + { + double cbh; + double cdh; + double linke; + double G_norm_extra; + double alb; + + }; + + + +struct GridGeometry + { + double xp; + double yp; + double xx0; + double yy0; + double xg0; + double yg0; + double stepx; + double stepy; + double deltx; + double delty; + double stepxy; + double sinlat; + double coslat; + + }; From landa at grass.itc.it Tue Oct 9 20:37:40 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 9 20:37:42 2007 Subject: [grass-addons] r1130 - trunk/grassaddons/gui/gui_modules Message-ID: <200710091837.l99Ibeci023637@grass.itc.it> Author: landa Date: 2007-10-09 20:37:36 +0200 (Tue, 09 Oct 2007) New Revision: 1130 Modified: trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/render.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Digitization tool: Fix copying features from background map. Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-09 10:33:54 UTC (rev 1129) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-09 18:37:36 UTC (rev 1130) @@ -69,7 +69,7 @@ if not settings: self.settings = {} # symbology -# self.settings["symbolBackground"] = (None, (255,255,255, 255)) # white + # self.settings["symbolBackground"] = (None, (255,255,255, 255)) # white self.settings["symbolHighlight"] = (None, (255, 255, 0, 255)) #yellow self.settings["symbolPoint"] = (True, (0, 0, 0, 255)) # black self.settings["symbolLine"] = (True, (0, 0, 0, 255)) # black @@ -89,7 +89,7 @@ # snapping self.settings["snapping"] = (10, "screen pixels") # value, unit self.settings["snapToVertex"] = False - self.settings["backgroundMap"] = 'a1@martin' + self.settings["backgroundMap"] = '' # digitize new record self.settings["addRecord"] = True @@ -181,7 +181,7 @@ Debug.msg (4, "Vline.AddPoint(): input=%s" % addstring) - self._AddFeature (map=map, input=addstring) + self.__AddFeature (map=map, input=addstring) def AddLine (self, map, type, coords): """ @@ -215,9 +215,9 @@ Debug.msg (4, "VEdit.AddLine(): input=%s" % addstring) - self._AddFeature (map=map, input=addstring, flags=flags) + self.__AddFeature (map=map, input=addstring, flags=flags) - def _AddFeature (self, map, input, flags=[]): + def __AddFeature (self, map, input, flags=[]): """ General method which adds feature to the vector map """ @@ -244,7 +244,7 @@ command.append(flag) # run the command - Debug.msg(4, "VEdit._AddFeature(): input=%s" % input) + Debug.msg(4, "VEdit.AddFeature(): input=%s" % input) vedit = gcmd.Command(cmd=command, stdin=input) # reload map (needed for v.edit) @@ -489,22 +489,20 @@ Debug.msg(4, "VEdit.SelectLinesFromBackgroundMap(): []") return [] - print "#", pos1, pos2 x1, y1 = pos1 x2, y2 = pos2 vEditCmd = gcmd.Command(['v.edit', '--q', - 'map=%s' % self.map, + 'map=%s' % self.settings['backgroundMap'], 'tool=select', # 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1])]) 'polygon=%f,%f,%f,%f,%f,%f,%f,%f,%f,%f' % \ (x1, y1, x2, y1, x2, y2, x1, y2, x1, y1)]) - + try: - output = vEditCmd.ReadStdOutput()[0][0] - print "#", output - ids = output.split(',') #first line & item in list + output = vEditCmd.ReadStdOutput()[0] # first line + ids = output.split(',') ids = map(int, ids) # str -> int except: return [] Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-09 10:33:54 UTC (rev 1129) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-09 18:37:36 UTC (rev 1130) @@ -46,10 +46,9 @@ sys.path.append(CompatPath) from compat import subprocess -gmpath = os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ) -sys.path.append(gmpath) -gmpath = os.path.join( os.getenv("GISBASE"),"etc","wx","icons" ) -sys.path.append(gmpath) +for gmpath in [os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ), + os.path.join( os.getenv("GISBASE"),"etc","wx","icons" )]: + sys.path.append(gmpath) import render import toolbars @@ -60,9 +59,9 @@ import disp_print import gcmd import dbm -import defaultfont as defaultfont -import histogram as histogram -import profile as profile +import defaultfont +import histogram +import profile from digit import Digit as Digit from digit import DigitCategoryDialog as DigitCategoryDialog from debug import Debug as Debug @@ -953,6 +952,7 @@ self.mouse['box'] = 'box' elif digitToolbar.action == "copyLine": self.copyIds = None + self.layerTmp = None else: # get decoration id self.lastpos = self.mouse['begin'] @@ -1099,10 +1099,22 @@ if nselected > 0: # highlight selected features self.UpdateMap(render=False) + else: + self.UpdateMap(render=False, renderVector=False) else: # copy features from background map self.copyIds = self.parent.digit.SelectLinesFromBackgroundMap(pos1, pos2) - self.UpdateMap(render=False, renderVector=False) + if len(self.copyIds) > 0: + dVectTmp = ['d.vect', + 'map=%s' % self.parent.digit.settings['backgroundMap'], + 'cats=%s' % ",".join(["%d" % v for v in self.copyIds]), + '-i', + 'color=yellow'] + self.layerTmp = self.Map.AddLayer(type='vector', + command=dVectTmp) + self.UpdateMap(render=True, renderVector=False) + else: + self.UpdateMap(render=False, renderVector=False) elif self.dragid != None: # end drag of overlay decoration @@ -1313,6 +1325,10 @@ elif digit.action == "copyLine": self.parent.digit.CopyLine(self.copyIds) del self.copyIds + if self.layerTmp: + self.Map.DeleteLayer(self.layerTmp) + self.UpdateMap(render=True, renderVector=False) + del self.layerTmp if digit.action != "addLine": self.parent.digit.driver.Unselect() @@ -1369,6 +1385,10 @@ pass elif digit.action == "copyLine": del self.copyIds + if self.layerTmp: + self.Map.DeleteLayer(self.layerTmp) + self.UpdateMap(render=True, renderVector=False) + del self.layerTmp self.UpdateMap(render=False) # render map Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-10-09 10:33:54 UTC (rev 1129) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-10-09 18:37:36 UTC (rev 1130) @@ -29,7 +29,7 @@ Common layer attributes: type - layer type (raster, vector, overlay, command, etc.) name - layer name, e.g. map name ('elevation@PERMANENT') - cmdlist - GRASS command (e.g. 'd.rast map=elevation@PERMANENT') + cmdlist - GRASS command (e.g. ['d.rast', 'map=elevation@PERMANENT']) active - layer is active, will be rendered only if True hidden - layer is hidden, won't be listed in GIS Manager if True Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-09 10:33:54 UTC (rev 1129) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-09 18:37:36 UTC (rev 1130) @@ -325,7 +325,7 @@ wx.ITEM_RADIO, Icons["digDispAttr"].GetLabel(), Icons["digDispAttr"].GetDesc(), self.OnDisplayAttr), (self.additioanlTools, "digAdditionalTools", Icons["digAdditionalTools"].GetBitmap(), - wx.ITEM_NORMAL, Icons["digAdditionalTools"].GetLabel(), + wx.ITEM_RADIO, Icons["digAdditionalTools"].GetLabel(), Icons["digAdditionalTools"].GetDesc(), self.OnAdditionalToolMenu)) From landa at grass.itc.it Fri Oct 12 17:05:19 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 12 17:05:21 2007 Subject: [grass-addons] r1131 - trunk/grassaddons/gui/display_driver Message-ID: <200710121505.l9CF5JaW015648@grass.itc.it> Author: landa Date: 2007-10-12 17:05:12 +0200 (Fri, 12 Oct 2007) New Revision: 1131 Added: trunk/grassaddons/gui/display_driver/pseudodc.h Log: Added header for pseudodc.h (should be removed in the future). Added: trunk/grassaddons/gui/display_driver/pseudodc.h =================================================================== --- trunk/grassaddons/gui/display_driver/pseudodc.h (rev 0) +++ trunk/grassaddons/gui/display_driver/pseudodc.h 2007-10-12 15:05:12 UTC (rev 1131) @@ -0,0 +1,814 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: pseudodc.h +// Purpose: wxPseudoDC class +// Author: Paul Lanier +// Modified by: +// Created: 05/25/06 +// RCS-ID: $Id: pseudodc.h,v 1.5 2006/10/11 04:01:29 RD Exp $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// +#ifndef _WX_PSUEDO_DC_H_BASE_ +#define _WX_PSUEDO_DC_H_BASE_ + +//---------------------------------------------------------------------------- +// Base class for all pdcOp classes +//---------------------------------------------------------------------------- +class pdcOp +{ + public: + // Constructor and Destructor + pdcOp() {} + virtual ~pdcOp() {} + + // Virtual Drawing Methods + virtual void DrawToDC(wxDC *dc, bool grey=false)=0; + virtual void Translate(wxCoord WXUNUSED(dx), wxCoord WXUNUSED(dy)) {} + virtual void CacheGrey() {} +}; + +//---------------------------------------------------------------------------- +// declare a list class for list of pdcOps +//---------------------------------------------------------------------------- +WX_DECLARE_LIST(pdcOp, pdcOpList); + + +//---------------------------------------------------------------------------- +// Helper functions used for drawing greyed out versions of objects +//---------------------------------------------------------------------------- +wxColour &MakeColourGrey(const wxColour &c); +wxBrush &GetGreyBrush(wxBrush &brush); +wxPen &GetGreyPen(wxPen &pen); +wxIcon &GetGreyIcon(wxIcon &icon); +wxBitmap &GetGreyBitmap(wxBitmap &bmp); + +//---------------------------------------------------------------------------- +// Classes derived from pdcOp +// There is one class for each method mirrored from wxDC to wxPseudoDC +//---------------------------------------------------------------------------- +class pdcSetFontOp : public pdcOp +{ + public: + pdcSetFontOp(const wxFont& font) + {m_font=font;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->SetFont(m_font);} + protected: + wxFont m_font; +}; + +class pdcSetBrushOp : public pdcOp +{ + public: + pdcSetBrushOp(const wxBrush& brush) + {m_greybrush=m_brush=brush;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (!grey) dc->SetBrush(m_brush); + else dc->SetBrush(m_greybrush); + } + virtual void CacheGrey() {m_greybrush=GetGreyBrush(m_brush);} + protected: + wxBrush m_brush; + wxBrush m_greybrush; +}; + +class pdcSetBackgroundOp : public pdcOp +{ + public: + pdcSetBackgroundOp(const wxBrush& brush) + {m_greybrush=m_brush=brush;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (!grey) dc->SetBackground(m_brush); + else dc->SetBackground(m_greybrush); + } + virtual void CacheGrey() {m_greybrush=GetGreyBrush(m_brush);} + protected: + wxBrush m_brush; + wxBrush m_greybrush; +}; + +class pdcSetPenOp : public pdcOp +{ + public: + pdcSetPenOp(const wxPen& pen) + {m_greypen=m_pen=pen;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (!grey) dc->SetPen(m_pen); + else dc->SetPen(m_greypen); + } + virtual void CacheGrey() {m_greypen=GetGreyPen(m_pen);} + protected: + wxPen m_pen; + wxPen m_greypen; +}; + +class pdcSetTextBackgroundOp : public pdcOp +{ + public: + pdcSetTextBackgroundOp(const wxColour& colour) + {m_colour=colour;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (!grey) dc->SetTextBackground(m_colour); + else dc->SetTextBackground(MakeColourGrey(m_colour)); + } + protected: + wxColour m_colour; +}; + +class pdcSetTextForegroundOp : public pdcOp +{ + public: + pdcSetTextForegroundOp(const wxColour& colour) + {m_colour=colour;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (!grey) dc->SetTextForeground(m_colour); + else dc->SetTextForeground(MakeColourGrey(m_colour)); + } + protected: + wxColour m_colour; +}; + +class pdcDrawRectangleOp : public pdcOp +{ + public: + pdcDrawRectangleOp(wxCoord x, wxCoord y, wxCoord w, wxCoord h) + {m_x=x; m_y=y; m_w=w; m_h=h;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawRectangle(m_x,m_y,m_w,m_h);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx;m_y+=dy;} + protected: + wxCoord m_x,m_y,m_w,m_h; +}; + +class pdcDrawLineOp : public pdcOp +{ + public: + pdcDrawLineOp(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) + {m_x1=x1; m_y1=y1; m_x2=x2; m_y2=y2;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawLine(m_x1,m_y1,m_x2,m_y2);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x1+=dx; m_y1+=dy; m_x2+=dx; m_y2+=dy;} + protected: + wxCoord m_x1,m_y1,m_x2,m_y2; +}; + +class pdcSetBackgroundModeOp : public pdcOp +{ + public: + pdcSetBackgroundModeOp(int mode) {m_mode=mode;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->SetBackgroundMode(m_mode);} + protected: + int m_mode; +}; + +class pdcDrawTextOp : public pdcOp +{ + public: + pdcDrawTextOp(const wxString& text, wxCoord x, wxCoord y) + {m_text=text; m_x=x; m_y=y;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawText(m_text, m_x, m_y);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxString m_text; + wxCoord m_x, m_y; +}; + +class pdcClearOp : public pdcOp +{ + public: + pdcClearOp() {} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->Clear();} +}; + +class pdcBeginDrawingOp : public pdcOp +{ + public: + pdcBeginDrawingOp() {} + virtual void DrawToDC(wxDC *WXUNUSED(dc), bool WXUNUSED(grey)=false) {} +}; + +class pdcEndDrawingOp : public pdcOp +{ + public: + pdcEndDrawingOp() {} + virtual void DrawToDC(wxDC *WXUNUSED(dc), bool WXUNUSED(grey)=false) {} +}; + +class pdcFloodFillOp : public pdcOp +{ + public: + pdcFloodFillOp(wxCoord x, wxCoord y, const wxColour& col, + int style) {m_x=x; m_y=y; m_col=col; m_style=style;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (!grey) dc->FloodFill(m_x,m_y,m_col,m_style); + else dc->FloodFill(m_x,m_y,MakeColourGrey(m_col),m_style); + } + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y; + wxColour m_col; + int m_style; +}; + +class pdcCrossHairOp : public pdcOp +{ + public: + pdcCrossHairOp(wxCoord x, wxCoord y) {m_x=x; m_y=y;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->CrossHair(m_x,m_y);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y; +}; + +class pdcDrawArcOp : public pdcOp +{ + public: + pdcDrawArcOp(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, + wxCoord xc, wxCoord yc) + {m_x1=x1; m_y1=y1; m_x2=x2; m_y2=y2; m_xc=xc; m_yc=yc;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) + {dc->DrawArc(m_x1,m_y1,m_x2,m_y2,m_xc,m_yc);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x1+=dx; m_x2+=dx; m_y1+=dy; m_y2+=dy;} + protected: + wxCoord m_x1,m_x2,m_xc; + wxCoord m_y1,m_y2,m_yc; +}; + +class pdcDrawCheckMarkOp : public pdcOp +{ + public: + pdcDrawCheckMarkOp(wxCoord x, wxCoord y, + wxCoord width, wxCoord height) + {m_x=x; m_y=y; m_w=width; m_h=height;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) + {dc->DrawCheckMark(m_x,m_y,m_w,m_h);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y,m_w,m_h; +}; + +class pdcDrawEllipticArcOp : public pdcOp +{ + public: + pdcDrawEllipticArcOp(wxCoord x, wxCoord y, wxCoord w, wxCoord h, + double sa, double ea) + {m_x=x; m_y=y; m_w=w; m_h=h; m_sa=sa; m_ea=ea;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) + {dc->DrawEllipticArc(m_x,m_y,m_w,m_h,m_sa,m_ea);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y,m_w,m_h; + double m_sa,m_ea; +}; + +class pdcDrawPointOp : public pdcOp +{ + public: + pdcDrawPointOp(wxCoord x, wxCoord y) + {m_x=x; m_y=y;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawPoint(m_x,m_y);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y; +}; + +class pdcDrawRoundedRectangleOp : public pdcOp +{ + public: + pdcDrawRoundedRectangleOp(wxCoord x, wxCoord y, wxCoord width, + wxCoord height, double radius) + {m_x=x; m_y=y; m_w=width; m_h=height; m_r=radius;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) + {dc->DrawRoundedRectangle(m_x,m_y,m_w,m_h,m_r);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y,m_w,m_h; + double m_r; +}; + +class pdcDrawEllipseOp : public pdcOp +{ + public: + pdcDrawEllipseOp(wxCoord x, wxCoord y, wxCoord width, wxCoord height) + {m_x=x; m_y=y; m_w=width; m_h=height;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawEllipse(m_x,m_y,m_w,m_h);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxCoord m_x,m_y,m_w,m_h; +}; + +class pdcDrawIconOp : public pdcOp +{ + public: + pdcDrawIconOp(const wxIcon& icon, wxCoord x, wxCoord y) + {m_icon=icon; m_x=x; m_y=y;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (grey) dc->DrawIcon(m_greyicon,m_x,m_y); + else dc->DrawIcon(m_icon,m_x,m_y); + } + virtual void CacheGrey() {m_greyicon=GetGreyIcon(m_icon);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxIcon m_icon; + wxIcon m_greyicon; + wxCoord m_x,m_y; +}; + +class pdcDrawLinesOp : public pdcOp +{ + public: + pdcDrawLinesOp(int n, wxPoint points[], + wxCoord xoffset = 0, wxCoord yoffset = 0); + virtual ~pdcDrawLinesOp(); + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) + {dc->DrawLines(m_n,m_points,m_xoffset,m_yoffset);} + virtual void Translate(wxCoord dx, wxCoord dy) + { + for(int i=0; iDrawPolygon(m_n,m_points,m_xoffset,m_yoffset,m_fillStyle);} + + virtual void Translate(wxCoord dx, wxCoord dy) + { + for(int i=0; iDrawPolyPolygon(m_n,m_count,m_points, + m_xoffset,m_yoffset,m_fillStyle);} + virtual void Translate(wxCoord dx, wxCoord dy) + { + for(int i=0; iDrawRotatedText(m_text,m_x,m_y,m_angle);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxString m_text; + wxCoord m_x,m_y; + double m_angle; +}; + +class pdcDrawBitmapOp : public pdcOp +{ + public: + pdcDrawBitmapOp(const wxBitmap &bmp, wxCoord x, wxCoord y, + bool useMask = false) + {m_bmp=bmp; m_x=x; m_y=y; m_useMask=useMask;} + virtual void DrawToDC(wxDC *dc, bool grey=false) + { + if (grey) dc->DrawBitmap(m_greybmp,m_x,m_y,m_useMask); + else dc->DrawBitmap(m_bmp,m_x,m_y,m_useMask); + } + virtual void CacheGrey() {m_greybmp=GetGreyBitmap(m_bmp);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_x+=dx; m_y+=dy;} + protected: + wxBitmap m_bmp; + wxBitmap m_greybmp; + wxCoord m_x,m_y; + bool m_useMask; +}; + +class pdcDrawLabelOp : public pdcOp +{ + public: + pdcDrawLabelOp(const wxString& text, + const wxBitmap& image, + const wxRect& rect, + int alignment = wxALIGN_LEFT | wxALIGN_TOP, + int indexAccel = -1) + {m_text=text; m_image=image; m_rect=rect; + m_align=alignment; m_iAccel=indexAccel;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) + {dc->DrawLabel(m_text,m_image,m_rect,m_align,m_iAccel);} + virtual void Translate(wxCoord dx, wxCoord dy) + {m_rect.x+=dx; m_rect.y+=dy;} + protected: + wxString m_text; + wxBitmap m_image; + wxRect m_rect; + int m_align; + int m_iAccel; +}; + +#if wxUSE_SPLINES +class pdcDrawSplineOp : public pdcOp +{ + public: + pdcDrawSplineOp(int n, wxPoint points[]); + virtual ~pdcDrawSplineOp(); + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->DrawSpline(m_n,m_points);} + virtual void Translate(wxCoord dx, wxCoord dy) + { + int i; + for(i=0; iSetPalette(m_palette);} + protected: + wxPalette m_palette; +}; +#endif // wxUSE_PALETTE + +class pdcSetLogicalFunctionOp : public pdcOp +{ + public: + pdcSetLogicalFunctionOp(int function) {m_function=function;} + virtual void DrawToDC(wxDC *dc, bool WXUNUSED(grey)=false) {dc->SetLogicalFunction(m_function);} + protected: + int m_function; +}; + +//---------------------------------------------------------------------------- +// pdcObject type to contain list of operations for each real (Python) object +//---------------------------------------------------------------------------- +class pdcObject +{ + public: + pdcObject(int id) + {m_id=id; m_bounded=false; m_oplist.DeleteContents(true); + m_greyedout=false;} + + virtual ~pdcObject() {m_oplist.Clear();} + + // Protected Member Access + void SetId(int id) {m_id=id;} + int GetId() {return m_id;} + void SetBounds(wxRect& rect) {m_bounds=rect; m_bounded=true;} + wxRect GetBounds() {return m_bounds;} + void SetBounded(bool bounded) {m_bounded=bounded;} + bool IsBounded() {return m_bounded;} + void SetGreyedOut(bool greyout=true); + bool GetGreyedOut() {return m_greyedout;} + + // Op List Management Methods + void Clear() {m_oplist.Clear();} + void AddOp(pdcOp *op) + { + m_oplist.Append(op); + if (m_greyedout) op->CacheGrey(); + } + int GetLen() {return m_oplist.GetCount();} + virtual void Translate(wxCoord dx, wxCoord dy); + + // Drawing Method + virtual void DrawToDC(wxDC *dc); + protected: + int m_id; // id of object (associates this pdcObject + // with a Python object with same id) + wxRect m_bounds; // bounding rect of this object + bool m_bounded; // true if bounds is valid, false by default + pdcOpList m_oplist; // list of operations for this object + bool m_greyedout; // if true then draw this object in greys only +}; + + +//---------------------------------------------------------------------------- +// Declare a wxList to hold all the objects. List order reflects drawing +// order (Z order) and is the same order as objects are added to the list +//---------------------------------------------------------------------------- +class pdcObjectList; +WX_DECLARE_LIST(pdcObject, pdcObjectList); + + +// ---------------------------------------------------------------------------- +// wxPseudoDC class +// ---------------------------------------------------------------------------- +// This is the actual PseudoDC class +// This class stores a list of recorded dc operations in m_list +// and plays them back to a real dc using DrawToDC or DrawToDCClipped. +// Drawing methods are mirrored from wxDC but add nodes to m_list +// instead of doing any real drawing. +// ---------------------------------------------------------------------------- +class wxPseudoDC : public wxObject +{ +public: + wxPseudoDC() + {m_currId=-1; m_lastObjNode=NULL; m_objectlist.DeleteContents(true);} + ~wxPseudoDC(); + // ------------------------------------------------------------------------ + // List managment methods + // + void RemoveAll(); + int GetLen(); + + // ------------------------------------------------------------------------ + // methods for managing operations by ID + // + // Set the Id for all subsequent operations (until SetId is called again) + void SetId(int id) {m_currId = id;} + // Remove all the operations associated with an id so it can be redrawn + void ClearId(int id); + // Remove the object node (and all operations) associated with an id + void RemoveId(int id); + // Set the bounding rect of a given object + // This will create an object node if one doesn't exist + void SetIdBounds(int id, wxRect& rect); + void GetIdBounds(int id, wxRect& rect); + // Translate all the operations for this id + void TranslateId(int id, wxCoord dx, wxCoord dy); + // Grey-out an object + void SetIdGreyedOut(int id, bool greyout=true); + bool GetIdGreyedOut(int id); + // Find Objects at a point. Returns Python list of id's + // sorted in reverse drawing order (result[0] is top object) + // This version looks at drawn pixels + PyObject *FindObjects(wxCoord x, wxCoord y, + wxCoord radius=1, const wxColor& bg=*wxWHITE); + // This version only looks at bounding boxes + PyObject *FindObjectsByBBox(wxCoord x, wxCoord y); + + // ------------------------------------------------------------------------ + // Playback Methods + // + // draw to dc but skip objects known to be outside of rect + // This is a coarse level of clipping to speed things up + // when lots of objects are off screen and doesn't affect the dc level + // clipping + void DrawToDCClipped(wxDC *dc, const wxRect& rect); + void DrawToDCClippedRgn(wxDC *dc, const wxRegion& region); + // draw to dc with no clipping (well the dc will still clip) + void DrawToDC(wxDC *dc); + // draw a single object to the dc + void DrawIdToDC(int id, wxDC *dc); + + // ------------------------------------------------------------------------ + // Hit Detection Methods + // + // returns list of object with a drawn pixel within radius pixels of (x,y) + // the list is in reverse draw order so last drawn is first in list + // PyObject *HitTest(wxCoord x, wxCoord y, double radius) + // returns list of objects whose bounding boxes include (x,y) + // PyObject *HitTestBB(wxCoord x, wxCoord y) + + + // ------------------------------------------------------------------------ + // Methods mirrored from wxDC + // + void FloodFill(wxCoord x, wxCoord y, const wxColour& col, + int style = wxFLOOD_SURFACE) + {AddToList(new pdcFloodFillOp(x,y,col,style));} + void FloodFill(const wxPoint& pt, const wxColour& col, + int style = wxFLOOD_SURFACE) + { FloodFill(pt.x, pt.y, col, style); } + + void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) + {AddToList(new pdcDrawLineOp(x1, y1, x2, y2));} + void DrawLine(const wxPoint& pt1, const wxPoint& pt2) + { DrawLine(pt1.x, pt1.y, pt2.x, pt2.y); } + + void CrossHair(wxCoord x, wxCoord y) + {AddToList(new pdcCrossHairOp(x,y));} + void CrossHair(const wxPoint& pt) + { CrossHair(pt.x, pt.y); } + + void DrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, + wxCoord xc, wxCoord yc) + {AddToList(new pdcDrawArcOp(x1,y1,x2,y2,xc,yc));} + void DrawArc(const wxPoint& pt1, const wxPoint& pt2, const wxPoint& centre) + { DrawArc(pt1.x, pt1.y, pt2.x, pt2.y, centre.x, centre.y); } + + void DrawCheckMark(wxCoord x, wxCoord y, + wxCoord width, wxCoord height) + {AddToList(new pdcDrawCheckMarkOp(x,y,width,height));} + void DrawCheckMark(const wxRect& rect) + { DrawCheckMark(rect.x, rect.y, rect.width, rect.height); } + + void DrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h, + double sa, double ea) + {AddToList(new pdcDrawEllipticArcOp(x,y,w,h,sa,ea));} + void DrawEllipticArc(const wxPoint& pt, const wxSize& sz, + double sa, double ea) + { DrawEllipticArc(pt.x, pt.y, sz.x, sz.y, sa, ea); } + + void DrawPoint(wxCoord x, wxCoord y) + {AddToList(new pdcDrawPointOp(x,y));} + void DrawPoint(const wxPoint& pt) + { DrawPoint(pt.x, pt.y); } + + void DrawPolygon(int n, wxPoint points[], + wxCoord xoffset = 0, wxCoord yoffset = 0, + int fillStyle = wxODDEVEN_RULE) + {AddToList(new pdcDrawPolygonOp(n,points,xoffset,yoffset,fillStyle));} + + void DrawPolyPolygon(int n, int count[], wxPoint points[], + wxCoord xoffset = 0, wxCoord yoffset = 0, + int fillStyle = wxODDEVEN_RULE) + {AddToList(new pdcDrawPolyPolygonOp(n,count,points,xoffset,yoffset,fillStyle));} + + void DrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) + {AddToList(new pdcDrawRectangleOp(x, y, width, height));} + void DrawRectangle(const wxPoint& pt, const wxSize& sz) + { DrawRectangle(pt.x, pt.y, sz.x, sz.y); } + void DrawRectangle(const wxRect& rect) + { DrawRectangle(rect.x, rect.y, rect.width, rect.height); } + + void DrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, + double radius) + {AddToList(new pdcDrawRoundedRectangleOp(x,y,width,height,radius));} + void DrawRoundedRectangle(const wxPoint& pt, const wxSize& sz, + double radius) + { DrawRoundedRectangle(pt.x, pt.y, sz.x, sz.y, radius); } + void DrawRoundedRectangle(const wxRect& r, double radius) + { DrawRoundedRectangle(r.x, r.y, r.width, r.height, radius); } + + void DrawCircle(wxCoord x, wxCoord y, wxCoord radius) + { DrawEllipse(x - radius, y - radius, 2*radius, 2*radius); } + void DrawCircle(const wxPoint& pt, wxCoord radius) + { DrawCircle(pt.x, pt.y, radius); } + + void DrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) + {AddToList(new pdcDrawEllipseOp(x,y,width,height));} + void DrawEllipse(const wxPoint& pt, const wxSize& sz) + { DrawEllipse(pt.x, pt.y, sz.x, sz.y); } + void DrawEllipse(const wxRect& rect) + { DrawEllipse(rect.x, rect.y, rect.width, rect.height); } + + void DrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) + {AddToList(new pdcDrawIconOp(icon,x,y));} + void DrawIcon(const wxIcon& icon, const wxPoint& pt) + { DrawIcon(icon, pt.x, pt.y); } + + void DrawLines(int n, wxPoint points[], + wxCoord xoffset = 0, wxCoord yoffset = 0) + {AddToList(new pdcDrawLinesOp(n,points,xoffset,yoffset));} + + void DrawBitmap(const wxBitmap &bmp, wxCoord x, wxCoord y, + bool useMask = false) + {AddToList(new pdcDrawBitmapOp(bmp,x,y,useMask));} + void DrawBitmap(const wxBitmap &bmp, const wxPoint& pt, + bool useMask = false) + { DrawBitmap(bmp, pt.x, pt.y, useMask); } + + void DrawText(const wxString& text, wxCoord x, wxCoord y) + {AddToList(new pdcDrawTextOp(text, x, y));} + void DrawText(const wxString& text, const wxPoint& pt) + { DrawText(text, pt.x, pt.y); } + + void DrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle) + {AddToList(new pdcDrawRotatedTextOp(text,x,y,angle));} + void DrawRotatedText(const wxString& text, const wxPoint& pt, double angle) + { DrawRotatedText(text, pt.x, pt.y, angle); } + + // this version puts both optional bitmap and the text into the given + // rectangle and aligns is as specified by alignment parameter; it also + // will emphasize the character with the given index if it is != -1 + void DrawLabel(const wxString& text, + const wxBitmap& image, + const wxRect& rect, + int alignment = wxALIGN_LEFT | wxALIGN_TOP, + int indexAccel = -1) + {AddToList(new pdcDrawLabelOp(text,image,rect,alignment,indexAccel));} + + void DrawLabel(const wxString& text, const wxRect& rect, + int alignment = wxALIGN_LEFT | wxALIGN_TOP, + int indexAccel = -1) + { DrawLabel(text, wxNullBitmap, rect, alignment, indexAccel); } + +/*?????? I don't think that the source dc would stick around + void Blit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, + int rop = wxCOPY, bool useMask = false, wxCoord xsrcMask = wxDefaultCoord, wxCoord ysrcMask = wxDefaultCoord) + {AddToList(new pdcBlitOp(xdest,ydest,width,height,source,xsrc, + ysrc,rop,useMask,xsrcMask,ysrcMask));} + void Blit(const wxPoint& destPt, const wxSize& sz, + wxDC *source, const wxPoint& srcPt, + int rop = wxCOPY, bool useMask = false, const wxPoint& srcPtMask = wxDefaultPosition) + { + Blit(destPt.x, destPt.y, sz.x, sz.y, source, srcPt.x, srcPt.y, + rop, useMask, srcPtMask.x, srcPtMask.y); + } +??????*/ + +#if wxUSE_SPLINES + void DrawSpline(int n, wxPoint points[]) + {AddToList(new pdcDrawSplineOp(n,points));} +#endif // wxUSE_SPLINES + +#if wxUSE_PALETTE + void SetPalette(const wxPalette& palette) + {AddToList(new pdcSetPaletteOp(palette));} +#endif // wxUSE_PALETTE + + void SetLogicalFunction(int function) + {AddToList(new pdcSetLogicalFunctionOp(function));} + void SetFont(const wxFont& font) + {AddToList(new pdcSetFontOp(font));} + void SetPen(const wxPen& pen) + {AddToList(new pdcSetPenOp(pen));} + void SetBrush(const wxBrush& brush) + {AddToList(new pdcSetBrushOp(brush));} + void SetBackground(const wxBrush& brush) + {AddToList(new pdcSetBackgroundOp(brush));} + void SetBackgroundMode(int mode) + {AddToList(new pdcSetBackgroundModeOp(mode));} + void SetTextBackground(const wxColour& colour) + {AddToList(new pdcSetTextBackgroundOp(colour));} + void SetTextForeground(const wxColour& colour) + {AddToList(new pdcSetTextForegroundOp(colour));} + + void Clear() + {AddToList(new pdcClearOp());} + void BeginDrawing() + {AddToList(new pdcBeginDrawingOp());} + void EndDrawing() + {AddToList(new pdcEndDrawingOp());} + +protected: + // ------------------------------------------------------------------------ + // protected helper methods + void AddToList(pdcOp *newOp); + pdcObjectList::Node *FindObjNode(int id, bool create=false); + + // ------------------------------------------------------------------------ + // Data members + // + int m_currId; // id to use for operations done on the PseudoDC + pdcObjectList::Node *m_lastObjNode; // used to find last used object quickly + pdcObjectList m_objectlist; // list of objects +}; + +#endif + From landa at grass.itc.it Fri Oct 12 21:05:42 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 12 21:05:44 2007 Subject: [grass-addons] r1132 - trunk/grassaddons/gui/gui_modules Message-ID: <200710121905.l9CJ5ga1018036@grass.itc.it> Author: landa Date: 2007-10-12 21:05:38 +0200 (Fri, 12 Oct 2007) New Revision: 1132 Modified: trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Digitization tool: Basic query tool implemented. Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-12 15:05:12 UTC (rev 1131) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-12 19:05:38 UTC (rev 1132) @@ -96,6 +96,11 @@ self.settings["layer"] = 1 self.settings["category"] = 1 self.settings["categoryMode"] = "Next to use" + + # query tool + self.settings["query"] = "length" + self.settings["queryLength"] = ("shorter than", 0) + self.settings["queryDangle"] = (0,) else: self.settings = settings @@ -496,9 +501,9 @@ '--q', 'map=%s' % self.settings['backgroundMap'], 'tool=select', - # 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1])]) - 'polygon=%f,%f,%f,%f,%f,%f,%f,%f,%f,%f' % \ - (x1, y1, x2, y1, x2, y2, x1, y2, x1, y1)]) + 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1])]) + #'polygon=%f,%f,%f,%f,%f,%f,%f,%f,%f,%f' % \ + # (x1, y1, x2, y1, x2, y2, x1, y2, x1, y1)]) try: output = vEditCmd.ReadStdOutput()[0] # first line @@ -512,6 +517,34 @@ return ids + def SelectLinesByQuery(self, pos1, pos2, query="length"): + """Select features by query""" + + vEdit = (['v.edit', + '--q', + 'map=%s' % self.map, + 'tool=select', + 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1]), + 'query=%s' % self.settings['query'], + 'thresh=%f' % self.settings['queryLength'][1]]) + + if self.settings['queryLength'][0] == "longer than": + vEdit.append('-r') + + vEditCmd = gcmd.Command(vEdit) + + try: + output = vEditCmd.ReadStdOutput()[0] # first line + ids = output.split(',') + ids = map(int, ids) # str -> int + except: + return [] + + Debug.msg(4, "VEdit.SelectLinesByQuery(): %s" % \ + ",".join(["%d" % v for v in ids])) + + return ids + class VDigit(AbstractDigit): """ Prototype of digitization class based on v.digit reimplementation @@ -823,7 +856,8 @@ self.__CreateSymbologyPage(notebook) parent.digit.SetCategory() # update category number (next to use) self.__CreateSettingsPage(notebook) - + self.__CreateQueryPage(notebook) + # buttons btnApply = wx.Button(self, wx.ID_APPLY, _("Apply") ) btnCancel = wx.Button(self, wx.ID_CANCEL) @@ -833,6 +867,7 @@ # bindigs btnApply.Bind(wx.EVT_BUTTON, self.OnApply) btnOk.Bind(wx.EVT_BUTTON, self.OnOK) + btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) # sizers btnSizer = wx.StdDialogButtonSizer() @@ -1017,6 +1052,75 @@ return panel + def __CreateQueryPage(self, notebook): + """Create notebook page for query tool""" + + settings = self.parent.digit.settings + + panel = wx.Panel(parent=notebook, id=wx.ID_ANY) + notebook.AddPage(page=panel, text=_("Query tool")) + + border = wx.BoxSizer(wx.VERTICAL) + + box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Choose query tool")) + sizer = wx.StaticBoxSizer(box, wx.VERTICAL) + + # + # length + # + self.queryLength = wx.RadioButton(parent=panel, id=wx.ID_ANY, label=_("length")) + self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) + sizer.Add(item=self.queryLength, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) + flexSizer = wx.FlexGridSizer (cols=4, hgap=5, vgap=5) + flexSizer.AddGrowableCol(0) + txt = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select lines")) + self.queryLengthSL = wx.Choice (parent=panel, id=wx.ID_ANY, + choices = [_("shorter than"), _("longer than")]) + self.queryLengthSL.SetStringSelection(settings["queryLength"][0]) + self.queryLengthValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(100, -1), + initial=1, + min=0, max=1e6) + self.queryLengthValue.SetValue(settings["queryLength"][1]) + units = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("map units")) + flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(self.queryLengthSL, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) + flexSizer.Add(self.queryLengthValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) + flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + sizer.Add(item=flexSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) + + # + # dangle + # + self.queryDangle = wx.RadioButton(parent=panel, id=wx.ID_ANY, label=_("dangle")) + self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) + sizer.Add(item=self.queryDangle, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) + flexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5) + flexSizer.AddGrowableCol(0) + txt = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select dangles shorter than")) + self.queryDangleValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(100, -1), + initial=1, + min=0, max=1e6) + self.queryDangleValue.SetValue(settings["queryDangle"][0]) + units = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("map units")) + flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(self.queryDangleValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) + flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + sizer.Add(item=flexSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) + + if settings["query"] == "length": + self.queryLength.SetValue(True) + else: + self.queryDangle.SetValue(True) + # enable & disable items + self.OnChangeQuery(None) + + border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5) + + panel.SetSizer(border) + + return panel + + def __SymbologyData(self): """ Data for __CreateSymbologyPage() @@ -1093,17 +1197,37 @@ self.parent.digit.settings['backgroundMap'] = map + def OnChangeQuery(self, event): + """Change query""" + if self.queryLength.GetValue(): + # length + self.queryLengthSL.Enable(True) + self.queryLengthValue.Enable(True) + self.queryDangleValue.Enable(False) + else: + # dangle + self.queryLengthSL.Enable(False) + self.queryLengthValue.Enable(False) + self.queryDangleValue.Enable(True) + def OnOK(self, event): """Button 'OK' clicked""" self.UpdateSettings() + self.parent.digittoolbar.settingsDialog = None self.Close() def OnApply(self, event): """Button 'Apply' clicked""" self.UpdateSettings() + def OnCancel(self, event): + """Button 'Cancel' clicked""" + self.parent.digittoolbar.settingsDialog = None + self.Close() + def UpdateSettings(self): """Update self.parent.digit.settings""" + # symbology for key, (enabled, color) in self.symbology.iteritems(): if enabled: @@ -1134,6 +1258,15 @@ except: pass + # query tool + if self.queryLength.GetValue(): + self.parent.digit.settings["query"] = "length" + else: + self.parent.digit.settings["query"] = "dangle" + self.parent.digit.settings["queryLength"] = (self.queryLengthSL.GetStringSelection(), + int(self.queryLengthValue.GetValue())) + self.parent.digit.settings["queryDangle"] = (int(self.queryDangleValue.GetValue()),) + # update driver settings self.parent.digit.driver.UpdateSettings() Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-12 15:05:12 UTC (rev 1131) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-12 19:05:38 UTC (rev 1132) @@ -1006,7 +1006,8 @@ if digitToolbar.action in ["deleteLine", "moveLine", "moveVertex", "copyCats", "editLine", "flipLine", - "mergeLine", "snapLine", "connectLine"]: + "mergeLine", "snapLine", "connectLine", + "queryLine"]: nselected = 0 # -> delete line || move line || move vertex if digitToolbar.action in ["moveVertex", "editLine"]: @@ -1041,6 +1042,12 @@ if nselected > 0: self.copyCatsIds = driver.GetSelected() + elif digitToolbar.action == "queryLine": + selected = self.parent.digit.SelectLinesByQuery(pos1, pos2) + nselected = len(selected) + if nselected > 0: + driver.SetSelected(selected) + else: # -> moveLine || deleteLine, etc. (select by box) nselected = driver.SelectLinesByBox(pos1, pos2) @@ -1368,7 +1375,8 @@ elif digit.action in ["deleteLine", "moveLine", "splitLine", "addVertex", "removeVertex", "moveVertex", "copyCats", "flipLine", "mergeLine", - "snapLine", "connectLine", "copyLine"]: + "snapLine", "connectLine", "copyLine", + "queryLine"]: # varios tools -> unselected selected features self.parent.digit.driver.Unselect() if digit.action in ["moveLine", "moveVertex", "editLine"] and \ Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-12 15:05:12 UTC (rev 1131) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-12 19:05:38 UTC (rev 1132) @@ -243,6 +243,9 @@ self.comboid = None + # only one dialog settings can be one + self.settingsDialog = None + # create toolbars (two rows) self.toolbar = [] numOfRows = 2 @@ -434,9 +437,11 @@ def OnSettings(self, event): """Show settings dialog""" - DigitSettingsDialog(parent=self.parent, title=_("Digitization settings"), - style=wx.DEFAULT_DIALOG_STYLE).Show() + if not self.settingsDialog: + self.settingsDialog = DigitSettingsDialog(parent=self.parent, title=_("Digitization settings"), + style=wx.DEFAULT_DIALOG_STYLE).Show() + def OnAdditionalToolMenu(self, event): """Menu for additional tools""" point = wx.GetMousePosition() @@ -462,6 +467,14 @@ toolMenu.AppendItem(connect) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnConnect, connect) + query = wx.MenuItem(toolMenu, wx.ID_ANY, 'Query tool') + toolMenu.AppendItem(query) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnQuery, query) + + zbulk = wx.MenuItem(toolMenu, wx.ID_ANY, 'Z bulk-labeling 3D lines') + toolMenu.AppendItem(zbulk) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnZBulk, zbulk) + # Popup the menu. If an item is selected then its handler # will be called before PopupMenu returns. self.parent.MapWindow.PopupMenu(toolMenu) @@ -497,6 +510,18 @@ self.action="connectLine" self.parent.MapWindow.mouse['box'] = 'box' + def OnQuery(self, event): + """Query selected lines/boundaries""" + Debug.msg(2, "Digittoolbar.OnQuery(): %s" % self.parent.digit.settings["query"]) + self.action="queryLine" + self.parent.MapWindow.mouse['box'] = 'box' + + def OnZBulk(self, event): + """Z bulk-labeling selected lines/boundaries""" + Debug.msg(2, "Digittoolbar.OnZBulk():") + self.action="zbulkLine" + self.parent.MapWindow.mouse['box'] = 'box' + def OnSelectMap (self, event): """ Select vector map layer for editing From landa at grass.itc.it Sat Oct 13 21:55:53 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sat Oct 13 21:55:56 2007 Subject: [grass-addons] r1133 - in trunk/grassaddons/gui: . display_driver gui_modules icons/silk Message-ID: <200710131955.l9DJtr6R020334@grass.itc.it> Author: landa Date: 2007-10-13 21:55:37 +0200 (Sat, 13 Oct 2007) New Revision: 1133 Modified: trunk/grassaddons/gui/display_driver/driver.cpp trunk/grassaddons/gui/display_driver/driver.h trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/menudata.py trunk/grassaddons/gui/gui_modules/toolbars.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/icons/silk/ trunk/grassaddons/gui/wxgui.py Log: Digitization tool: * z bulk-labeling tool implemented * 'connect line' tool fixed * various minor fixes Modified: trunk/grassaddons/gui/display_driver/driver.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-13 19:55:37 UTC (rev 1133) @@ -742,11 +742,11 @@ dx = std::fabs(x2 - x1); dy = std::fabs(y2 - y1); - Vect_append_point(bbox, x1, y1, 0.0); - Vect_append_point(bbox, x2, y1, 0.0); - Vect_append_point(bbox, x2, y2, 0.0); - Vect_append_point(bbox, x1, y2, 0.0); - Vect_append_point(bbox, x1, y1, 0.0); + Vect_append_point(bbox, x1, y1, -PORT_DOUBLE_MAX); + Vect_append_point(bbox, x2, y1, PORT_DOUBLE_MAX); + Vect_append_point(bbox, x2, y2, -PORT_DOUBLE_MAX); + Vect_append_point(bbox, x1, y2, PORT_DOUBLE_MAX); + Vect_append_point(bbox, x1, y1, -PORT_DOUBLE_MAX); Vect_select_lines_by_polygon(mapInfo, bbox, 0, NULL, @@ -837,23 +837,6 @@ } /** - \brief Unselect selected features by user - - Clear list of ids of selected vector objects - - \param - - \return -*/ -void DisplayDriver::Unselect() -{ - selected.clear(); - drawSegments = false; - - return; -} - -/** \brief Get ids of selected objects \param[in] grassId if true return GRASS line ids @@ -923,6 +906,9 @@ { selected = id; + if (selected.size() <= 0) + drawSegments = false; + return 1; } Modified: trunk/grassaddons/gui/display_driver/driver.h =================================================================== --- trunk/grassaddons/gui/display_driver/driver.h 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/display_driver/driver.h 2007-10-13 19:55:37 UTC (rev 1133) @@ -157,7 +157,6 @@ std::vector SelectLineByPoint(double x, double y, double thresh, int type); - void Unselect(); std::vector GetSelected(bool grassId); int SetSelected(std::vector id); std::vector GetSelectedVertex(double x, double y); Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-13 19:55:37 UTC (rev 1133) @@ -9,6 +9,7 @@ * CDisplayDriver * DigitSettingsDialog * DigitCategoryDialog + * DigitZBulkDialog PURPOSE: Digitization tool wxPython GUI prototype @@ -517,7 +518,7 @@ return ids - def SelectLinesByQuery(self, pos1, pos2, query="length"): + def SelectLinesByQuery(self, pos1, pos2): """Select features by query""" vEdit = (['v.edit', @@ -528,8 +529,9 @@ 'query=%s' % self.settings['query'], 'thresh=%f' % self.settings['queryLength'][1]]) - if self.settings['queryLength'][0] == "longer than": - vEdit.append('-r') + if self.settings['query'] == "length" and \ + self.settings['queryLength'][0] == "longer than": + vEdit.append('-r') # FIXBUG: reverse selection regardless of bbox vEditCmd = gcmd.Command(vEdit) @@ -545,6 +547,17 @@ return ids + def ZBulkLine(self, pos1, pos2, value, step): + """Provide z bulk-labeling (automated assigment of z coordinate + to 3d lines""" + + gcmd.Command(['v.edit', + '--q', + 'map=%s' % self.map, + 'tool=zbulk', + 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1]), + 'zbulk=%f,%f' % (value, step)]) + class VDigit(AbstractDigit): """ Prototype of digitization class based on v.digit reimplementation @@ -743,11 +756,6 @@ return id - def Unselect(self): - """Delesect selected vector features""" - - self.__display.Unselect() - def SetSelected(self, id): """Set selected vector features""" @@ -1065,6 +1073,7 @@ box = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Choose query tool")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) + LocUnits = self.parent.MapWindow.Map.ProjInfo()['units'] # # length # @@ -1081,7 +1090,7 @@ initial=1, min=0, max=1e6) self.queryLengthValue.SetValue(settings["queryLength"][1]) - units = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("map units")) + units = wx.StaticText(parent=panel, id=wx.ID_ANY, label="%s" % LocUnits) flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.queryLengthSL, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(self.queryLengthValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) @@ -1101,7 +1110,7 @@ initial=1, min=0, max=1e6) self.queryDangleValue.SetValue(settings["queryDangle"][0]) - units = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("map units")) + units = wx.StaticText(parent=panel, id=wx.ID_ANY, label="%s" % LocUnits) flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.queryDangleValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) @@ -1305,7 +1314,7 @@ Debug.msg(3, "DigitCategoryDialog(): line=%d, cats=%s" % \ (self.line, self.cats)) - wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title=title, style=style) + wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title=title, style=style, pos=pos) # list of categories box = wx.StaticBox(parent=self, id=wx.ID_ANY, @@ -1652,3 +1661,65 @@ self.currentItem = 0 return itemData + +class DigitZBulkDialog(wx.Dialog): + """ + Dialog used for Z bulk-labeling tool + """ + def __init__(self, parent, title, nselected, style=wx.DEFAULT_DIALOG_STYLE): + wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style) + + self.parent = parent # mapdisplay.BufferedWindow class instance + + # panel = wx.Panel(parent=self, id=wx.ID_ANY) + + border = wx.BoxSizer(wx.VERTICAL) + + txt = wx.StaticText(parent=self, + label=_("%d lines selected for z bulk-labeling") % nselected); + border.Add(item=txt, proportion=0, flag=wx.ALL | wx.EXPAND, border=5) + + box = wx.StaticBox (parent=self, id=wx.ID_ANY, label=" %s " % _("Set value")) + sizer = wx.StaticBoxSizer(box, wx.VERTICAL) + flexSizer = wx.FlexGridSizer (cols=2, hgap=5, vgap=5) + flexSizer.AddGrowableCol(0) + + # starting value + txt = wx.StaticText(parent=self, + label=_("Starting value")); + self.value = wx.SpinCtrl(parent=self, id=wx.ID_ANY, size=(150, -1), + initial=0, + min=-1e6, max=1e6) + flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(self.value, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) + + # step + txt = wx.StaticText(parent=self, + label=_("Step")) + self.step = wx.SpinCtrl(parent=self, id=wx.ID_ANY, size=(150, -1), + initial=0, + min=0, max=1e6) + flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(self.step, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) + + sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=1) + border.Add(item=sizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) + + # buttons + btnCancel = wx.Button(self, wx.ID_CANCEL) + btnOk = wx.Button(self, wx.ID_OK) + btnOk.SetDefault() + + # sizers + btnSizer = wx.StdDialogButtonSizer() + btnSizer.AddButton(btnCancel) + btnSizer.AddButton(btnOk) + btnSizer.Realize() + + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(item=border, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + mainSizer.Add(item=btnSizer, proportion=0, + flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5) + + self.SetSizer(mainSizer) + mainSizer.Fit(self) Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-13 19:55:37 UTC (rev 1133) @@ -62,10 +62,11 @@ import defaultfont import histogram import profile -from digit import Digit as Digit +from digit import Digit as Digit from digit import DigitCategoryDialog as DigitCategoryDialog -from debug import Debug as Debug -from icon import Icons as Icons +from digit import DigitZBulkDialog as DigitZBulkDialog +from debug import Debug as Debug +from icon import Icons as Icons import images imagepath = images.__path__[0] @@ -447,6 +448,8 @@ """ dc = wx.BufferedPaintDC(self, self._Buffer) self.pdc.DrawToDC(dc) + if self.pdcVector: + self.pdcVector.DrawToDC(dc) self._Buffer.SaveFile(FileName, FileType) def GetOverlay(self): @@ -815,6 +818,7 @@ elif self.mouse["use"] == "pointer" and self.parent.digittoolbar: # digitization digitToolbar = self.parent.digittoolbar + digitClass = self.parent.digit east, north = self.Pixel2Cell(self.mouse['begin']) try: @@ -842,18 +846,18 @@ if digitToolbar.action == "addLine": if digitToolbar.type in ["point", "centroid"]: # add new point - self.parent.digit.AddPoint(map=map, + digitClass.AddPoint(map=map, type=digitToolbar.type, x=east, y=north) self.UpdateMap(render=False) # redraw map # add new record into atribute table - if self.parent.digit.settings["addRecord"]: + if digitClass.settings["addRecord"]: # select attributes based on layer and category addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map, - layer=self.parent.digit.settings["layer"], - cat=self.parent.digit.settings["category"], + layer=digitClass.settings["layer"], + cat=digitClass.settings["category"], pos=posWindow, action="add") if addRecordDlg.mapInfo and \ @@ -893,15 +897,17 @@ self.moveIds = [] if digitToolbar.action in ["moveVertex", "editLine"]: # set pen - self.polypen = wx.Pen(colour=self.parent.digit.settings["symbolHighlight"][1], + self.polypen = wx.Pen(colour=digitClass.settings["symbolHighlight"][1], width=2, style=wx.SHORT_DASH) self.pdcVector.SetPen(self.polypen) + elif digitToolbar.action == "splitLine": pass - elif digitToolbar.action in ["displayAttributes", "displayCategories"]: + + elif digitToolbar.action in ["displayAttrs", "displayCats"]: qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width) redraw = False - if digitToolbar.action == "displayAttributes": + if digitToolbar.action == "displayAttrs": # select attributes based on coordinates (all layers) updateRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map, queryCoords=(east, north), @@ -911,7 +917,7 @@ if updateRecordDlg.mapInfo and \ updateRecordDlg.GetLine(): # highlight feature & re-draw map - self.parent.digit.driver.SetSelected([updateRecordDlg.GetLine()]) + digitClass.driver.SetSelected([updateRecordDlg.GetLine()]) self.UpdateMap(render=False) redraw = True if updateRecordDlg.ShowModal() == wx.ID_OK: @@ -924,7 +930,7 @@ executeCommand = gcmd.Command(cmd=["db.execute", "--q", "input=%s" % sqlfile.name]) - else: # displayCategories + else: # displayCats categoryDlg = DigitCategoryDialog(parent=self, map=map, queryCoords=(east, north), @@ -934,7 +940,7 @@ if categoryDlg.GetLine(): # highlight feature & re-draw map - self.parent.digit.driver.SetSelected([categoryDlg.GetLine()]) + digitClass.driver.SetSelected([categoryDlg.GetLine()]) self.UpdateMap(render=False) redraw = True @@ -942,17 +948,36 @@ pass # unselect & re-draw if redraw: - self.parent.digit.driver.Unselect() + digitClass.driver.SetSelected([]) self.UpdateMap(render=False) + elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsList"): self.copyCatsList = [] else: self.copyCatsIds = [] self.mouse['box'] = 'box' + elif digitToolbar.action == "copyLine": self.copyIds = None self.layerTmp = None + + elif digitToolbar.action == "zbulkLine": + if len(self.polycoords) > 1: # start new line + self.polycoords = [] + self.ClearLines(pdc=self.pdcTmp) + self.polycoords.append(event.GetPositionTuple()[:]) + if len(self.polycoords) == 1: + self.mouse['begin'] = self.polycoords[-1] + else: + self.mouse['end'] = self.polycoords[-1] + self.DrawLines(pdc=self.pdcTmp) + elif digitToolbar.action == "connectLine": + if len(digitClass.driver.GetSelected()) > 1: + # if two line selected -> reset + digitClass.driver.SetSelected([]) + digitClass.driver.SelectLineByPoint(self.Pixel2Cell(self.mouse['begin'])) + else: # get decoration id self.lastpos = self.mouse['begin'] @@ -970,10 +995,9 @@ Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \ self.mouse["use"]) + self.mouse['end'] = event.GetPositionTuple()[:] + if self.mouse['use'] in ["zoom", "pan"]: - # end point of zoom box or drag - self.mouse['end'] = event.GetPositionTuple()[:] - # set region in zoom or pan self.Zoom(self.mouse['begin'], self.mouse['end'], self.zoomtype) @@ -999,33 +1023,34 @@ elif self.mouse["use"] == "pointer" and self.parent.digittoolbar: # digitization tool active digitToolbar = self.parent.digittoolbar - driver = self.parent.digit.driver + digitClass = self.parent.digit + self.mouse['end'] = event.GetPositionTuple()[:] pos1 = self.Pixel2Cell(self.mouse['begin']) pos2 = self.Pixel2Cell(self.mouse['end']) if digitToolbar.action in ["deleteLine", "moveLine", "moveVertex", "copyCats", "editLine", "flipLine", - "mergeLine", "snapLine", "connectLine", + "mergeLine", "snapLine", "queryLine"]: nselected = 0 # -> delete line || move line || move vertex if digitToolbar.action in ["moveVertex", "editLine"]: - if len(driver.GetSelected()) == 0: + if len(digitClass.driver.GetSelected()) == 0: # -> move vertex (select by point) # return vertex coordinates (tuple) - nselected = driver.SelectLineByPoint(pos1, type="line") + nselected = digitClass.driver.SelectLineByPoint(pos1, type="line") elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsIds"): # collect categories - nselected = driver.SelectLineByPoint(pos1, type="line") + nselected = digitClass.driver.SelectLineByPoint(pos1, type="line") if nselected: qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / \ self.Map.width) vWhat = gcmd.Command(['v.what', '--q', - 'map=%s' % self.parent.digit.map, + 'map=%s' % digitClass.map, 'east_north=%f,%f' % \ (float(pos1[0]), float(pos1[1])), 'distance=%f' % qdist]) @@ -1036,21 +1061,21 @@ self.copyCatsList.append(cat) else: # collect ids - driver.Unselect() + digitClass.driver.SetSelected([]) # return number of selected features - nselected = driver.SelectLinesByBox(pos1, pos2) + nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) if nselected > 0: - self.copyCatsIds = driver.GetSelected() + self.copyCatsIds = digitClass.driver.GetSelected() elif digitToolbar.action == "queryLine": - selected = self.parent.digit.SelectLinesByQuery(pos1, pos2) + selected = digitClass.SelectLinesByQuery(pos1, pos2) nselected = len(selected) if nselected > 0: - driver.SetSelected(selected) + digitClass.driver.SetSelected(selected) else: # -> moveLine || deleteLine, etc. (select by box) - nselected = driver.SelectLinesByBox(pos1, pos2) + nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) if nselected > 0: # highlight selected features @@ -1063,17 +1088,17 @@ # get pseudoDC id of objects which should be redrawn if digitToolbar.action == "moveLine": # -> move line - self.moveIds = driver.GetSelected(grassId=False) + self.moveIds = digitClass.driver.GetSelected(grassId=False) elif digitToolbar.action == "moveVertex": # -> move vertex - self.moveIds = driver.GetSelectedVertex(pos1) + self.moveIds = digitClass.driver.GetSelectedVertex(pos1) elif digitToolbar.action == "editLine": # -> edit line # get id of selected vertex (last or first node) - selVertex = driver.GetSelectedVertex(pos1)[0] - ids = driver.GetSelected(grassId=False) + selVertex = digitClass.driver.GetSelectedVertex(pos1)[0] + ids = digitClass.driver.GetSelected(grassId=False) for id in ids: if id % 2: # vertex self.moveIds.append(id) @@ -1084,7 +1109,7 @@ else: self.UpdateMap(render=False, renderVector=False) elif digitToolbar.action in ["splitLine", "addVertex", "removeVertex"]: - pointOnLine = driver.SelectLineByPoint(pos1, + pointOnLine = digitClass.driver.SelectLineByPoint(pos1, type="line") if pointOnLine: self.UpdateMap(render=False) # highlight object @@ -1093,15 +1118,15 @@ size=5) elif digitToolbar.action == "removeVertex": # get only id of vertex - id = driver.GetSelectedVertex(pos1)[0] + id = digitClass.driver.GetSelectedVertex(pos1)[0] x, y = self.pdcVector.GetIdBounds(id)[0:2] self.pdcVector.RemoveId(id) self.DrawCross(pdc=self.pdcVector, coords=(x, y), size=5) elif digitToolbar.action == "copyLine": - if self.parent.digit.settings['backgroundMap'] == '': + if digitClass.settings['backgroundMap'] == '': # no background map -> copy from current vector map layer - nselected = driver.SelectLinesByBox(pos1, pos2) + nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) if nselected > 0: # highlight selected features @@ -1110,10 +1135,10 @@ self.UpdateMap(render=False, renderVector=False) else: # copy features from background map - self.copyIds = self.parent.digit.SelectLinesFromBackgroundMap(pos1, pos2) + self.copyIds = digitClass.SelectLinesFromBackgroundMap(pos1, pos2) if len(self.copyIds) > 0: dVectTmp = ['d.vect', - 'map=%s' % self.parent.digit.settings['backgroundMap'], + 'map=%s' % digitClass.settings['backgroundMap'], 'cats=%s' % ",".join(["%d" % v for v in self.copyIds]), '-i', 'color=yellow'] @@ -1123,6 +1148,23 @@ else: self.UpdateMap(render=False, renderVector=False) + elif digitToolbar.action == "zbulkLine" and len(self.polycoords) == 2: + # select lines to be labeled + pos1 = self.Pixel2Cell(self.polycoords[0]) + pos2 = self.Pixel2Cell(self.polycoords[1]) + nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) + + if nselected > 0: + # highlight selected features + self.UpdateMap(render=False) + self.DrawLines(pdc=self.pdcTmp) # redraw temp line + else: + self.UpdateMap(render=False, renderVector=False) + + elif digitToolbar.action == "connectLine": + if len(digitClass.driver.GetSelected()) > 0: + self.UpdateMap(render=False) + elif self.dragid != None: # end drag of overlay decoration self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid) @@ -1213,14 +1255,15 @@ Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \ self.mouse["use"]) - digit = self.parent.digittoolbar - if digit: + digitToolbar = self.parent.digittoolbar + if digitToolbar: + digitClass = self.parent.digit # digitization tool (confirm action) - if digit.action == "addLine" and \ - digit.type in ["line", "boundary"]: + if digitToolbar.action == "addLine" and \ + digitToolbar.type in ["line", "boundary"]: # -> add new line / boundary try: - map = digit.layers[digit.layerSelectedID].name + map = digitToolbar.layers[digitToolbar.layerSelectedID].name except: map = None dlg = wx.MessageDialog(self, _("No vector map layer is selected"), @@ -1234,22 +1277,22 @@ for coord in self.polycoords: mapcoords.append(self.Pixel2Cell(coord)) - self.parent.digit.AddLine(map=map, - type=self.parent.digittoolbar.type, + digitClass.AddLine(map=map, + type=digitToolbar.type, coords=mapcoords) self.UpdateMap(render=False) # add new record into atribute table - if self.parent.digit.settings["addRecord"]: + if digitClass.settings["addRecord"]: offset = 5 posWindow = self.ClientToScreen((self.polycoords[-1][0] + offset, self.polycoords[-1][1] + offset)) # select attributes based on layer and category addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map, - layer=self.parent.digit.settings["layer"], - cat=self.parent.digit.settings["category"], + layer=digitClass.settings["layer"], + cat=digitClass.settings["category"], pos=posWindow, action="add") if addRecordDlg.mapInfo and \ @@ -1263,10 +1306,10 @@ "input=%s" % sqlfile.name]) # clean up saved positions self.polycoords = [] - elif digit.action == "deleteLine": + elif digitToolbar.action == "deleteLine": # -> delete selected vector features - self.parent.digit.DeleteSelectedLines() - elif digit.action in ["moveLine", "moveVertex"] and \ + digitClass.DeleteSelectedLines() + elif digitToolbar.action in ["moveLine", "moveVertex"] and \ hasattr(self, "moveBegin"): # move vector feature # move = [self.Distance((0,0), (self.moveBegin[0], 0))[0], @@ -1281,12 +1324,12 @@ pFrom = self.Pixel2Cell(self.moveCoords) move = (pTo[0]-pFrom[0], pTo[1]-pFrom[1]) - if digit.action == "moveLine": + if digitToolbar.action == "moveLine": # move line - self.parent.digit.MoveSelectedLines(move) - elif digit.action == "moveVertex": + digitClass.MoveSelectedLines(move) + elif digitToolbar.action == "moveVertex": # move vertex - self.parent.digit.MoveSelectedVertex(pFrom, + digitClass.MoveSelectedVertex(pFrom, move) else: # edit line pass @@ -1294,62 +1337,77 @@ del self.moveBegin del self.moveCoords del self.moveIds - elif digit.action == "splitLine": + elif digitToolbar.action == "splitLine": # split line - self.parent.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) - elif digit.action == "addVertex": + digitClass.SplitLine(self.Pixel2Cell(self.mouse['begin'])) + elif digitToolbar.action == "addVertex": # add vertex - self.parent.digit.AddVertex(self.Pixel2Cell(self.mouse['begin'])) - elif digit.action == "removeVertex": + digitClass.AddVertex(self.Pixel2Cell(self.mouse['begin'])) + elif digitToolbar.action == "removeVertex": # remove vertex - self.parent.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) - elif digit.action == "copyCats": + digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) + elif digitToolbar.action == "copyCats": try: - self.parent.digit.CopyCats(self.copyCatsList, + digitClass.CopyCats(self.copyCatsList, self.copyCatsIds) del self.copyCatsList del self.copyCatsIds except: pass - elif digit.action == "editLine" and hasattr(self, "moveBegin"): - line = self.parent.digit.driver.GetSelected() + elif digitToolbar.action == "editLine" and hasattr(self, "moveBegin"): + line = digitClass.driver.GetSelected() coords = [] for id in self.moveIds: # avoid last point x, y = self.pdcVector.GetIdBounds(id)[0:2] coords.append(self.Pixel2Cell((x, y))) - self.parent.digit.EditLine(line, coords) + digitClass.EditLine(line, coords) del self.moveBegin del self.moveCoords del self.moveIds - elif digit.action == "flipLine": - self.parent.digit.FlipLine() - elif digit.action == "mergeLine": - self.parent.digit.MergeLine() - elif digit.action == "snapLine": - self.parent.digit.SnapLine() - elif digit.action == "connectLine": - self.parent.digit.ConnectLine() - elif digit.action == "copyLine": - self.parent.digit.CopyLine(self.copyIds) + elif digitToolbar.action == "flipLine": + digitClass.FlipLine() + elif digitToolbar.action == "mergeLine": + digitClass.MergeLine() + elif digitToolbar.action == "snapLine": + digitClass.SnapLine() + elif digitToolbar.action == "connectLine": + if len(digitClass.driver.GetSelected()) == 2: + digitClass.ConnectLine() + elif digitToolbar.action == "copyLine": + digitClass.CopyLine(self.copyIds) del self.copyIds if self.layerTmp: self.Map.DeleteLayer(self.layerTmp) self.UpdateMap(render=True, renderVector=False) del self.layerTmp - if digit.action != "addLine": - self.parent.digit.driver.Unselect() + elif digitToolbar.action == "zbulkLine" and len(self.polycoords) == 2: + pos1 = self.Pixel2Cell(self.polycoords[0]) + pos2 = self.Pixel2Cell(self.polycoords[1]) + + selected = digitClass.driver.GetSelected() + dlg = DigitZBulkDialog(parent=self, title=_("Z bulk-labeling dialog"), + nselected=len(selected)) + if dlg.ShowModal() == wx.ID_OK: + digitClass.ZBulkLine(pos1, pos2, dlg.value.GetValue(), dlg.step.GetValue()) + + self.UpdateMap(render=False, renderVector=True) + + if digitToolbar.action != "addLine": + # unselect and re-render + digitClass.driver.SetSelected([]) self.UpdateMap(render=False) event.Skip() def OnMiddleDown(self, event): """Middle mouse button pressed""" - digit = self.parent.digittoolbar + digitToolbar = self.parent.digittoolbar # digitization tool - if self.mouse["use"] == "pointer" and digit: - if (digit.action == "addLine" and digit.type in ["line", "boundary"]) or \ - digit.action == "editLine": + if self.mouse["use"] == "pointer" and digitToolbar: + digitClass = self.parent.digit + if (digitToolbar.action == "addLine" and digitToolbar.type in ["line", "boundary"]) or \ + digitToolbar.action == "editLine": # add line or boundary -> remove last point from the line try: removed = self.polycoords.pop() @@ -1360,7 +1418,7 @@ except: pass - if digit.action == "editLine" and len(self.moveIds) > 0: + if digitToolbar.action == "editLine" and len(self.moveIds) > 0: # remove last vertex & line self.pdcVector.RemoveId(self.moveIds[-1]) # remove last vertex if self.moveIds[-1] > self.moveIds[-2]: @@ -1372,47 +1430,54 @@ self.ClearLines(pdc=self.pdcTmp) self.UpdateMap(render=False, renderVector=False) self.DrawLines(pdc=self.pdcTmp) - elif digit.action in ["deleteLine", "moveLine", "splitLine", + elif digitToolbar.action in ["deleteLine", "moveLine", "splitLine", "addVertex", "removeVertex", "moveVertex", "copyCats", "flipLine", "mergeLine", "snapLine", "connectLine", "copyLine", "queryLine"]: # varios tools -> unselected selected features - self.parent.digit.driver.Unselect() - if digit.action in ["moveLine", "moveVertex", "editLine"] and \ + digitClass.driver.SetSelected([]) + if digitToolbar.action in ["moveLine", "moveVertex", "editLine"] and \ hasattr(self, "moveBegin"): # move feature -> delete 'move' variables del self.moveBegin del self.moveCoords del self.moveIds - elif digit.action == "copyCats": + elif digitToolbar.action == "copyCats": try: del self.copyCatsList del self.copyCatsIds except: pass - elif digit.action == "copyLine": + elif digitToolbar.action == "copyLine": del self.copyIds if self.layerTmp: self.Map.DeleteLayer(self.layerTmp) self.UpdateMap(render=True, renderVector=False) del self.layerTmp - self.UpdateMap(render=False) # render map + self.UpdateMap(render=False) # render vector + elif digitToolbar.action == "zbulkLine": + # reset polyline + self.polycoords = [] + digitClass.driver.SetSelected([]) + self.UpdateMap(render=False) + + def OnMouseMoving(self, event): """Motion event and no mouse buttons were pressed""" - digit = self.parent.digittoolbar - if self.mouse["use"] == "pointer" and digit: + digitToolbar = self.parent.digittoolbar + if self.mouse["use"] == "pointer" and digitToolbar: + digitClass = self.parent.digit self.mouse['end'] = event.GetPositionTuple()[:] Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \ (self.mouse['end'][0], self.mouse['end'][1])) - if digit.action == "addLine" and \ - digit.type in ["line", "boundary"]: + if digitToolbar.action == "addLine" and digitToolbar.type in ["line", "boundary"]: if len(self.polycoords) > 0: # draw mouse moving self.MouseDraw(self.pdcTmp) - elif digit.action in ["moveLine", "moveVertex", "editLine"] \ + elif digitToolbar.action in ["moveLine", "moveVertex", "editLine"] \ and hasattr(self, "moveBegin"): dx = self.mouse['end'][0] - self.mouse['begin'][0] dy = self.mouse['end'][1] - self.mouse['begin'][1] @@ -1420,11 +1485,11 @@ self.moveBegin[1] += dy if len(self.moveIds) > 0: # draw lines on new position - if digit.action == "moveLine": + if digitToolbar.action == "moveLine": # move line for id in self.moveIds: self.pdcVector.TranslateId(id, dx, dy) - elif digit.action in ["moveVertex", "editLine"]: + elif digitToolbar.action in ["moveVertex", "editLine"]: # move vertex -> # (vertex, left vertex, left line, # right vertex, right line) @@ -1432,7 +1497,7 @@ # self.pdcVector.RemoveId(self.moveIds[0]) # do not draw static lines self.polycoords = [] - if digit.action == "moveVertex": + if digitToolbar.action == "moveVertex": self.pdcVector.TranslateId(self.moveIds[0], dx, dy) if self.moveIds[1] > 0: # previous vertex x, y = self.pdcVector.GetIdBounds(self.moveIds[1])[0:2] @@ -1461,6 +1526,11 @@ self.Refresh() # TODO: use RefreshRect() self.mouse['begin'] = self.mouse['end'] + + elif digitToolbar.action == "zbulkLine": + if len(self.polycoords) == 1: + # draw mouse moving + self.MouseDraw(self.pdcTmp) event.Skip() @@ -2108,7 +2178,7 @@ Debug.msg(3, "BufferedWindow.ReRender():") self.MapWindow.UpdateMap(render=True) - def Pointer(self, event): + def OnPointer(self, event): """Pointer button clicled""" self.MapWindow.mouse['use'] = "pointer" @@ -2118,6 +2188,19 @@ if self.digittoolbar: # digitization tool activated self.MapWindow.SetCursor(self.cursors["cross"]) + + # reset mouse['box'] if needed + if self.digittoolbar.action in ['addLine']: + if digittoolbar.type in ['point', 'centroid']: + self.MapWindow.mouse['box'] = 'point' + else: # line, boundary + self.MapWindow.mouse['box'] = 'line' + elif self.digittoolbar.action in ['addVertex', 'removeVertex', 'splitLine', + 'editLine', 'displayCats', 'displayAttrs', + 'copyCats', 'connectLine']: + self.MapWindow.mouse['box'] = 'point' + else: # moveLine, deleteLine + self.MapWindow.mouse['box'] = 'box' else: self.MapWindow.SetCursor(self.cursors["default"]) Modified: trunk/grassaddons/gui/gui_modules/menudata.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-13 19:55:37 UTC (rev 1133) @@ -542,9 +542,9 @@ # ("","","", "") )), ("Help", ( - ("GRASS help", "GRASS help", "self.RunMenuCmd", ['g.manual', '-i']), - ("GIS Manager help", "GIS Manager help", "self.RunMenuCmd", ['g.manual', 'gis.m']), - ("About GRASS", "About GRASS", "self.OnAboutGRASS", ""), + ("GRASS GIS help", "GRASS GIS help", "self.RunMenuCmd", ['g.manual', '-i']), + ("GRASS GIS Layer Manager help", "GRASS GIS Layer Manager help", "self.RunMenuCmd", ['g.manual', 'gis.m']), + ("About GRASS GIS", "About GRASS GIS", "self.OnAboutGRASS", ""), # ("About system (not functional)", "About system", "self.OnMenuCmd", ""), # ("","","", "") )))] Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-13 19:55:37 UTC (rev 1133) @@ -108,7 +108,7 @@ ("", "", "", "", "", "", ""), (self.pointer, "pointer", Icons["pointer"].GetBitmap(), wx.ITEM_RADIO, Icons["pointer"].GetLabel(), Icons["pointer"].GetDesc(), - self.mapdisplay.Pointer), + self.mapdisplay.OnPointer), (self.query, "query", Icons["query"].GetBitmap(), wx.ITEM_RADIO, Icons["query"].GetLabel(), Icons["query"].GetDesc(), self.mapdisplay.OnQuery), @@ -195,7 +195,7 @@ ("", "", "", "", "", "", ""), (self.gcpset, "gcpset", Icons["gcpset"].GetBitmap(), wx.ITEM_RADIO, Icons["gcpset"].GetLabel(), Icons["gcpset"].GetDesc(), - self.mapdisplay.Pointer), + self.mapdisplay.OnPointer), (self.pan, "pan", Icons["pan"].GetBitmap(), wx.ITEM_RADIO, Icons["pan"].GetLabel(), Icons["pan"].GetDesc(), self.mapdisplay.OnPan), @@ -420,13 +420,13 @@ def OnDisplayCats(self, event): """Display/update categories""" Debug.msg(2, "Digittoolbar.OnDisplayCats():") - self.action="displayCategories" + self.action="displayCats" self.parent.MapWindow.mouse['box'] = 'point' def OnDisplayAttr(self, event): """Display/update attributes""" Debug.msg(2, "Digittoolbar.OnDisplayAttr():") - self.action="displayAttributes" + self.action="displayAttrs" self.parent.MapWindow.mouse['box'] = 'point' def OnCopyCats(self, event): @@ -508,7 +508,7 @@ """Connect selected lines/boundaries""" Debug.msg(2, "Digittoolbar.OnConnect():") self.action="connectLine" - self.parent.MapWindow.mouse['box'] = 'box' + self.parent.MapWindow.mouse['box'] = 'point' def OnQuery(self, event): """Query selected lines/boundaries""" @@ -520,7 +520,7 @@ """Z bulk-labeling selected lines/boundaries""" Debug.msg(2, "Digittoolbar.OnZBulk():") self.action="zbulkLine" - self.parent.MapWindow.mouse['box'] = 'box' + self.parent.MapWindow.mouse['box'] = 'line' def OnSelectMap (self, event): """ @@ -530,13 +530,20 @@ firstly terminated. The map layer is closed. After this the selected map layer activated for editing. """ - if self.layerSelectedID: # deactive map layer for editing + + if self.layerSelectedID == event.GetSelection(): + return False + + if self.layerSelectedID != None: # deactive map layer for editing self.StopEditing(self.layers[self.layerSelectedID]) # select the given map layer for editing - self.layerSelectedID = self.combo.GetCurrentSelection() + self.layerSelectedID = event.GetSelection() self.StartEditing(self.layers[self.layerSelectedID]) + event.Skip() + + return True def StartEditing (self, layerSelected): """ Start editing of selected vector map layer. @@ -587,7 +594,8 @@ (layerSelected.name)) self.combo.SetValue ('Select vector map') - # re-active layer + # re-active layer + # TODO: if status doesn't change in layer tree... self.mapcontent.ChangeLayerActive(layerSelected, True) self.parent.digit.SetMapName(None) @@ -637,6 +645,12 @@ self.combo = wx.ComboBox(self.toolbar[0], id=wx.ID_ANY, value=value, choices=layerNameList, size=(150, -1), style=wx.CB_READONLY) + + # update layer index + try: + self.layerSelectedID = layerNameList.index(value) + except ValueError: + self.layerSelectedID = None self.comboid = self.toolbar[0].InsertControl(0, self.combo) Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-13 19:55:37 UTC (rev 1133) @@ -245,7 +245,7 @@ self.popupMenu = wx.Menu() # general item - self.popupMenu.Append(self.popupID1, text=_("Delete")) + self.popupMenu.Append(self.popupID1, text=_("Remove")) self.Bind(wx.EVT_MENU, self.gismgr.DeleteLayer, id=self.popupID1) if ltype != "command": # rename @@ -279,12 +279,19 @@ layer = self.layers[self.layer_selected].maplayer # enable editing only for vector map layers available in the current mapset digit = self.mapdisplay.digittoolbar - if layer.GetMapset() != grassenv.env["MAPSET"] or \ - (digit and digit.layerSelectedID != None and \ - digit.layers[digit.layerSelectedID] == layer): + if layer.GetMapset() != grassenv.env["MAPSET"]: + # only vector map in current mapset can be edited self.popupMenu.Enable (self.popupID5, False) - if layer.GetMapset() == grassenv.env["MAPSET"]: - self.popupMenu.Enable (self.popupID6, True) + self.popupMenu.Enable (self.popupID6, False) + elif digit and digit.layerSelectedID != None: + # vector map already edited + if digit.layers[digit.layerSelectedID] == layer: + self.popupMenu.Enable (self.popupID5, False) + self.popupMenu.Enable(self.popupID6, True) + self.popupMenu.Enable(self.popupID1, False) + else: + self.popupMenu.Enable(self.popupID5, False) + self.popupMenu.Enable(self.popupID6, False) # raster elif mltype and mltype == "raster": @@ -579,6 +586,9 @@ if self.mapdisplay.autoRender.GetValue(): self.mapdisplay.ReRender(None) + if self.mapdisplay.digittoolbar: + self.mapdisplay.digittoolbar.UpdateListOfLayers (updateTool=True) + def OnLayerChecked(self, event): """Enable/disable given layer item""" item = event.GetItem() Property changes on: trunk/grassaddons/gui/icons/silk ___________________________________________________________________ Name: svn:ignore + __init__.pyc Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-12 19:05:38 UTC (rev 1132) +++ trunk/grassaddons/gui/wxgui.py 2007-10-13 19:55:37 UTC (rev 1133) @@ -141,7 +141,7 @@ # self.cmdsizer = wx.BoxSizer(wx.HORIZONTAL) # do layout - self.SetTitle(_("GRASS Layer Manager")) + self.SetTitle(_("GRASS GIS Layer Manager")) self.SetMinSize((500, 400)) self.SetIcon(wx.Icon(os.path.join(imagepath,'grass.smlogo.gif'), wx.BITMAP_TYPE_ANY)) @@ -813,12 +813,12 @@ layerName = str(self.curr_page.maptree.GetItemText(self.curr_page.maptree.layer_selected)) if layerName: - message = _("Are you sure you want delete layer <" + layerName + ">?") + message = _("Are you sure you want remove layer <" + layerName + ">?") else: - message = _("Are you sure you want delete this layer?") + message = _("Are you sure you want remove selected layer?") dlg = wx.MessageDialog (parent=self, message=message, - caption=_("Delete layer"), + caption=_("Remove layer from layer tree"), style=wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_QUESTION) if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]: From landa at grass.itc.it Sat Oct 13 22:49:15 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sat Oct 13 22:49:17 2007 Subject: [grass-addons] r1134 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710132049.l9DKnFsH020394@grass.itc.it> Author: landa Date: 2007-10-13 22:49:07 +0200 (Sat, 13 Oct 2007) New Revision: 1134 Modified: trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/debug.py trunk/grassaddons/gui/gui_modules/georect.py trunk/grassaddons/gui/gui_modules/profile.py trunk/grassaddons/gui/gui_modules/render.py trunk/grassaddons/gui/gui_modules/select.py trunk/grassaddons/gui/gui_modules/utils.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/location_wizard.py Log: Cosmetics: cmd -> gcmd Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -37,7 +37,7 @@ import wx.lib.mixins.listctrl as listmix import grassenv -import gcmd as cmd +import gcmd from debug import Debug as Debug class Log: @@ -94,7 +94,7 @@ # building the columns i = 0 # FIXME: Maximal number of columns, when the GUI is still usable - dbDescribe = cmd.Command (cmd = ["db.describe", "-c", + dbDescribe = gcmd.Command (cmd = ["db.describe", "-c", "table=%s" % self.parent.tablename, "driver=%s" % self.parent.driver, "database=%s" % self.parent.database]) @@ -171,7 +171,7 @@ "driver=%s" % self.parent.driver] # run command - vDbSelect = cmd.Command (cmd=cmdv) + vDbSelect = gcmd.Command (cmd=cmdv) # FIXME: Max. number of rows, while the GUI is still usable i = 0 @@ -271,9 +271,9 @@ "width=3"] #print cmd if self.icon: - cmd.append("icon=%s" % (self.icon)) + gcmd.append("icon=%s" % (self.icon)) if self.pointsize: - cmd.append("size=%s" % (self.pointsize)) + gcmd.append("size=%s" % (self.pointsize)) self.qlayer = self.map.AddLayer(type="vector", name='qlayer', command=cmd, l_active=True, l_hidden=True, l_opacity=1, l_render=False) @@ -492,7 +492,7 @@ pointdata=None): # get list of attribute tables (TODO: open more tables) - vDbConnect = cmd.Command (cmd=["v.db.connect", "-g", "map=%s" % vectmap]) + vDbConnect = gcmd.Command (cmd=["v.db.connect", "-g", "map=%s" % vectmap]) try: if vDbConnect.returncode == 0: @@ -875,7 +875,7 @@ def __CheckDBConnection(self): """Check DB connection""" - layerCommand = cmd.Command(cmd=["v.db.connect", + layerCommand = gcmd.Command(cmd=["v.db.connect", "-g", "--q", "map=%s" % self.map,], dlgMsg='txt') @@ -898,7 +898,7 @@ """Describe linked tables""" for layer in self.layers.keys(): # determine column names and types - columnsCommand = cmd.Command (cmd=["v.db.connect", "-c", "--q", + columnsCommand = gcmd.Command (cmd=["v.db.connect", "-c", "--q", "map=%s" % self.map, "layer=%d" % layer]) table = self.layers[layer]["table"] @@ -921,7 +921,7 @@ Return line id or None if no line is found""" line = None nselected = 0 - cmdWhat = cmd.Command(cmd=['v.what', + cmdWhat = gcmd.Command(cmd=['v.what', '-a', '--q', 'map=%s' % self.map, 'east_north=%f,%f' % \ @@ -965,7 +965,7 @@ table = self.layers[layer]["table"] # get table desc # select values (only one record) - selectCommand = cmd.Command(cmd=["v.db.select", "-v", "--q", + selectCommand = gcmd.Command(cmd=["v.db.select", "-v", "--q", "map=%s" % self.map, "layer=%d" % layer, "where=cat=%d" % cat]) Modified: trunk/grassaddons/gui/gui_modules/debug.py =================================================================== --- trunk/grassaddons/gui/gui_modules/debug.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/debug.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -62,8 +62,8 @@ # testing if __name__ == "__main__": - import cmd - cmd.Command (cmd=["g.gisenv", "set=DEBUG=3"]) + import gcmd + gcmd.Command (cmd=["g.gisenv", "set=DEBUG=3"]) reload (grassenv) # reload GRASS environments ! for level in range (4): Modified: trunk/grassaddons/gui/gui_modules/georect.py =================================================================== --- trunk/grassaddons/gui/gui_modules/georect.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/georect.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -62,7 +62,7 @@ import menuform import select import disp_print -import gcmd as cmd +import gcmd from debug import Debug as Debug from icon import Icons as Icons @@ -155,15 +155,15 @@ #set environmental variables cmdlist = ['g.gisenv', 'get=GISDBASE'] global grassdatabase - grassdatabase = cmd.Command(cmdlist).module_stdout.read().strip() + grassdatabase = gcmd.Command(cmdlist).module_stdout.read().strip() cmdlist = ['g.gisenv', 'get=LOCATION_NAME'] global curr_location - curr_location = cmd.Command(cmdlist).module_stdout.read().strip() + curr_location = gcmd.Command(cmdlist).module_stdout.read().strip() cmdlist = ['g.gisenv', 'get=MAPSET'] global curr_mapset - curr_mapset = cmd.Command(cmdlist).module_stdout.read().strip() + curr_mapset = gcmd.Command(cmdlist).module_stdout.read().strip() # define wizard pages self.wizard = wiz.Wizard(parent, -1, "Setup for georectification") @@ -234,10 +234,10 @@ def SwitchLocMapset(self, location, mapset): cmdlist = ['g.gisenv', 'set=LOCATION_NAME=%s' % location] - cmd.Command(cmdlist) + gcmd.Command(cmdlist) cmdlist = ['g.gisenv', 'set=MAPSET=%s' % mapset] - cmd.Command(cmdlist) + gcmd.Command(cmdlist) def onWizFinished(self): global grassdatabase Modified: trunk/grassaddons/gui/gui_modules/profile.py =================================================================== --- trunk/grassaddons/gui/gui_modules/profile.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/profile.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -50,7 +50,7 @@ import menuform import disp_print import select -import gcmd as cmd +import gcmd import gui_modules.defaultfont as defaultfont from debug import Debug as Debug from icon import Icons as Icons @@ -288,7 +288,7 @@ # set self.ylabel to match units if they exist cmdlist = ['r.info', 'map=%s' % self.rast1, '-u', '--quiet'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) try: units1 = p.module_stdout.read().strip().split('=')[1] except: @@ -305,7 +305,7 @@ if self.rast2 != '': self.datalist2 = self.CreateDatalist(self.rast2, self.coordstr) cmdlist = ['r.info', 'map=%s' % self.rast2, '-u', '--quiet'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) try: units2 = p.module_stdout.read().strip().split('=')[1] except: @@ -324,7 +324,7 @@ if self.rast3 != '': self.datalist3 = self.CreateDatalist(self.rast3, self.coordstr) cmdlist = ['r.info', 'map=%s' % self.rast3, '-u', '--quiet'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) try: units3 = p.module_stdout.read().strip().split('=')[1] except: @@ -348,7 +348,7 @@ # get value of raster cell at coordinate point try: cmdlist = ['r.what', 'input=%s' % self.rast1, 'east_north=%d,%d' % (east,north)] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.returncode == 0: output = p.module_stdout.read().strip().split('|') val = output[3] @@ -427,7 +427,7 @@ datalist = [] try: # cmdlist = ['r.profile', 'input=%s' % raster, 'profile=%s' % coords, 'null=nan', '--quiet'] -# p = cmd.Command(cmdlist, wait=False) +# p = gcmd.Command(cmdlist, wait=False) # output = p.module_stdout.read().strip().split('\n') # if p.returncode == 0: # for outline in output: Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -19,7 +19,7 @@ import os, sys, glob, math import utils -import gcmd as cmd +import gcmd from debug import Debug as Debug class MapLayer(object): @@ -127,7 +127,7 @@ (self.name, self.cmdlist)) return None - runcmd = cmd.Command(cmd=self.cmdlist + ['--q']) # run quiet + runcmd = gcmd.Command(cmd=self.cmdlist + ['--q']) # run quiet if runcmd.returncode != 0: print "Could not execute '%s'" % (self.cmdlist) for msg in runcmd.msg: @@ -276,7 +276,7 @@ "in GRASS GIS to run this program\n")) sys.exit(1) - gisenvCmd = cmd.Command(["g.gisenv"]) + gisenvCmd = gcmd.Command(["g.gisenv"]) for line in gisenvCmd.ReadStdOutput(): line = line.strip() @@ -398,7 +398,7 @@ os.unsetenv("GRASS_REGION") # do not update & shell style output - cmdRegion = cmd.Command(["g.region", "-u", "-g", "-p", "-c"]) + cmdRegion = gcmd.Command(["g.region", "-u", "-g", "-p", "-c"]) for reg in cmdRegion.ReadStdOutput(): reg = reg.strip() @@ -490,7 +490,7 @@ projinfo = {} - p = cmd.Command(['g.proj', '-p']) + p = gcmd.Command(['g.proj', '-p']) if p.returncode == 0: for line in p.ReadStdOutput(): Modified: trunk/grassaddons/gui/gui_modules/select.py =================================================================== --- trunk/grassaddons/gui/gui_modules/select.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/select.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -24,7 +24,7 @@ GuiModulePath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") sys.path.append(GuiModulePath) -import gcmd as cmd +import gcmd class SelectDialog(wx.Dialog): def __init__(self, parent, id=wx.ID_ANY, title='Select GIS element', @@ -156,11 +156,11 @@ """ #set environmental variables cmdlist = ['g.gisenv', 'get=MAPSET'] - curr_mapset = cmd.Command(cmdlist).module_stdout.read().strip() + curr_mapset = gcmd.Command(cmdlist).module_stdout.read().strip() #mapsets in current location cmdlist = ['g.mapsets', '-p'] - mapsets = cmd.Command(cmdlist).module_stdout.read().strip().split(' ') + mapsets = gcmd.Command(cmdlist).module_stdout.read().strip().split(' ') # map element types to g.mlist types elementdict = {'cell':'rast', @@ -219,7 +219,7 @@ self.seltree.SetItemTextColour(dir_node, wx.Colour(50,50,200)) try: cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] - elem_list = cmd.Command(cmdlist).module_stdout.read().strip().split('\n') + elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') elem_list.sort() for elem in elem_list: if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) @@ -230,7 +230,7 @@ self.seltree.SetItemTextColour(dir_node,wx.Colour(50,50,200)) try: cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] - elem_list = cmd.Command(cmdlist).module_stdout.read().strip().split('\n') + elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') elem_list.sort() for elem in elem_list: if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) Modified: trunk/grassaddons/gui/gui_modules/utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/utils.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/utils.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -16,7 +16,7 @@ import os -import gcmd as cmd +import gcmd def GetTempfile(pref=None): """ @@ -28,7 +28,7 @@ Path to file name (string) or None """ - tempfileCmd = cmd.Command(["g.tempfile", + tempfileCmd = gcmd.Command(["g.tempfile", "pid=%d" % os.getpid()]) Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -35,7 +35,7 @@ import menuform import mapdisp import render -import gcmd as cmd +import gcmd import grassenv import histogram from debug import Debug as Debug @@ -1101,7 +1101,7 @@ else: # process GRASS command with argument cmdlist.append('--verbose') - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) # deactivate computational region and return to display settings Modified: trunk/grassaddons/gui/location_wizard.py =================================================================== --- trunk/grassaddons/gui/location_wizard.py 2007-10-13 19:55:37 UTC (rev 1133) +++ trunk/grassaddons/gui/location_wizard.py 2007-10-13 20:49:07 UTC (rev 1134) @@ -27,18 +27,19 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ -import gui_modules -import gui_modules.cmd as cmd import os import shutil import re import string import sys + import wx import wx.lib.mixins.listctrl as listmix import wx.lib.rcsizer as rcs import wx.wizard as wiz +import gui_modules +import gui_modules.gcmd as gcmd try: import subprocess except: @@ -1186,7 +1187,7 @@ #Set current working environment to PERMANENT mapset in selected location in order to set default region (WIND) envval = {} cmdlist = ['g.gisenv'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.returncode == 0: output = p.module_stdout.read().strip("'").split(';\n') for line in output: @@ -1199,7 +1200,7 @@ pass else: cmdlist = ['g.mapset', 'location=%s' % self.location, 'mapset=PERMANENT'] - cmd.Command(cmdlist) + gcmd.Command(cmdlist) else: wx.MessageBox('A valid location must be selected') return @@ -1207,7 +1208,7 @@ #Get current region settings region = {} cmdlist = ['g.region', '-gp'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.returncode == 0: output = p.module_stdout.read().split('\n') for line in output: @@ -1355,7 +1356,7 @@ def OnSetButton(self,event=None): cmdlist = ['g.region', '-sgpa', 'n=%s' % self.north, 's=%s' % self.south, \ 'e=%s' % self.east, 'w=%s' % self.west, 'res=%s' % self.res] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.returncode == 0: output = p.module_stdout.read() wx.MessageBox('New default region:\n%s' % output) @@ -1695,7 +1696,7 @@ # Creating location from PROJ.4 string passed to g.proj try: cmdlist = ['g.proj', '-c', 'proj4=%s' % proj4string, 'location=%s' % location] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.module.returncode == 0: return True else: @@ -1724,7 +1725,7 @@ try: cmdlist = ['g.proj','-c','proj4=%s' % proj4string,'location=%s' % location] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.module.returncode == 0: return True else: @@ -1767,7 +1768,7 @@ # creating location try: cmdlist = ['g.proj','epsg=%s' % epsgcode,'datumtrans=-1'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) dtoptions = p.module_stdout.read() if dtoptions != None: dtrans = '' @@ -1794,7 +1795,7 @@ else: cmdlist = ['g.proj','-c','epsg=%s' % epsgcode,'location=%s' % location,'datumtrans=1'] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.module.returncode == 0: return True else: @@ -1842,7 +1843,7 @@ # creating location try: cmdlist = ['g.proj','-c','georef=%s' % georeffile,'location=%s' % location] - p = cmd.Command(cmdlist) + p = gcmd.Command(cmdlist) if p.module.returncode == 0: return True else: From landa at grass.itc.it Sun Oct 14 11:30:15 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sun Oct 14 11:30:17 2007 Subject: [grass-addons] r1135 - trunk/grassaddons/gui/gui_modules Message-ID: <200710140930.l9E9UF7C016648@grass.itc.it> Author: landa Date: 2007-10-14 11:30:12 +0200 (Sun, 14 Oct 2007) New Revision: 1135 Modified: trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py Log: Minor fixes in GMConsole & gcmd, command output widget need to be improved... Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-13 20:49:07 UTC (rev 1134) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-14 09:30:12 UTC (rev 1135) @@ -1,5 +1,5 @@ """ -PACKAGE: gcmd +MODULE: gcmd CLASSES: * EndOfCommand @@ -9,7 +9,7 @@ AUTHORS: The GRASS Development Team Original author: Jachym Cepicky - Various updates: Martin Landa + Various updates: Martin Landa COPYRIGHT: (C) 2007 by the GRASS Development Team This program is free software under the GNU General Public @@ -50,7 +50,7 @@ Parameters: cmd - command string (given as list) stdin - standard input stream - verbose - verbose mode (GRASS commands '--v') (default: False) + verbose - verbose mode [0; 3] wait - wait for childer execution dlgMsg - type of error message (None, gui, txt) [only if wait=True] @@ -66,14 +66,23 @@ """ def __init__ (self, cmd, stdin=None, - verbose=False, wait=True, dlgMsg='gui'): + verbose=0, wait=True, dlgMsg='gui'): # # input # self.module_stdin = None self.cmd = cmd + self.dlgMsg = dlgMsg # + # set verbosity level + # + if verbose == 0 and '--q' not in self.cmd: + self.cmd.append('--q') + elif verbose == 3 and '--v' not in self.cmd: + self.cmd.append('--v') + + # # GRASS module # self.module = None @@ -82,14 +91,13 @@ # output # self.module_stderr = None - self.module_msg = [] # list of messages (msgtype, content) # # set message formatting # message_format = os.getenv("GRASS_MESSAGE_FORMAT") - # os.environ["GRASS_MESSAGE_FORMAT"] = "gui" - os.environ["GRASS_MESSAGE_FORMAT"] = "txt" + os.environ["GRASS_MESSAGE_FORMAT"] = "gui" + # os.environ["GRASS_MESSAGE_FORMAT"] = "txt" # # run command ... @@ -121,35 +129,28 @@ else: os.unsetenv("GRASS_MESSAGE_FORMAT") - # - # read stderr - # ... - # self.messages = [] - # self.errors = [] - # self.warnings = [] + # list of messages (<- stderr) + # -> [(type, content)] type = (error, warning, message) + self.module_msg = self.__ProcessStdErr() # -> self.module_msg - # try: - # self.__ProcessMessages() # -> messages, errors, warnings - # except EndOfCommand: - # pass - if self.module: if wait: self.module.wait() self.returncode = self.module.returncode # failed? - if dlgMsg and self.returncode != 0: - errs = self.ReadErrOutput() - if dlgMsg == 'gui': # GUI dialog + if self.dlgMsg and self.returncode != 0: + if self.dlgMsg == 'gui': # GUI dialog dlg = wx.MessageDialog(None, - ("Execution failed: '%s'\n\nDetails:\n%s") % (' '.join(self.cmd), '\n'.join(errs)), + ("Execution failed: '%s'\n\n" + "Details:\n%s") % (' '.join(self.cmd), + self.PrintModuleOutput()), ("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() else: # otherwise 'txt' print >> sys.stderr, "Execution failed: '%s'" % (' '.join(self.cmd)) - print >> sys.stderr, "Details:\n%s" % '\n'.join(errs) + print >> sys.stderr, "\nDetails:\n%s" % self.PrintModuleOutput() else: self.returncode = None # running ? @@ -161,28 +162,36 @@ Debug.msg (3, "Command(): cmd='%s', wait=%d, returncode=?" % \ (' '.join(self.cmd), wait)) - def __ProcessMessages(self): + def __ProcessStdErr(self): """ Read messages/warnings/errors from stderr """ - msgtype = None - content = None - line = None + lines = self.ReadErrOutput() - while True: - line = self.module_stderr.readline() - if not line: - raise EndOfCommand - if line.find(':') > -1: - msgtype, content = line.split(":", 1) - content = content.strip() - if msgtype.find("GRASS_INFO_ERROR"): - self.errors.append(content) - elif msgtype.find("GRASS_INFO_WARNING") > -1: - self.warnings.append(content) - else: - self.messages.append(content) + msg = [] + type = None + content = "" + for line in lines: + if len(line) == 0: + continue + if 'GRASS_' in line: # error or warning + if 'GRASS_INFO_WARNING' in line: # warning + type = "WARNING" + elif 'GRASS_INFO_ERROR' in line: # error + type = "ERROR" + elif 'GRASS_INFO_END': # end of message + msg.append((type, content)) + type = None + content = "" + + if type: + content += line.split(':')[1].strip() + else: # stderr + msg.append((None, line.strip())) + + return msg + def __ReadOutput(self, stream): """Read stream and return list of lines @@ -207,8 +216,22 @@ """Read standard error output and return list""" return self.__ReadOutput(self.module_stderr) + + def PrintModuleOutput(self, error=True, warning=True, message=True, rest=False): + """Print module errors, warnings, messages...""" - + msgString = "" + for type, msg in self.module_msg: + if type: + if (type == 'ERROR' and error) or \ + (type == 'WARNING' and warning) or \ + (type == 'MESSAGE' and message): + msgString += " " + type + ": " + msg + "\n" + else: + msgString += " " + msg + "\n" + + return msgString + # testing ... if __name__ == "__main__": SEP = "-----------------------------------------------------------------------------" @@ -232,7 +255,7 @@ # v.net.path silently, wait for process termination print "Running v.net.path for 0 593527.6875 4925297.0625 602083.875 4917545.8125..." - cmd = Command(cmd=["v.net.path", "in=roads@PERMANENT", "out=tmp dmax=100000", "--o"], + cmd = Command(cmd=["v.net.path", "in=roads@PERMANENT", "out=tmp", "dmax=100000", "--o"], stdin="0 593527.6875 4925297.0625 602083.875 4917545.8125", verbose=False, wait=True, dlgMsg='txt') Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-13 20:49:07 UTC (rev 1134) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-14 09:30:12 UTC (rev 1135) @@ -858,11 +858,6 @@ self.layers[layer].AddProperties (propwin) - def writeDCommand(self, dcmd): - # echos d.* command to output console - global goutput - goutput.write(dcmd+"\n----------\n") - def ReorderLayers(self): """Add commands from data associated with any valid layers (checked or not) to layer list in order to @@ -920,7 +915,7 @@ self.mapdisplay.ReRender(None) def setNotebookPage(self,pg): - self.Parent.notebook.SetSelection(pg) + self.parent.notebook.SetSelection(pg) def OnCloseWindow(self, event): pass @@ -931,53 +926,55 @@ Create and manage output console for commands entered on the GIS Manager command line. """ - def __init__(self, parent, id=-1, - pos=wx.DefaultPosition, size=wx.DefaultSize, - style=wx.TAB_TRAVERSAL|wx.FULL_REPAINT_ON_RESIZE): + def __init__(self, parent, id=wx.ID_ANY, + pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.TAB_TRAVERSAL|wx.FULL_REPAINT_ON_RESIZE): wx.Panel.__init__(self, parent, id, pos, size, style) - #initialize variables - self.Map = '' - self.parent = parent - self.cmd_output = "" + + # initialize variables + self.Map = None + self.parent = parent # GMFrame + self.cmd_output = "" self.console_command = "" - self.console_clear = "" - self.console_save = "" - self.gcmdlst = [] #list of commands in bin and scripts + self.console_clear = "" + self.console_save = "" + self.gcmdlst = [] # list of commands in bin and scripts - #text control for command output - self.cmd_output = wx.TextCtrl(self, -1, "", - style=wx.TE_MULTILINE| - wx.TE_READONLY) + # text control for command output + self.cmd_output = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", + style=wx.TE_MULTILINE| wx.TE_READONLY) self.cmd_output.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, '')) - global goutput - goutput = self.cmd_output - self.console_clear = wx.Button(self, -1, "Clear") - self.console_save = wx.Button(self, -1, "Save") - - self.console_progressbar = wx.Gauge(self, -1, 100, (110, 50), (250, 25)) - + # buttons + self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR) + self.console_save = wx.Button(parent=self, id=wx.ID_SAVE) self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear) self.Bind(wx.EVT_BUTTON, self.SaveHistory, self.console_save) + # progress bar + self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY, + range=100, pos=(110, 50), size=(-1, 25)) + # output control layout boxsizer1 = wx.BoxSizer(wx.VERTICAL) - gridsizer1 = wx.GridSizer(1, 2, 0, 0) - boxsizer1.Add(self.cmd_output, 1, - wx.EXPAND|wx.ADJUST_MINSIZE, 0) - gridsizer1.Add(self.console_clear, 0, - wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 0) - gridsizer1.Add(self.console_save, 0, - wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 0) + gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0) + boxsizer1.Add(item=self.cmd_output, proportion=1, + flag=wx.EXPAND | wx.ADJUST_MINSIZE, border=0) + gridsizer1.Add(item=self.console_clear, proportion=0, + flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0) + gridsizer1.Add(item=self.console_save, proportion=0, + flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0) - boxsizer1.Add((0,5)) - boxsizer1.Add(gridsizer1, 0, wx.EXPAND|wx.ALIGN_CENTRE_VERTICAL) - boxsizer1.Add((0,5)) - boxsizer1.Add(self.console_progressbar, 0, - wx.EXPAND|wx.ADJUST_MINSIZE, 0) + boxsizer1.Add(item=gridsizer1, proportion=0, + flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.TOP | wx.BOTTOM, + border=5) + boxsizer1.Add(item=self.console_progressbar, proportion=0, + flag=wx.EXPAND | wx.ADJUST_MINSIZE, border=0) + boxsizer1.Fit(self) boxsizer1.SetSizeHints(self) + self.SetAutoLayout(True) self.SetSizer(boxsizer1) @@ -997,11 +994,10 @@ def RunCmd(self, command): """ Run in GUI or shell GRASS (or other) commands typed into - console command text widget, echo command to - output text widget, and send stdout output to output + console command text widget, and send stdout output to output text widget. - Command is transformed into a list for processing + Command is transformed into a list for processing. TODO: Display commands (*.d) are captured and processed separately by mapdisp.py. Display commands are @@ -1011,12 +1007,12 @@ # create list of available GRASS commands gcmdlst = self.GetGRASSCmds() - # cmd = self.console_command.GetLineText(0) + + # map display window available ? try: - curr_disp = self.Parent.Parent.curr_page.maptree.mapdisplay + curr_disp = self.parent.curr_page.maptree.mapdisplay self.Map = curr_disp.GetRender() except: - ## disp_idx = None curr_disp = None try: @@ -1028,7 +1024,6 @@ if len(cmdlist) == 1 and cmdlist[0] in gcmdlst: # send GRASS command without arguments to GUI command interface # except display commands (they are handled differently) - global gmpath if command[0:2] == "d.": try: layertype = {'d.rast' : 'raster', @@ -1047,22 +1042,20 @@ 'd.labels' : 'labels'}[command] except KeyError: print _('Command type not yet implemented') - return + return False # add layer - self.Parent.Parent.curr_page.maptree.AddLayer(layertype) + self.parent.curr_page.maptree.AddLayer(layertype) else: menuform.GUI().ParseCommand(string.join(cmdlist), parentframe=None) - self.cmd_output.write(string.join(cmdlist) + "\n----------\n") + #self.cmd_output.write(string.join(cmdlist) + "\n----------\n") elif command[0:2] == "d." and len(cmdlist) > 1: - """ - Send GRASS display command(s)with arguments - to the display processor and echo to command output console. - Accepts a list of d.* commands separated by semi-colons. - Display with focus receives display command(s). - """ + # Send GRASS display command(s)with arguments + # to the display processor and echo to command output console. + # Accepts a list of d.* commands separated by semi-colons. + # Display with focus receives display command(s). self.cmd_output.write("$" + ' '.join(cmdlist)) @@ -1083,72 +1076,46 @@ else: # Send any other command to the shell. Send output to # console output window. - try: - os.environ["GRASS_MESSAGE_FORMAT"] = "gui" - #self.cmd_output.write(command+"\n----------\n") - self.cmd_output.write("$ " + ' '.join(cmdlist) + "\n") + + if self.parent.notebook.GetSelection() != 1: + # select 'Command output' tab + self.parent.notebook.SetSelection(1) + + self.cmd_output.write("$ " + ' '.join(cmdlist) + "\n") + + if cmdlist[0] not in gcmdlst: + # if command is not a GRASS command, treat it like a shell command + generalCmd = subprocess.Popen(cmdlist, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + + for outline in runCmd.stdout: + self.cmd_output.write(outline) + else: # activate compuational region (set with g.region) for all non-display commands. tmpreg = os.getenv("GRASS_REGION") os.unsetenv("GRASS_REGION") + # process GRASS command with argument + grassCmd = gcmd.Command(cmdlist, verbose=3) - if cmdlist[0] not in gcmdlst: - # if command is not a GRASS command, treat it like a shell command - output = os.popen(command, "r").read().strip().split('\n') - for outline in output: - self.cmd_output.write(outline+'\n') - return - else: - # process GRASS command with argument - cmdlist.append('--verbose') - p = gcmd.Command(cmdlist) - - + # deactivate computational region and return to display settings if tmpreg: os.environ["GRASS_REGION"] = tmpreg - oline = p.module_stderr.readline() - while oline: - oline = oline.strip() - oline = p.module_stderr.readline() - # make some progress - #GRASS_INFO_PERCENT: 100 - if oline.find("GRASS_INFO_PERCENT")>-1: - self.console_progressbar.SetValue(int(oline.split()[1])) - elif oline.find("GRASS_INFO_MESSAGE")>-1: - self.cmd_output.write(string.split(oline,maxsplit=1)[1]+"\n") - elif oline.find("GRASS_INFO_WARNING")>-1: - self.cmd_output.write("WARNING: "+string.split(oline,maxsplit=1)[1]+"\n") - elif oline.find("GRASS_INFO_ERROR")>-1: - self.cmd_output.write("ERROR: "+string.split(oline,maxsplit=1)[1]+"\n") + if grassCmd.returncode != 0: + return False - oline = p.module_stdout.readline() - while oline: - oline = oline.strip() - if command[0] == 'r.what': - rastqlist = oline.split('|') - self.cmd_output.write('East: '+rastqlist[0]+"\n") - self.cmd_output.write('North: '+rastqlist[1]+"\n") - self.cmd_output.write(rastqlist[2]+"\n") - data = rastqlist[3:] - for x in range(0,len(data),2): - self.cmd_output.write('Category: '+data[x]+"\n") - self.cmd_output.write('Label: '+data[x+1]+"\n") - else: - self.cmd_output.write(oline+"\n") - print >> sys.stderr, oline - oline = p.module_stdout.readline() - #self.cmd_output.write("\n==========\n") - self.cmd_output.write("\n") - if p.module_stdout < 0: - print >> sys.stderr, "Child was terminated by signal", p.module_stdout - elif p.module_stdout > 0: - #print >> sys.stderr, p.module_stdout - pass - except OSError, e: - print >> sys.stderr, "Execution failed:", e + # if oline.find("GRASS_INFO_PERCENT")>-1: + # self.console_progressbar.SetValue(int(oline.split()[1])) + for line in grassCmd.ReadStdOutput(): + self.cmd_output.write(line + '\n') + + return True + def ClearHistory(self, event): """Clear history of commands""" self.cmd_output.Clear() From landa at grass.itc.it Sun Oct 14 11:34:09 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sun Oct 14 11:34:10 2007 Subject: [grass-addons] r1136 - trunk/grassaddons/gui/gui_modules Message-ID: <200710140934.l9E9Y9P3016829@grass.itc.it> Author: landa Date: 2007-10-14 11:34:07 +0200 (Sun, 14 Oct 2007) New Revision: 1136 Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py Log: Bugfix for GMConsole.SaveHistory(). Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-14 09:30:12 UTC (rev 1135) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-14 09:34:07 UTC (rev 1136) @@ -1131,16 +1131,17 @@ #Use a standard dialog for this wildcard = "Text file (*.txt)|*.txt" dlg = wx.FileDialog( - self, message="Save file as ...", defaultDir=os.getcwd(), - defaultFile="grass_cmd_history.txt", wildcard=wildcard, style=wx.SAVE|wx.FD_OVERWRITE_PROMPT - ) + self, message=_("Save file as ..."), defaultDir=os.getcwd(), + defaultFile="grass_cmd_history.txt", wildcard=wildcard, + style=wx.SAVE|wx.FD_OVERWRITE_PROMPT) # Show the dialog and retrieve the user response. If it is the OK response, # process the data. if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() - output = open(path,"w") - output.write(self.history) - output.close() + output = open(path,"w") + output.write(self.history) + output.close() + dlg.Destroy() From landa at grass.itc.it Tue Oct 16 13:49:22 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 16 13:49:24 2007 Subject: [grass-addons] r1137 - in trunk/grassaddons/gui: . gui_modules icons icons/silk Message-ID: <200710161149.l9GBnMPl022158@grass.itc.it> Author: landa Date: 2007-10-16 13:49:11 +0200 (Tue, 16 Oct 2007) New Revision: 1137 Added: trunk/grassaddons/gui/gui_modules/grass-grc.dtd trunk/grassaddons/gui/icons/silk/folder.png trunk/grassaddons/gui/icons/silk/page_save.png trunk/grassaddons/gui/icons/silk/page_white.png Modified: trunk/grassaddons/gui/gui_modules/grass-interface.dtd trunk/grassaddons/gui/gui_modules/menudata.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/icons/icon.py trunk/grassaddons/gui/icons/silk/__init__.py trunk/grassaddons/gui/wxgui.py Log: Support for workspace file added (currently only basic prototype of "Save workspace to file" implemented). Added: trunk/grassaddons/gui/gui_modules/grass-grc.dtd =================================================================== --- trunk/grassaddons/gui/gui_modules/grass-grc.dtd (rev 0) +++ trunk/grassaddons/gui/gui_modules/grass-grc.dtd 2007-10-16 11:49:11 UTC (rev 1137) @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Modified: trunk/grassaddons/gui/gui_modules/grass-interface.dtd =================================================================== --- trunk/grassaddons/gui/gui_modules/grass-interface.dtd 2007-10-14 09:34:07 UTC (rev 1136) +++ trunk/grassaddons/gui/gui_modules/grass-interface.dtd 2007-10-16 11:49:11 UTC (rev 1137) @@ -1,14 +1,18 @@ - + @@ -132,6 +136,7 @@ )? --> + @@ -146,4 +151,6 @@ - + + Modified: trunk/grassaddons/gui/gui_modules/menudata.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-14 09:34:07 UTC (rev 1136) +++ trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-16 11:49:11 UTC (rev 1137) @@ -25,6 +25,14 @@ def GetMenu(self): return [( ("File", ( + ("Workspace (not functional)", ( + ("Open", "Create new workspace file (erase current workspace settings first", "self.OnWorkspaceNew", ""), + ("Open", "Open existing workspace file", "self.OnWorkspaceOpen", ""), + ("Save", "Save current workspace to file", "self.OnWorkspaceSave", ""), + ("Save as", "Save current workspace as...", "self.OnWorkspaceSave", ""), +# ("Close", "Close workspace file", "self.OnWorkspaceClose", ""), + )), + ("","","", ""), ("Import raster map", ( ("Multiple import formats using GDAL", "Import multiple formats using GDAL", "self.OnMenuCmd", "r.in.gdal"), ("","","", ""), Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-14 09:34:07 UTC (rev 1136) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-16 11:49:11 UTC (rev 1137) @@ -50,7 +50,7 @@ Abstract layer in LayerTree Attributes: - * type - layer type ('cmdlayer', 'group', etc) -- see LayerTree.AddLayer() + * type - layer type ('cmdlayer', 'group', etc) -- see LayerTree.AddLayer() """ def __init__(self, type): @@ -499,45 +499,45 @@ ltype) if ltype == 'raster': - menuform.GUI().ParseCommand('d.rast', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.rast', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rgb': - menuform.GUI().ParseCommand('d.rgb', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.rgb', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'his': - menuform.GUI().ParseCommand('d.his', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.his', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'shaded': - menuform.GUI().ParseCommand('d.shadedmap', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.shadedmap', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rastarrow': - menuform.GUI().ParseCommand('d.rast.arrow', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.rast.arrow', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rastnum': - menuform.GUI().ParseCommand('d.rast.num', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.rast.num', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'vector': - menuform.GUI().ParseCommand('d.vect', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.vect', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'thememap': menuform.GUI().ParseCommand('d.vect.thematic', - completed=(self.getOptData,layer,params), + completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'themechart': menuform.GUI().ParseCommand('d.vect.chart', - completed=(self.getOptData,layer,params), + completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'grid': - menuform.GUI().ParseCommand('d.grid', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.grid', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'geodesic': - menuform.GUI().ParseCommand('d.geodesic', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.geodesic', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rhumb': - menuform.GUI().ParseCommand('d.rhumbline', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.rhumbline', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'labels': - menuform.GUI().ParseCommand('d.labels', completed=(self.getOptData,layer,params), + menuform.GUI().ParseCommand('d.labels', completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'cmdlayer': pass @@ -823,7 +823,8 @@ # completed drag and drop self.drag = False - def getOptData(self, dcmd, layer, params, propwin): + def GetOptData(self, dcmd, layer, params, propwin): + """Process layer data""" for item in dcmd: if 'map=' in item: mapname = item.split('=')[1] Modified: trunk/grassaddons/gui/icons/icon.py =================================================================== --- trunk/grassaddons/gui/icons/icon.py 2007-10-14 09:34:07 UTC (rev 1136) +++ trunk/grassaddons/gui/icons/icon.py 2007-10-16 11:49:11 UTC (rev 1137) @@ -65,6 +65,9 @@ "digExit" : 'exit.gif', # gis manager "newdisplay" : 'gui-startmon.gif', + "workspaceNew" : 'file-new.gif', + "workspaceOpen" : 'file-open.gif', + "workspaceSave" : 'file-save.gif', "addrast" : 'element-cell.gif', "addvect" : 'element-vector.gif', "addcmd" : 'gui-cmd.gif', @@ -210,6 +213,9 @@ "printmap" : MetaIcon (img=icons_img["printmap"], label="Print display"), # gis manager "newdisplay" : MetaIcon (img=icons_img["newdisplay"], label="Start new display"), + "workspaceNew" : MetaIcon (img=icons_img["workspaceNew"], label="Create new workspace file"), + "workspaceOpen" : MetaIcon (img=icons_img["workspaceOpen"], label="Open existing workspace file"), + "workspaceSave" : MetaIcon (img=icons_img["workspaceSave"], label="Save current workspace to file"), "addrast" : MetaIcon (img=icons_img["addrast"], label="Add raster map layer"), "addvect" : MetaIcon (img=icons_img["addvect"], label="Add vector map layer"), "addcmd" : MetaIcon (img=icons_img["addcmd"], label="Add command layer"), Modified: trunk/grassaddons/gui/icons/silk/__init__.py =================================================================== --- trunk/grassaddons/gui/icons/silk/__init__.py 2007-10-14 09:34:07 UTC (rev 1136) +++ trunk/grassaddons/gui/icons/silk/__init__.py 2007-10-16 11:49:11 UTC (rev 1137) @@ -57,6 +57,9 @@ "digExit" : 'door_in.png', # gis manager "newdisplay" : 'application_add.png', + "workspaceNew" : 'page_white.png', + "workspaceOpen" : 'folder.png', + "workspaceSave" : 'page_save.png', "addrast" : 'image_add.png', "addshaded" : 'picture_empty.png', "addrarrow" : 'arrow_inout.png', Added: trunk/grassaddons/gui/icons/silk/folder.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/icons/silk/folder.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/icons/silk/page_save.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/icons/silk/page_save.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/grassaddons/gui/icons/silk/page_white.png =================================================================== (Binary files differ) Property changes on: trunk/grassaddons/gui/icons/silk/page_white.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-14 09:34:07 UTC (rev 1136) +++ trunk/grassaddons/gui/wxgui.py 2007-10-16 11:49:11 UTC (rev 1137) @@ -404,6 +404,81 @@ wx.AboutBox(info) + def OnWorkspaceNew(self, event): + """Create new workspace file + + Erase current workspace settings first""" + pass + + def OnWorkspaceOpen(self, event): + """Open file with workspace definition""" + dlg = wx.FileDialog(parent=self, message=_("Choose workspace file"), + defaultDir=os.getcwd(), wildcard="*.grc") + + filename = '' + if dlg.ShowModal() == wx.ID_OK: + filename = dlg.GetFilename() + + Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename) + + def OnWorkspaceSave(self, event): + """Save file with workspace definition""" + + filename = "test-out.grc" + + self.SaveLayerTreeToGrcXml(filename) + + def SaveLayerTreeToGrcXml(self, filename): + """Save layer tree layout to workspace file""" + + file = open(filename, "w") + #file = sys.stderr + try: + # write header + file.write('\n') + file.write('\n') + file.write('\n') + # list of layers + mapTree = self.curr_page.maptree + root = mapTree.GetRootItem() + childitem = mapTree.GetFirstChild(root) + item = childitem[0] + cookie = childitem[1] + for n in range(0, mapTree.GetChildrenCount(root)): + layer = mapTree.layers[item] + type = layer.type + name = mapTree.GetItemText(item) + checked = int(item.IsChecked()) + opacity = layer.maplayer.GetOpacity(float=True) + file.write(' \n' % \ + (type, name, checked, opacity)); + # layer properties + cmd = mapTree.GetPyData(item)[0] + file.write(' \n' % cmd[0]) + for option in cmd[1:]: + if option[0] == '-': # flag + file.write(' \n' % option[1]) + else: # parameter + key, value = option.split('=') + file.write(' \n' % key) + file.write(' %s\n' % value) + file.write(' \n'); + file.write(' \n'); + file.write(' \n'); + item = mapTree.GetNextChild(item, cookie)[0] + file.write('\n') + finally: + pass + #file.close() + + def OnWorkspaceClose(self, event): + """Close file with workspace definition + + If workspace has been modified ask user to save the changes. + """ + pass + + def RulesCmd(self, event): """ Launches dialog for commands that need rules @@ -414,8 +489,10 @@ if dlg.ShowModal() == wx.ID_OK: gtemp = utils.GetTempfile() output = open(gtemp,"w") - output.write(dlg.rules) - output.close() + try: + output.write(dlg.rules) + finally: + output.close() if command == 'r.colors': cmdlist = [command,'map=%s' % dlg.inmap,'rules=%s' % gtemp,'--verbose'] @@ -425,10 +502,8 @@ if dlg.overwrite == True: cmdlist.append('--o') - cmdlist.append('--verbose') + gcmd.Command(cmdlist, verbose=3) - gcmd.Command(cmdlist) - dlg.Destroy() def OnXTerm(self, event): @@ -523,11 +598,11 @@ """Creates toolbar""" toolbar = self.CreateToolBar() - for each in self.toolbarData(): - self.addToolbarButton(toolbar, *each) + for each in self.ToolbarData(): + self.AddToolbarButton(toolbar, *each) toolbar.Realize() - def addToolbarButton(self, toolbar, label, icon, help, handler): + def AddToolbarButton(self, toolbar, label, icon, help, handler): """Adds button to the given toolbar""" if not label: @@ -536,11 +611,15 @@ tool = toolbar.AddLabelTool(id=wx.ID_ANY, label=label, bitmap=icon, shortHelp=help) self.Bind(wx.EVT_TOOL, handler, tool) - def toolbarData(self): + def ToolbarData(self): return ( ('newdisplay', Icons["newdisplay"].GetBitmap(), Icons["newdisplay"].GetLabel(), self.NewDisplay), ('', '', '', ''), + ('workspaceNew', Icons["workspaceNew"].GetBitmap(), Icons["workspaceNew"].GetLabel(), self.OnWorkspaceNew), + ('workspaceOpen', Icons["workspaceOpen"].GetBitmap(), Icons["workspaceOpen"].GetLabel(), self.OnWorkspaceOpen), + ('workspaceSave', Icons["workspaceSave"].GetBitmap(), Icons["workspaceSave"].GetLabel(), self.OnWorkspaceSave), + ('', '', '', ''), ('addrast', Icons["addrast"].GetBitmap(), Icons["addrast"].GetLabel(), self.OnRaster), ('addvect', Icons["addvect"].GetBitmap(), Icons["addvect"].GetLabel(), self.OnVector), ('addcmd', Icons["addcmd"].GetBitmap(), Icons["addcmd"].GetLabel(), self.AddCommand), @@ -841,15 +920,10 @@ self.DeleteAllPages() except: pass -# self.DestroyChildren() + # self.DestroyChildren() self._auimgr.UnInit() self.Destroy() - def Nomethod(self, event): - '''Stub for testing''' - pass - event.Skip() - def MsgNoLayerSelected(self): """Show dialog message 'No layer selected'""" dlg = wx.MessageDialog(self, _("No layer selected"), _("Error"), wx.OK | wx.ICON_ERROR) From landa at grass.itc.it Tue Oct 16 21:52:28 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 16 21:52:29 2007 Subject: [grass-addons] r1138 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710161952.l9GJqS2B031057@grass.itc.it> Author: landa Date: 2007-10-16 21:52:16 +0200 (Tue, 16 Oct 2007) New Revision: 1138 Modified: trunk/grassaddons/gui/gui_modules/menudata.py trunk/grassaddons/gui/gui_modules/menuform.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/wxgui.py Log: Open workspace file implemented (not fully). Will be fixed. Modified: trunk/grassaddons/gui/gui_modules/menudata.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-16 11:49:11 UTC (rev 1137) +++ trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-16 19:52:16 UTC (rev 1138) @@ -26,7 +26,7 @@ return [( ("File", ( ("Workspace (not functional)", ( - ("Open", "Create new workspace file (erase current workspace settings first", "self.OnWorkspaceNew", ""), + ("New", "Create new workspace file (erase current workspace settings first", "self.OnWorkspaceNew", ""), ("Open", "Open existing workspace file", "self.OnWorkspaceOpen", ""), ("Save", "Save current workspace to file", "self.OnWorkspaceSave", ""), ("Save as", "Save current workspace as...", "self.OnWorkspaceSave", ""), Modified: trunk/grassaddons/gui/gui_modules/menuform.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-16 11:49:11 UTC (rev 1137) +++ trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-16 19:52:16 UTC (rev 1138) @@ -1152,7 +1152,10 @@ if 'flags' in dcmd_params: self.grass_task.flags = dcmd_params['flags'] - self.mf = mainFrame(parent=self.parent, ID=wx.ID_ANY, task_description=self.grass_task, get_dcmd=get_dcmd, layer=layer) + self.mf = mainFrame(parent=self.parent, ID=wx.ID_ANY, + task_description=self.grass_task, + get_dcmd=get_dcmd, layer=layer) + self.mf.Show(True) self.mf.MakeModal(modal) Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-16 11:49:11 UTC (rev 1137) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-16 19:52:16 UTC (rev 1138) @@ -373,7 +373,7 @@ """Rename layer""" self.EditLabel(self.layer_selected) - def AddLayer(self, ltype): + def AddLayer(self, ltype, lname=None, lchecked=None, lopacity=None, lproperties=None): """Add new item to the layer tree, create corresponding MapLayer instance. Launch property dialog if needed (raster, vector, etc.)""" self.first = True @@ -427,14 +427,14 @@ newlayer = self.layers[layer] = Layer(type=ltype, wxCtrl=ctrl) # layer is initially unchecked as inactive (beside 'command') + # use predefined value if given + if lchecked: + checked = lchecked self.CheckItem(layer, checked=checked) # select item self.SelectItem(layer) - # add a data object to hold the layer's command (does not apply to generic command layers) - self.SetPyData(layer, (None,None)) - # add text and icons for each layer ltype if ltype == 'raster': self.SetItemImage(layer, self.rast_icon) @@ -481,13 +481,36 @@ self.SetItemImage(layer, self.folder) self.SetItemText(layer, grouptext) + # use predefined layer name if given + if lname: self.SetItemText(layer, lname) + self.first = False if ltype != 'group': - newlayer.AddMapLayer(self.Map.AddLayer(type=ltype, command=[], - l_active=checked, l_hidden=False, l_opacity=1, l_render=False)) - self.PropertiesDialog(layer) + if lopacity: + opacity = lopacity + else: + opacity = 1.0 + if lproperties: + cmd = lproperties + render = True + name = self.GetLayerNameFromCmd(cmd) + else: + cmd = [] + render = False + name = None + newlayer.AddMapLayer(self.Map.AddLayer(type=ltype, command=cmd, name=name, + l_active=checked, l_hidden=False, + l_opacity=opacity, l_render=render)) + if lproperties: + self.SetPyData(layer, (cmd,None)) + else: + # add a data object to hold the layer's command (does not apply to generic command layers) + self.SetPyData(layer, (None,None)) + # run properties dialog if no properties given + self.PropertiesDialog(layer) + def PropertiesDialog (self, layer): """Launch the properties dialog""" global gmpath @@ -569,19 +592,25 @@ except: pass - Debug.msg (3, "LayerTree.OnDeleteLayer(): name=%s" % \ - (self.GetItemText(item))) + if item != self.root: + Debug.msg (3, "LayerTree.OnDeleteLayer(): name=%s" % \ + (self.GetItemText(item))) + else: + self.root = None # unselect item self.Unselect() self.layer_selected = None - layer = self.layers[item] - if layer.type != 'group': - self.Map.DeleteLayer(layer.maplayer) + try: + layer = self.layers[item] + if layer.type != 'group': + self.Map.DeleteLayer(layer.maplayer) + + self.layers.pop(item) + except: + pass - self.layers.pop(item) - # redraw map if auto-rendering is enabled if self.mapdisplay.autoRender.GetValue(): self.mapdisplay.ReRender(None) @@ -589,6 +618,8 @@ if self.mapdisplay.digittoolbar: self.mapdisplay.digittoolbar.UpdateListOfLayers (updateTool=True) + event.Skip() + def OnLayerChecked(self, event): """Enable/disable given layer item""" item = event.GetItem() @@ -823,8 +854,9 @@ # completed drag and drop self.drag = False - def GetOptData(self, dcmd, layer, params, propwin): - """Process layer data""" + def GetLayerNameFromCmd(self, dcmd): + """Get layer name from GRASS command""" + mapname = '' for item in dcmd: if 'map=' in item: mapname = item.split('=')[1] @@ -842,8 +874,14 @@ mapname = 'rhumb' elif 'labels=' in item: mapname = item.split('=')[1]+' labels' + + return mapname + def GetOptData(self, dcmd, layer, params, propwin): + """Process layer data""" + # set layer text to map name + mapname = self.GetLayerNameFromCmd(dcmd) self.SetItemText(layer, mapname) # add command to layer's data Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-16 11:49:11 UTC (rev 1137) +++ trunk/grassaddons/gui/wxgui.py 2007-10-16 19:52:16 UTC (rev 1138) @@ -7,6 +7,7 @@ * GRasterDialog * GMFrame * GMApp + * ProcessGrcXml PURPOSE: Main Python app for GRASS wxPython GUI. Main menu, layer management toolbar, notebook control for display management and access to @@ -15,7 +16,7 @@ AUTHORS: The GRASS Development Team Michael Barton (Arizona State University) Jachym Cepicky (Mendel University of Agriculture) - Martin Landa + Martin Landa COPYRIGHT: (C) 2006-2007 by the GRASS Development Team This program is free software under the GNU General Public @@ -29,6 +30,15 @@ import time import traceback import types +import re +# for GRC (workspace file) parsering +from xml.parsers.xmlproc import xmlproc +from xml.parsers.xmlproc import xmlval +from xml.parsers.xmlproc import xmldtd +import xml.sax +import xml.sax.handler +HandlerBase=xml.sax.handler.ContentHandler +from xml.sax import make_parser import wx import wx.aui @@ -408,8 +418,15 @@ """Create new workspace file Erase current workspace settings first""" - pass + # TODO: ask user to save current settings + + maptree = self.curr_page.maptree + maptree.DeleteAllItems() + # add new root element + maptree.root = maptree.AddRoot("Map Layers") + self.curr_page.maptree.SetPyData(maptree.root, (None,None)) + def OnWorkspaceOpen(self, event): """Open file with workspace definition""" dlg = wx.FileDialog(parent=self, message=_("Choose workspace file"), @@ -421,19 +438,108 @@ Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename) + self.LoadGrcXmlToLayerTree(filename) + + def LoadGrcXmlToLayerTree(self, filename): + """Load layer tree definition stored in GRC XML file + + Return True on success + Return False on error""" + + # dtd + gisbase = os.getenv("GISBASE") + dtdFilename = os.path.join(gisbase, "etc", "wx", "gui_modules", "grass-grc.dtd") + + # parse xml agains dtd + dtd = xmldtd.load_dtd(dtdFilename) + parser = xmlproc.XMLProcessor() + parser.set_application(xmlval.ValidatingApp(dtd, parser)) + parser.dtd = dtd + parser.ent = dtd + try: + # TODO: set_error_handler(self,err) + parser.parse_resource(filename) + except: + dlg = wx.MessageDialog(self, _("Unable to open workspace file <%s>. " + "It is not valid GRC XML file.") % filename, + _("Error"), wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False + + # delete current layer tree content + self.OnWorkspaceNew(None) + + # read file and fix patch to dtd + + file = open(filename, "r") + + fileStream = ''.join(file.readlines()) + p = re.compile( '(grass-grc.dtd)') + p.search(fileStream) + fileStream = p.sub(dtdFilename, fileStream) + + # sax + grcXml = ProcessGrcXml() + xml.sax.parseString(fileStream, grcXml) + + maptree = self.curr_page.maptree + for layer in grcXml.layers: + newItem = maptree.AddLayer(ltype=layer['type'], + lname=layer['name'], + lchecked=layer['checked'], + lopacity=layer['opacity'], + lproperties=layer['cmd']) + + file.close() +# except: +# dlg = wx.MessageDialog(self, _("Unable to read workspace file <%s>.") % filename, +# _("Error"), wx.OK | wx.ICON_ERROR) +# dlg.ShowModal() +# dlg.Destroy() +# return False + + return True + def OnWorkspaceSave(self, event): - """Save file with workspace definition""" + """Save file with workspace definition + + Return True on success + Return False on error""" - filename = "test-out.grc" + dlg = wx.FileDialog(parent=self, message=_("Choose file to save current workspace"), + defaultDir=os.getcwd(), wildcard="*.grc", style=wx.FD_SAVE) + filename = '' + if dlg.ShowModal() == wx.ID_OK: + filename = dlg.GetFilename() + + if filename == '': + return False + + # check for extension + if filename[-4:] != ".grc": + filename += ".grc" + + # TODO: overwrite / save as... + + Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % filename) + self.SaveLayerTreeToGrcXml(filename) def SaveLayerTreeToGrcXml(self, filename): """Save layer tree layout to workspace file""" - file = open(filename, "w") - #file = sys.stderr try: + file = open(filename, "w") + except IOError: + dlg = wx.MessageDialog(self, _("Unable to open workspace file <%s> for writing.") % filename, + _("Error"), wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False + + try: # write header file.write('\n') file.write('\n') @@ -468,9 +574,11 @@ item = mapTree.GetNextChild(item, cookie)[0] file.write('\n') finally: - pass - #file.close() + file.close() + return True + return False + def OnWorkspaceClose(self, event): """Close file with workspace definition @@ -1036,6 +1144,89 @@ return True +class ProcessGrcXml(HandlerBase): + """ + A SAX handler for the GRC XML file, as + defined in grass-grc.dtd. + """ + def __init__(self): + self.inGrc = False + self.inLayer = False + self.inTask = False + self.inParameter = False + self.inFlag = False + self.inValue = False + + # list of layers + self.layers = [] + self.cmd = [] + + def startElement(self, name, attrs): + if name == 'grc': + self.inGrc = True + + elif name == 'layer': + self.inLayer = True + self.layerType = attrs.get('type', None) + self.layerName = attrs.get('name', None) + self.layerChecked = attrs.get('checked', None) + self.layerOpacity = attrs.get('opacity', None) + + elif name == 'task': + self.inTask = True; + name = attrs.get('name', None) + self.cmd.append(name) + + elif name == 'parameter': + self.inParameter = True; + self.parameterName = attrs.get('name', None) + + elif name == 'value': + self.inValue = True + self.value = '' + + elif name == 'flag': + self.inFlag = True; + name = attrs.get('name', None) + self.cmd.append('-' + name) + + def endElement(self, name): + if name == 'grc': + self.inGrc = False + + elif name == 'layer': + self.inLayer = False + self.layers.append({ + "type" : self.layerType, + "name" : self.layerName, + "checked" : int(self.layerChecked), + "opacity" : float(self.layerOpacity), + "cmd" : self.cmd}) + + self.layerType = self.layerName = self.Checked = \ + self.Opacity = self.cmd = None + + elif name == 'task': + self.inTask = False + + elif name == 'parameter': + self.inParameter = False + self.cmd.append('%s=%s' % (self.parameterName, self.value)) + self.parameterName = self.value = None + + elif name == 'value': + self.inValue = False + + elif name == 'flag': + self.inFlag = False + + def characters(self, ch): + self.my_characters(ch) + + def my_characters(self, ch): + if self.inValue: + self.value += ch + def reexec_with_pythonw(): if sys.platform == 'darwin' and\ not sys.executable.endswith('MacOS/Python'): From landa at grass.itc.it Wed Oct 17 22:39:16 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Wed Oct 17 22:39:19 2007 Subject: [grass-addons] r1139 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710172039.l9HKdGkm016456@grass.itc.it> Author: landa Date: 2007-10-17 22:39:08 +0200 (Wed, 17 Oct 2007) New Revision: 1139 Modified: trunk/grassaddons/gui/gui_modules/grass-grc.dtd trunk/grassaddons/gui/gui_modules/grassenv.py trunk/grassaddons/gui/gui_modules/menudata.py trunk/grassaddons/gui/gui_modules/menuform.py trunk/grassaddons/gui/gui_modules/render.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/wxgui.py Log: Basic workspace support implemeneted. Cleaning the code. Layers can be added also from command prompt (including module options). Modified: trunk/grassaddons/gui/gui_modules/grass-grc.dtd =================================================================== --- trunk/grassaddons/gui/gui_modules/grass-grc.dtd 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/gui_modules/grass-grc.dtd 2007-10-17 20:39:08 UTC (rev 1139) @@ -14,51 +14,39 @@ - + - + + + + + + + - + - - - - Modified: trunk/grassaddons/gui/gui_modules/grassenv.py =================================================================== --- trunk/grassaddons/gui/gui_modules/grassenv.py 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/gui_modules/grassenv.py 2007-10-17 20:39:08 UTC (rev 1139) @@ -1,5 +1,26 @@ +""" +MODULE: grassenv + +PURPOSE: GRASS environment variable management + +AUTHORS: The GRASS Development Team + Jachym Cepicky (Mendel University of Agriculture) + Martin Landa + +COPYRIGHT: (C) 2006-2007 by the GRASS Development Team + This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. + +""" + import os +import sys +gmpath = os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ) +sys.path.append(gmpath) +import gcmd + env={} class NotInGRASSSession(Exception): @@ -43,3 +64,13 @@ val = val.replace("'","") val = val.replace(";","") env[key] = val + +def GetGRASSVariable(var): + """Return GRASS variable""" + gisEnv = gcmd.Command(['g.gisenv']) + + for item in gisEnv.ReadStdOutput(): + if var in item: + return item.split('=')[1].replace("'",'').replace(';','').strip() + + return '' Modified: trunk/grassaddons/gui/gui_modules/menudata.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-17 20:39:08 UTC (rev 1139) @@ -25,12 +25,11 @@ def GetMenu(self): return [( ("File", ( - ("Workspace (not functional)", ( - ("New", "Create new workspace file (erase current workspace settings first", "self.OnWorkspaceNew", ""), + ("Workspace", ( + ("New", "Create new workspace file (erase current workspace settings first)", "self.OnWorkspaceNew", ""), ("Open", "Open existing workspace file", "self.OnWorkspaceOpen", ""), ("Save", "Save current workspace to file", "self.OnWorkspaceSave", ""), - ("Save as", "Save current workspace as...", "self.OnWorkspaceSave", ""), -# ("Close", "Close workspace file", "self.OnWorkspaceClose", ""), + ("Save as", "Save current workspace as", "self.OnWorkspaceSave", ""), )), ("","","", ""), ("Import raster map", ( Modified: trunk/grassaddons/gui/gui_modules/menuform.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-17 20:39:08 UTC (rev 1139) @@ -80,6 +80,7 @@ imagepath = os.path.join(wxbase,"images") sys.path.append(imagepath) +import grassenv import select import gcmd try: @@ -198,10 +199,19 @@ Find and return a param by name. """ for p in self.params: - if p['name'] == aParam: + lparam = len(aParam) + if p['name'] == aParam or \ + p['name'][:lparam] == aParam: return p - raise ValueError, "Parameter not found : %s" % aParam + raise ValueError, _("Parameter not found : %s") % aParam + def set_param(self, aParam, aValue): + """ + Set param value/values. + """ + param = self.get_param(aParam) + param['value'] = aValue + def get_flag( self, aFlag ): """ Find and return a flag by name. @@ -209,8 +219,16 @@ for f in self.flags: if f['name'] == aFlag: return f - raise ValueError, "Flag not found : %s" % aFlag + raise ValueError, _("Flag not found : %s") % aFlag + def set_flag(self, aFlag, aValue): + """ + Enable / disable flag. + """ + param = self.get_flag(aFlag) + param['value'] = aValue + + def getCmd(self, ignoreErrors = False): """ Produce an array of command name and arguments for feeding @@ -243,7 +261,6 @@ return cmd - class processTask(HandlerBase): """ A SAX handler for the --interface-description output, as @@ -260,6 +277,7 @@ self.inGispromptContent = False self.inGuisection = False self.inKeywordsContent = False + self.inFirstParameter = True self.task = task_description def startElement(self, name, attrs): @@ -377,6 +395,10 @@ "values" : self.param_values, "value" : ''}) + if self.inFirstParameter: + self.task.firstParam = self.param_name # store name of first parameter + self.inFirstParameter = False; + if name == 'flag': self.inFlag = False; self.task.flags.append({ @@ -636,9 +658,12 @@ if cmd is not None and self.get_dcmd is not None: # return d.* command to layer tree for rendering - self.get_dcmd(cmd, self.layer, {"params":self.task.params,"flags":self.task.flags}, self ) + self.get_dcmd(cmd, self.layer, {"params": self.task.params, + "flags" :self.task.flags}, + self) # echo d.* command to output console # self.parent.writeDCommand(cmd) + return cmd def OnRun(self, event): @@ -1112,16 +1137,20 @@ class GUI: """ Parses GRASS commands when module is imported and used - from wxgui.py + from Layer Manager. """ def __init__(self, parent=-1): self.parent = parent - def ParseCommand(self, cmd, gmpath=None, completed=None, parentframe=-1, modal=False): + def ParseCommand(self, cmd, gmpath=None, completed=None, parentframe=-1, show=True, modal=False): """ Parse command - Note: cmd is given as string + Note: cmd is given as list + + If command is given with options, return validated cmd list: + * add key name for first parameter if not given + * change mapname to mapname@mapset """ dcmd_params = {} if completed == None: @@ -1136,29 +1165,61 @@ if parentframe != -1: self.parent = parentframe - - if ' ' in cmd: - raise ValueError, _("usage: %s ") % cmd else: - # parse the interface decription - self.grass_task = grassTask() - handler = processTask(self.grass_task) - xml.sax.parseString( getInterfaceDescription( cmd ) , handler ) + self.parent = None - # if layer parameters previously set, re-insert them into dialog - if completed is not None: - if 'params' in dcmd_params: - self.grass_task.params = dcmd_params['params'] - if 'flags' in dcmd_params: - self.grass_task.flags = dcmd_params['flags'] + # parse the interface decription + self.grass_task = grassTask() + handler = processTask(self.grass_task) + xml.sax.parseString( getInterfaceDescription(cmd[0]), handler ) + + # if layer parameters previously set, re-insert them into dialog + if completed is not None: + if 'params' in dcmd_params: + self.grass_task.params = dcmd_params['params'] + if 'flags' in dcmd_params: + self.grass_task.flags = dcmd_params['flags'] - self.mf = mainFrame(parent=self.parent, ID=wx.ID_ANY, - task_description=self.grass_task, - get_dcmd=get_dcmd, layer=layer) + # update parameters if needed && validate command + if len(cmd) > 1: + i = 0 + cmd_validated = [cmd[0]] + for option in cmd[1:]: + if option[0] == '-': # flag + self.grass_task.set_flag(option[1], True) + cmd_validated.append(option) + else: # parameter + try: + key, value = option.split('=') + except: + if i == 0: # add key name of first parameter if not given + key = self.grass_task.firstParam + value = option + else: + raise ValueError, _("Unable to parse command %s") % ''.join(cmd) - self.mf.Show(True) + if self.grass_task.get_param(key)['element'] in ['cell', 'vector']: + # mapname -> mapname@mapset + if '@' not in value: + value = value + '@' + grassenv.GetGRASSVariable('MAPSET') + self.grass_task.set_param(key, value) + cmd_validated.append(key + '=' + value) + i = i + 1 + + # update original command list + cmd = cmd_validated + + self.mf = mainFrame(parent=self.parent, ID=wx.ID_ANY, + task_description=self.grass_task, + get_dcmd=get_dcmd, layer=layer) + + if show: + self.mf.Show(show) self.mf.MakeModal(modal) + else: + self.mf.OnApply(None) + return cmd class StaticWrapText(wx.StaticText): """ Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-10-17 20:39:08 UTC (rev 1139) @@ -129,9 +129,6 @@ runcmd = gcmd.Command(cmd=self.cmdlist + ['--q']) # run quiet if runcmd.returncode != 0: - print "Could not execute '%s'" % (self.cmdlist) - for msg in runcmd.msg: - print msg[1] self.mapfile = None self.maskfile = None return None @@ -647,7 +644,7 @@ item - gis manager layer tree item type - layer type name - layer name - cmd - GRASS command string + cmd - GRASS command given as list l_active - checked/not checked for display in layer tree l_hidden - not used here Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-17 20:39:08 UTC (rev 1139) @@ -45,39 +45,6 @@ except: from compat import subprocess -class AbstractLayer: - """ - Abstract layer in LayerTree - - Attributes: - * type - layer type ('cmdlayer', 'group', etc) -- see LayerTree.AddLayer() - """ - - def __init__(self, type): - self.type = type - -class Layer(AbstractLayer): - """ - This class represents general item in LayerTree - - Attributes: - * maplayer - reference to MapLayer instance - * properties - menuform properties (needed for PropertiesDialog) - """ - def __init__ (self, type, wxCtrl=None): - AbstractLayer.__init__(self, type) - - Debug.msg (3, "Layer.__init__(): type=%s" % \ - type) - - self.wxCtrl = wxCtrl - - # reference to MapLayer instance - self.maplayer = None - - # properties - self.properties = None - def __del__(self): Debug.msg (3, "Layer.__del__(): type=%s" % \ self.type) @@ -114,7 +81,6 @@ self.groupnode = 0 # index value for layers self.optpage = {} # dictionary of notebook option pages for each map layer self.layer_selected = None # ID of currently selected layer - self.layers = {} # dictionary of layers (see Layer class) self.saveitem = {} # dictionary to preserve layer attributes for drag and drop self.first = True # indicates if a layer is just added or not self.drag = False # flag to indicate a drag event is in process @@ -227,7 +193,7 @@ event.Skip() return - ltype = self.layers[self.layer_selected].type + ltype = self.GetPyData(self.layer_selected)[0]['type'] Debug.msg (4, "LayerTree.OnContextMenu: layertype=%s" % \ ltype) @@ -261,7 +227,7 @@ # specific items try: - mltype = self.layers[self.layer_selected].maplayer.type + mltype = self.GetPyData(self.layer_selected)[0]['type'] except: mltype = None # vector specific items @@ -276,7 +242,7 @@ self.Bind (wx.EVT_MENU, self.OnStartEditing, id=self.popupID5) self.Bind (wx.EVT_MENU, self.OnStopEditing, id=self.popupID6) - layer = self.layers[self.layer_selected].maplayer + layer = self.GetPyData(self.layer_selected)[0]['maplayer'] # enable editing only for vector map layers available in the current mapset digit = self.mapdisplay.digittoolbar if layer.GetMapset() != grassenv.env["MAPSET"]: @@ -307,7 +273,7 @@ """ Plot histogram for given raster map layer """ - rastName = self.layers[self.layer_selected].maplayer.name + rastName = self.GetPyData(self.layer_selected)[0]['maplayer'].name if not hasattr (self, "histogramFrame"): self.histogramFrame = None @@ -332,7 +298,7 @@ Start editing vector map layer requested by the user """ try: - maplayer = self.layers[self.layer_selected].maplayer + maplayer = self.GetPyData(self.layer_selected)[0]['maplayer'] except: event.Skip() return @@ -350,7 +316,7 @@ Stop editing the current vector map layer """ try: - maplayer = self.layers[self.layer_selected].maplayer + maplayer = self.GetPyData(self.layer_selected)[0]['maplayer'] except: event.Skip() return @@ -373,9 +339,12 @@ """Rename layer""" self.EditLabel(self.layer_selected) - def AddLayer(self, ltype, lname=None, lchecked=None, lopacity=None, lproperties=None): + def AddLayer(self, ltype, lname=None, lchecked=None, lopacity=None, lcmd=None, lgroup=None): """Add new item to the layer tree, create corresponding MapLayer instance. - Launch property dialog if needed (raster, vector, etc.)""" + Launch property dialog if needed (raster, vector, etc.) + + Note: lcmd is given as a list + """ self.first = True checked = False params = {} # no initial options parameters @@ -408,24 +377,21 @@ self.Bind(wx.EVT_SPINCTRL, self.OnOpacity, ctrl) # add layer to the layer tree - if (self.layer_selected and self.layer_selected != self.GetRootItem() and \ - self.layers[self.layer_selected].type != 'group'): - parent = self.GetItemParent(self.layer_selected) - layer = self.InsertItem(parent, self.GetPrevSibling(self.layer_selected), - text='', ct_type=1, wnd=ctrl) - # add layer to the group - elif (self.layer_selected and self.layer_selected != self.GetRootItem() and \ - self.layers[self.layer_selected].type == 'group'): - layer = self.PrependItem(parent=self.layer_selected, - text='', ct_type=1, wnd=ctrl) - self.Expand(self.layer_selected) - # add first layer to the layer tree - else: + if self.layer_selected and self.layer_selected != self.GetRootItem(): + if self.GetPyData(self.layer_selected)[0]['type'] != 'group': + if lgroup is None or lgroup is True: + parent = self.GetItemParent(self.layer_selected) + else: + parent = self.root + layer = self.InsertItem(parent, self.GetPrevSibling(self.layer_selected), + text='', ct_type=1, wnd=ctrl) + else: # group + layer = self.PrependItem(parent=self.layer_selected, + text='', ct_type=1, wnd=ctrl) + self.Expand(self.layer_selected) + else: # add first layer to the layer tree layer = self.PrependItem(parent=self.root, text='', ct_type=1, wnd=ctrl) - # create Layer instance & add to self.layers dictionary - newlayer = self.layers[layer] = Layer(type=ltype, wxCtrl=ctrl) - # layer is initially unchecked as inactive (beside 'command') # use predefined value if given if lchecked: @@ -434,6 +400,7 @@ # select item self.SelectItem(layer) + self.layer_selected = layer # add text and icons for each layer ltype if ltype == 'raster': @@ -482,7 +449,11 @@ self.SetItemText(layer, grouptext) # use predefined layer name if given - if lname: self.SetItemText(layer, lname) + if lname: + if ltype != 'command': + self.SetItemText(layer, lname) + else: + ctrl.SetValue(lname) self.first = False @@ -491,76 +462,99 @@ opacity = lopacity else: opacity = 1.0 - if lproperties: - cmd = lproperties + if lcmd and len(lcmd) > 1: + cmd = lcmd render = True - name = self.GetLayerNameFromCmd(cmd) + name = self.GetLayerNameFromCmd(lcmd) else: cmd = [] render = False name = None - newlayer.AddMapLayer(self.Map.AddLayer(type=ltype, command=cmd, name=name, - l_active=checked, l_hidden=False, - l_opacity=opacity, l_render=render)) - if lproperties: - self.SetPyData(layer, (cmd,None)) + # add a data object to hold the layer's command (does not apply to generic command layers) + self.SetPyData(layer, ({'cmd': cmd, + 'type' : ltype, + 'ctrl' : ctrl, + 'maplayer' : None, + 'prowin' : None}, + None)) + + maplayer = self.Map.AddLayer(type=ltype, command=self.GetPyData(layer)[0]['cmd'], name=name, + l_active=checked, l_hidden=False, + l_opacity=opacity, l_render=render) + self.GetPyData(layer)[0]['maplayer'] = maplayer + + # run properties dialog if no properties given + if len(cmd) > 1: + self.PropertiesDialog(layer, show=False) else: - # add a data object to hold the layer's command (does not apply to generic command layers) - self.SetPyData(layer, (None,None)) - # run properties dialog if no properties given - self.PropertiesDialog(layer) + self.PropertiesDialog(layer, show=True) - def PropertiesDialog (self, layer): + else: # group + self.SetPyData(layer, ({'cmd': None, + 'type' : ltype, + 'ctrl' : None, + 'maplayer' : None, + 'prowin' : None}, + None)) + + return layer + + def PropertiesDialog (self, layer, show=True): """Launch the properties dialog""" global gmpath completed = '' params = self.GetPyData(layer)[1] - ltype = self.layers[layer].type + ltype = self.GetPyData(layer)[0]['type'] Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \ ltype) - if ltype == 'raster': - menuform.GUI().ParseCommand('d.rast', completed=(self.GetOptData,layer,params), + if self.GetPyData(layer)[0]['cmd']: + cmdValidated = menuform.GUI().ParseCommand(self.GetPyData(layer)[0]['cmd'], + completed=(self.GetOptData,layer,params), + parentframe=self, show=show) + self.GetPyData(layer)[0]['cmd'] = cmdValidated + elif ltype == 'raster': + menuform.GUI().ParseCommand(['d.rast'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rgb': - menuform.GUI().ParseCommand('d.rgb', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.rgb'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'his': - menuform.GUI().ParseCommand('d.his', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.his'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'shaded': - menuform.GUI().ParseCommand('d.shadedmap', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.shadedmap'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rastarrow': - menuform.GUI().ParseCommand('d.rast.arrow', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.rast.arrow'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rastnum': - menuform.GUI().ParseCommand('d.rast.num', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.rast.num'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'vector': - menuform.GUI().ParseCommand('d.vect', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.vect'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'thememap': - menuform.GUI().ParseCommand('d.vect.thematic', + menuform.GUI().ParseCommand(['d.vect.thematic'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'themechart': - menuform.GUI().ParseCommand('d.vect.chart', + menuform.GUI().ParseCommand(['d.vect.chart'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'grid': - menuform.GUI().ParseCommand('d.grid', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.grid'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'geodesic': - menuform.GUI().ParseCommand('d.geodesic', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.geodesic'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'rhumb': - menuform.GUI().ParseCommand('d.rhumbline', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.rhumbline'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'labels': - menuform.GUI().ParseCommand('d.labels', completed=(self.GetOptData,layer,params), + menuform.GUI().ParseCommand(['d.labels'], completed=(self.GetOptData,layer,params), parentframe=self) elif ltype == 'cmdlayer': pass @@ -576,7 +570,7 @@ self.PropertiesDialog (layer) - if self.layers[layer].type == 'group': + if self.GetPyData(layer)[0]['type'] == 'group': if self.IsExpanded(layer): self.Collapse(layer) else: @@ -603,11 +597,8 @@ self.layer_selected = None try: - layer = self.layers[item] - if layer.type != 'group': - self.Map.DeleteLayer(layer.maplayer) - - self.layers.pop(item) + if self.GetPyData(item)[0]['type'] != 'group': + self.Map.DeleteLayer( self.GetPyData(item)[0]['maplayer']) except: pass @@ -624,11 +615,10 @@ """Enable/disable given layer item""" item = event.GetItem() checked = item.IsChecked() - layer = self.layers[item] - + if self.drag == False and self.first == False: # change active parameter for item in layers list in render.Map - if layer.type == 'group': + if self.GetPyData(item)[0]['type'] == 'group': childitem = self.GetFirstChild(item) child = childitem[0] cookie = childitem[1] @@ -637,10 +627,10 @@ childchecked = False else: childchecked = child.IsChecked() - self.Map.ChangeLayerActive(self.layers[child].maplayer, childchecked) + self.Map.ChangeLayerActive(self.GetPyData(child)[0]['maplayer'], childchecked) child = self.GetNextChild(item, cookie)[0] else: - self.Map.ChangeLayerActive(self.layers[item].maplayer, checked) + self.Map.ChangeLayerActive(self.GetPyData(item)[0]['maplayer'], checked) # redraw map if auto-rendering is enabled if self.mapdisplay.autoRender.GetValue(): @@ -650,20 +640,28 @@ """Change command string""" ctrl = event.GetEventObject() cmd = event.GetString() + layer = None - layer = item = None + vislayer = self.GetFirstVisibleItem() - for item, layer in self.layers.iteritems(): - if layer.wxCtrl == ctrl: + for item in range(0, self.GetCount()): + if self.GetPyData(vislayer)[0]['ctrl'] == ctrl: + layer = vislayer + + if not self.GetNextVisible(vislayer): break + else: + vislayer = self.GetNextVisible(vislayer) # change parameters for item in layers list in render.Map - if item and self.drag == False: - self.ChangeLayer(item) - for option in layer.maplayer.GetCmd(): + if layer and self.drag == False: + self.ChangeLayer(layer) + self.GetPyData(layer)[0]['cmd'] = cmd.split(' ') + maplayer = self.GetPyData(layer)[0]['maplayer'] + for option in maplayer.GetCmd(): if 'map=' in option: mapname = option.split('=')[1] - self.Map.ChangeLayerName(layer.maplayer, mapname) + self.Map.ChangeLayerName(maplayer, mapname) event.Skip() @@ -675,10 +673,22 @@ ctrl = event.GetEventObject() maplayer = None - for layer in self.layers.itervalues(): - if layer.wxCtrl == ctrl: - maplayer = layer.maplayer + vislayer = self.GetFirstVisibleItem() + + layer = None + for item in range(0, self.GetCount()): + if self.GetPyData(vislayer)[0]['ctrl'] == ctrl: + layer = vislayer + + if not self.GetNextVisible(vislayer): + break + else: + vislayer = self.GetNextVisible(vislayer) + + if layer: + maplayer = self.GetPyData(layer)[0]['maplayer'] + opacity = event.GetInt() / 100. # change opacity parameter for item in layers list in render.Map if maplayer and self.drag == False: @@ -702,7 +712,7 @@ """ Collapse node """ - if self.layers[self.layer_selected].type == 'group': + if self.GetPyData(self.layer_selected)[0]['type'] == 'group': self.SetItemImage(self.layer_selected, self.folder) def OnExpandNode(self, event): @@ -710,7 +720,7 @@ Expand node """ self.layer_selected = event.GetItem() - if self.layers[self.layer_selected].type == 'group': + if self.GetPyData(self.layer_selected)[0]['type'] == 'group': self.SetItemImage(self.layer_selected, self.folder_open) def OnBeginDrag(self, event): @@ -733,29 +743,27 @@ """ Recreate item (needed for OnEndDrag()) """ - oldLayer = self.layers[oldItem] - Debug.msg (4, "LayerTree.RecreateItem(): layer=%s" % \ self.GetItemText(oldItem)) # recreate spin/text control for layer - if oldLayer.type == 'command': + if self.GetPyData(oldItem)[0]['type'] == 'command': newctrl = wx.TextCtrl(self, id=wx.ID_ANY, value='', pos=wx.DefaultPosition, size=(250,25), style=wx.TE_MULTILINE|wx.TE_WORDWRAP) try: - newctrl.SetValue(oldLayer.maplayer.GetCmd(string=True)) + newctrl.SetValue(self.GetPyData(oldItem)[0]['maplayer'].GetCmd(string=True)) except: pass newctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged) newctrl.Bind(wx.EVT_TEXT, self.OnCmdChanged) - elif oldLayer.type == 'group': + elif self.GetPyData(oldItem)[0]['type'] == 'group': newctrl = None else: newctrl = wx.SpinCtrl(self, id=wx.ID_ANY, value="", pos=(30, 50), style=wx.SP_ARROW_KEYS, min=0, max=100) try: - newctrl.SetValue(oldLayer.maplayer.GetOpacity()) + newctrl.SetValue(self.GetPyData(oldItem)[0]['maplayer'].GetOpacity()) except: newctrl.SetValue(100) self.Bind(wx.EVT_SPINCTRL, self.OnOpacity, newctrl) @@ -771,7 +779,7 @@ image = self.GetItemImage(oldItem, 0) wind = self.GetItemWindow(oldItem) checked = self.IsItemChecked(oldItem) - if oldLayer.type == 'group': + if self.GetPyData(oldItem)[0]['type'] == 'group': windval = None data = None else: @@ -780,12 +788,12 @@ # create GenericTreeItem instance if flag & wx.TREE_HITTEST_ABOVE: - new = self.PrependItem(self.root, text=text, \ + newItem = self.PrependItem(self.root, text=text, \ ct_type=1, wnd=newctrl, image=image, \ data=data) elif (flag & wx.TREE_HITTEST_BELOW) or (flag & wx.TREE_HITTEST_NOWHERE) \ or (flag & wx.TREE_HITTEST_TOLEFT) or (flag & wx.TREE_HITTEST_TORIGHT): - new = self.AppendItem(self.root, text=text, \ + newItem = self.AppendItem(self.root, text=text, \ ct_type=1, wnd=newctrl, image=image, \ data=data) else: @@ -794,27 +802,27 @@ else: afteritem = event.GetItem() - if self.layers[afteritem].type == 'group': + if self.GetPyData(afteritem)[0]['type'] == 'group': parent = afteritem - new = self.AppendItem(parent, text=text, \ + newItem = self.AppendItem(parent, text=text, \ ct_type=1, wnd=newctrl, image=image, \ data=data) self.Expand(afteritem) else: parent = self.GetItemParent(afteritem) - new = self.InsertItem(parent, afteritem, text=text, \ + newItem = self.InsertItem(parent, afteritem, text=text, \ ct_type=1, wnd=newctrl, image=image, \ data=data) # add layer at new position - self.layers[new] = self.layers[oldItem] - self.layers[new].wxCtrl = newctrl + self.SetPyData(newItem, self.GetPyData(oldItem)) + self.GetPyData(newItem)[0]['ctrl'] = newctrl - self.CheckItem(new, checked=checked) + self.CheckItem(newItem, checked=checked) event.Skip() - return new + return newItem def OnEndDrag(self, event): """ @@ -831,10 +839,9 @@ Debug.msg (4, "LayerTree.OnEndDrag(): layer=%s" % \ (self.GetItemText(self.dragItem))) - # recreate item and update self.layers dictionary newItem = self.RecreateItem (event, self.dragItem) - if self.layers[newItem].type == 'group': + if self.GetPyData(newItem)[0]['type'] == 'group': (child, cookei) = self.GetFirstChild(self.dragItem) if child: while child: @@ -846,11 +853,13 @@ # delete layer at original position self.Delete(old) # entry in render.Map layers list automatically deleted by OnDeleteLayer handler - # self.layers.pop(old) # reorder layers in render.Map to match new order after drag and drop self.ReorderLayers() + # select new item + self.SelectItem(newItem) + # completed drag and drop self.drag = False @@ -875,6 +884,9 @@ elif 'labels=' in item: mapname = item.split('=')[1]+' labels' + if mapname != '': + break + return mapname def GetOptData(self, dcmd, layer, params, propwin): @@ -884,8 +896,9 @@ mapname = self.GetLayerNameFromCmd(dcmd) self.SetItemText(layer, mapname) - # add command to layer's data - self.SetPyData(layer, (dcmd,params)) + # update layer data + self.SetPyData(layer, (self.GetPyData(layer)[0], params)) + self.GetPyData(layer)[0]['propwin'] = propwin # check layer as active self.CheckItem(layer, checked=True) @@ -893,10 +906,6 @@ # change parameters for item in layers list in render.Map self.ChangeLayer(layer) - # set the layer properties dialog dictionary entry - self.layers[layer].AddProperties (propwin) - - def ReorderLayers(self): """Add commands from data associated with any valid layers (checked or not) to layer list in order to @@ -904,14 +913,18 @@ # make a list of visible layers treelayers = [] + vislayer = self.GetFirstVisibleItem() + if not vislayer: return + itemList = "" + for item in range(0, self.GetCount()): itemList += self.GetItemText(vislayer) + ',' - if self.layers[vislayer].type != 'group': - treelayers.append(self.layers[vislayer].maplayer) + if self.GetPyData(vislayer)[0]['type'] != 'group': + treelayers.append(self.GetPyData(vislayer)[0]['maplayer']) if not self.GetNextVisible(vislayer): break @@ -927,24 +940,28 @@ def ChangeLayer(self, item): """Change layer""" - layer = self.layers[item] - if layer.type == 'command': + type = self.GetPyData(item)[0]['type'] + + if type == 'command': if self.GetItemWindow(item).GetValue() != None: cmdlist = self.GetItemWindow(item).GetValue().split(' ') opac = 1.0 chk = self.IsItemChecked(item) hidden = not self.IsVisible(item) - elif layer.type != 'group': + elif type != 'group': if self.GetPyData(item)[0] != None: - cmdlist = self.GetPyData(item)[0] + cmdlist = self.GetPyData(item)[0]['cmd'] opac = float(self.GetItemWindow(item).GetValue())/100 chk = self.IsItemChecked(item) hidden = not self.IsVisible(item) - layer.maplayer = self.Map.ChangeLayer(layer=layer.maplayer, type=layer.maplayer.type, command=cmdlist, name=self.GetItemText(item), - l_active=chk, l_hidden=hidden, l_opacity=opac, l_render=False) + maplayer = self.Map.ChangeLayer(layer=self.GetPyData(item)[0]['maplayer'], type=type, + command=cmdlist, name=self.GetItemText(item), + l_active=chk, l_hidden=hidden, l_opacity=opac, l_render=False) + self.GetPyData(item)[0]['maplayer'] = maplayer + # if digitization tool enabled -> update list of available vector map layers if self.mapdisplay.digittoolbar: self.mapdisplay.digittoolbar.UpdateListOfLayers(updateTool=True) @@ -1056,14 +1073,14 @@ try: # if command is not already a list, make it one - cmdlist = command.split(' ') + cmdlist = command.strip().split(' ') except: cmdlist = command - if len(cmdlist) == 1 and cmdlist[0] in gcmdlst: + if cmdlist[0] in gcmdlst: # send GRASS command without arguments to GUI command interface # except display commands (they are handled differently) - if command[0:2] == "d.": + if cmdlist[0][0:2] == "d.": try: layertype = {'d.rast' : 'raster', 'd.rgb' : 'rgb', @@ -1078,40 +1095,21 @@ 'd.grid' : 'grid', 'd.geodesic' : 'geodesic', 'd.rhumbline' : 'rhumb', - 'd.labels' : 'labels'}[command] + 'd.labels' : 'labels'}[cmdlist[0]] except KeyError: print _('Command type not yet implemented') return False # add layer - self.parent.curr_page.maptree.AddLayer(layertype) + self.parent.curr_page.maptree.AddLayer(ltype=layertype, + lcmd=cmdlist) else: - menuform.GUI().ParseCommand(string.join(cmdlist), parentframe=None) - #self.cmd_output.write(string.join(cmdlist) + "\n----------\n") + if len(cmdlist) > 1: + menuform.GUI().ParseCommand(cmdlist, parentframe=self, show=False) + else: + menuform.GUI().ParseCommand(cmdlist, parentframe=self, show=True) - elif command[0:2] == "d." and len(cmdlist) > 1: - # Send GRASS display command(s)with arguments - # to the display processor and echo to command output console. - # Accepts a list of d.* commands separated by semi-colons. - # Display with focus receives display command(s). - - self.cmd_output.write("$" + ' '.join(cmdlist)) - - dcmds = command.split(';') - for command in dcmds: - try: - # only add the display command to the rendering list if it has arguments - cmdlist = command.strip().split(' ') - if cmdlist[0] in gcmdlst and len(cmdlist) > 1: - self.Map.AddLayer(type='command', command=cmdlist, - l_active=True, l_hidden=False, l_opacity=1, l_render=False) - except: - pass - - curr_disp.MapWindow.UpdateMap() - - else: # Send any other command to the shell. Send output to # console output window. Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-16 19:52:16 UTC (rev 1138) +++ trunk/grassaddons/gui/wxgui.py 2007-10-17 20:39:08 UTC (rev 1139) @@ -148,7 +148,7 @@ toolbar = self.__createToolBar() #self.panel = wx.Panel(self,-1, style= wx.EXPAND) self.sizer= wx.BoxSizer(wx.VERTICAL) -# self.cmdsizer = wx.BoxSizer(wx.HORIZONTAL) + # self.cmdsizer = wx.BoxSizer(wx.HORIZONTAL) # do layout self.SetTitle(_("GRASS GIS Layer Manager")) @@ -159,13 +159,14 @@ os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE" # initialize variables - self.mapdisplays = {} #dictionary to index open map displays - self.disp_idx = 0 #index value for map displays and layer trees - self.maptree = {} #dictionary to index a layer tree to accompanying a map display - self.mapfocus = 0 #track which display currently has focus - self.curr_page = '' # currently selected page for layer tree notebook - self.curr_pagenum = '' # currently selected page number for layer tree notebook + self.mapdisplays = {} # dictionary to index open map displays + self.disp_idx = 0 # index value for map displays and layer trees + self.maptree = {} # dictionary to index a layer tree to accompanying a map display + self.mapfocus = 0 # track which display currently has focus + self.curr_page = '' # currently selected page for layer tree notebook + self.curr_pagenum = '' # currently selected page number for layer tree notebook self.encoding = 'ISO-8859-1' # default encoding for display fonts + self.workspaceFile = None # workspace file self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.Bind(wx.EVT_LEFT_DOWN, self.AddRaster) @@ -371,19 +372,25 @@ self.goutput.RunCmd(cmd) def GetMenuCmd(self, event): + """Get GRASS command from menu item + + + Return command as a list""" menuitem = self.menubar.FindItemById(event.GetId()) itemtext = menuitem.GetText() cmd = menucmd[itemtext] - return cmd + cmdlist = cmd.split(' ') + return cmdlist + def RunMenuCmd(self, event): + """Run command selected from menu""" cmd = self.GetMenuCmd(event) self.goutput.RunCmd(cmd) def OnMenuCmd(self, event): - """Run menu command""" + """Parse command selected from menu""" cmd = self.GetMenuCmd(event) - global gmpath menuform.GUI().ParseCommand(cmd, parentframe=self) def OnAboutGRASS(self, event): @@ -419,10 +426,22 @@ Erase current workspace settings first""" - # TODO: ask user to save current settings + maptree = self.curr_page.maptree - maptree = self.curr_page.maptree + # ask user to save current settings + if maptree.GetCount() > 0: + dlg = wx.MessageDialog(self, message=_("Workspace is not empty. " + "Do you want to store current settings " + "to workspace file?"), + caption=_("Save current settings?"), + style=wx.OK | wx.CANCEL | wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_OK: + self.OnWorkspaceSave(None) + dlg.Destroy() + + # delete all items maptree.DeleteAllItems() + # add new root element maptree.root = maptree.AddRoot("Map Layers") self.curr_page.maptree.SetPyData(maptree.root, (None,None)) @@ -440,6 +459,8 @@ self.LoadGrcXmlToLayerTree(filename) + self.workspaceFile = filename + def LoadGrcXmlToLayerTree(self, filename): """Load layer tree definition stored in GRC XML file @@ -471,28 +492,29 @@ self.OnWorkspaceNew(None) # read file and fix patch to dtd - +# try: file = open(filename, "r") fileStream = ''.join(file.readlines()) p = re.compile( '(grass-grc.dtd)') p.search(fileStream) fileStream = p.sub(dtdFilename, fileStream) - - # sax + + # sax grcXml = ProcessGrcXml() xml.sax.parseString(fileStream, grcXml) - maptree = self.curr_page.maptree for layer in grcXml.layers: newItem = maptree.AddLayer(ltype=layer['type'], - lname=layer['name'], - lchecked=layer['checked'], - lopacity=layer['opacity'], - lproperties=layer['cmd']) - + lname=layer['name'], + lchecked=layer['checked'], + lopacity=layer['opacity'], + lcmd=layer['cmd'], + lgroup=layer['group']) + maptree.PropertiesDialog(newItem, show=False) + file.close() -# except: + # except: # dlg = wx.MessageDialog(self, _("Unable to read workspace file <%s>.") % filename, # _("Error"), wx.OK | wx.ICON_ERROR) # dlg.ShowModal() @@ -500,13 +522,10 @@ # return False return True - - def OnWorkspaceSave(self, event): - """Save file with workspace definition - Return True on success - Return False on error""" - + def OnWorkspaceSaveAs(self, event): + """Save workspace definition to selected file""" + dlg = wx.FileDialog(parent=self, message=_("Choose file to save current workspace"), defaultDir=os.getcwd(), wildcard="*.grc", style=wx.FD_SAVE) @@ -521,15 +540,73 @@ if filename[-4:] != ".grc": filename += ".grc" - # TODO: overwrite / save as... + if os.path.exists(filename): + dlg = wx.MessageDialog(self, message=_("Workspace file <%s> already exists. " + "Do you want to overwrite this file?") % filename, + caption=_("File exits"), style=wx.OK | wx.CANCEL | wx.ICON_QUESTION) + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + return False + + Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename) - Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % filename) - self.SaveLayerTreeToGrcXml(filename) + + def OnWorkspaceSave(self, event): + """Save file with workspace definition""" + if self.workspaceFile: + Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile) + self.SaveLayerTreeToGrcXml(self.workspaceFile) + else: + self.OnWorkspaceSaveAs(None) + + def WriteLayersToGrcXml(self, file, mapTree, item): + """Write bunch of layers to GRC XML file""" + while item and item.IsOk(): + type = mapTree.GetPyData(item)[0]['type'] + if type != 'group': + maplayer = mapTree.GetPyData(item)[0]['maplayer'] + else: + maplayer = None + + checked = int(item.IsChecked()) + cmd = mapTree.GetPyData(item)[0]['cmd'] + if type == 'command': + file.write(' \n' % \ + (type, ' '.join(cmd), checked)); + elif type == 'group': + name = mapTree.GetItemText(item) + file.write(' \n' % \ + (name, checked)); + subItem = mapTree.GetFirstChild(item)[0] + self.WriteLayersToGrcXml(file, mapTree, subItem) + file.write(' \n'); + else: + name = mapTree.GetItemText(item) + opacity = maplayer.GetOpacity(float=True) + file.write(' \n' % \ + (type, name, checked, opacity)); + # layer properties + file.write(' \n' % cmd[0]) + for option in cmd[1:]: + if option[0] == '-': # flag + file.write(' \n' % option[1]) + else: # parameter + key, value = option.split('=') + file.write(' \n' % key) + file.write(' %s\n' % value) + file.write(' \n'); + file.write(' \n'); + file.write(' \n'); + item = mapTree.GetNextSibling(item) + def SaveLayerTreeToGrcXml(self, filename): - """Save layer tree layout to workspace file""" + """Save layer tree layout to workspace file + Return True on success, False on error + """ + try: file = open(filename, "w") except IOError: @@ -546,39 +623,20 @@ file.write('\n') # list of layers mapTree = self.curr_page.maptree - root = mapTree.GetRootItem() - childitem = mapTree.GetFirstChild(root) - item = childitem[0] - cookie = childitem[1] - for n in range(0, mapTree.GetChildrenCount(root)): - layer = mapTree.layers[item] - type = layer.type - name = mapTree.GetItemText(item) - checked = int(item.IsChecked()) - opacity = layer.maplayer.GetOpacity(float=True) - file.write(' \n' % \ - (type, name, checked, opacity)); - # layer properties - cmd = mapTree.GetPyData(item)[0] - file.write(' \n' % cmd[0]) - for option in cmd[1:]: - if option[0] == '-': # flag - file.write(' \n' % option[1]) - else: # parameter - key, value = option.split('=') - file.write(' \n' % key) - file.write(' %s\n' % value) - file.write(' \n'); - file.write(' \n'); - file.write(' \n'); - item = mapTree.GetNextChild(item, cookie)[0] + item = mapTree.GetFirstChild(mapTree.root)[0] + self.WriteLayersToGrcXml(file, mapTree, item) file.write('\n') - finally: - file.close() - return True + except: + dlg = wx.MessageDialog(self, _("Writing current settings to workspace file failed."), + _("Error"), wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False - return False + file.close() + return True + def OnWorkspaceClose(self, event): """Close file with workspace definition @@ -751,7 +809,7 @@ # available only for vector map layers try: - maptype = self.curr_page.maptree.layers[layer].maplayer.type + maptype = self.curr_page.maptree.GetPyData(layer)['maplayer'].type except: maptype = None if not maptype or maptype != 'vector': @@ -1015,7 +1073,7 @@ dlg.Destroy() for layer in self.curr_page.maptree.GetSelections(): - if self.curr_page.maptree.layers[layer].type == 'group': + if self.curr_page.maptree.GetPyData(layer)[0]['type'] == 'group': self.curr_page.maptree.DeleteChildren(layer) self.curr_page.maptree.Delete(layer) @@ -1156,6 +1214,7 @@ self.inParameter = False self.inFlag = False self.inValue = False + self.inGroup = False # list of layers self.layers = [] @@ -1164,13 +1223,26 @@ def startElement(self, name, attrs): if name == 'grc': self.inGrc = True - + + elif name == 'group': + self.inGroup = True + self.groupName = attrs.get('name', None) + self.groupChecked = attrs.get('checked', None) + self.layers.append({ + "type" : 'group', + "name" : self.groupName, + "checked" : int(self.groupChecked), + "opacity" : None, + "cmd" : None, + "group" : None}) + elif name == 'layer': self.inLayer = True self.layerType = attrs.get('type', None) self.layerName = attrs.get('name', None) self.layerChecked = attrs.get('checked', None) self.layerOpacity = attrs.get('opacity', None) + self.cmd = [] elif name == 'task': self.inTask = True; @@ -1194,15 +1266,24 @@ if name == 'grc': self.inGrc = False + elif name == 'group': + self.inGroup = False + self.groupName = self.groupChecked = None + elif name == 'layer': self.inLayer = False self.layers.append({ "type" : self.layerType, "name" : self.layerName, "checked" : int(self.layerChecked), - "opacity" : float(self.layerOpacity), - "cmd" : self.cmd}) - + "opacity" : None, + "cmd" : None, + "group" : self.inGroup}) + if self.layerOpacity: + self.layers[-1]["opacity"] = float(self.layerOpacity) + if self.cmd: + self.layers[-1]["cmd"] = self.cmd + self.layerType = self.layerName = self.Checked = \ self.Opacity = self.cmd = None @@ -1230,7 +1311,7 @@ def reexec_with_pythonw(): if sys.platform == 'darwin' and\ not sys.executable.endswith('MacOS/Python'): - print >>sys.stderr,'re-executing using pythonw' + print >> sys.stderr, _('re-executing using pythonw') os.execvp('pythonw',['pythonw',__file__] + sys.argv[1:]) if __name__ == "__main__": From landa at grass.itc.it Thu Oct 18 16:49:34 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 18 16:49:35 2007 Subject: [grass-addons] r1140 - in trunk/grassaddons/gui: . gui_modules icons Message-ID: <200710181449.l9IEnYid031850@grass.itc.it> Author: landa Date: 2007-10-18 16:49:05 +0200 (Thu, 18 Oct 2007) New Revision: 1140 Modified: trunk/grassaddons/gui/README trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/debug.py trunk/grassaddons/gui/gui_modules/georect.py trunk/grassaddons/gui/gui_modules/grassenv.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/sqlbuilder.py trunk/grassaddons/gui/gui_modules/toolbars.py trunk/grassaddons/gui/gui_modules/utils.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/icons/icon.py Log: Bugfix in wxgui_utils.GetOptData(). Use environment variable GRASS_WX_DEBUG instead of GRASS variable DEBUG. Cleaning of grassenv module. Modified: trunk/grassaddons/gui/README =================================================================== --- trunk/grassaddons/gui/README 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/README 2007-10-18 14:49:05 UTC (rev 1140) @@ -121,19 +121,11 @@ 5 - DEBUGGING -To enable debugging messages use "GRASS standard way", e.g. +To enable GUI debugging messages on given level set GRASS_DEBUG_WX +environment variables, e.g. -$ g.gisenv set=DEBUG=3 +$ export GRASS_WX_DEBUG=3 -This enables all debug messages (GRASS modules + GUI). GUI debug -messages starts with 'GUI', e.g. - - GUI D1/1: MapFrame.__init__() - -If you want to enable *only* GUI debug messages set DEBUG variable to 'GUI:level', e.g. - -$ g.gisenv set=DEBUG=GUI:3 - 6 - ICON THEMES Currently only two icon themes are available: Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -61,7 +61,7 @@ self.vectmap = vectmap if not "@" in self.vectmap: - self.vectmap = self.vectmap+"@"+grassenv.env["MAPSET"] + self.vectmap = self.vectmap + "@" + grassenv.GetGRASSVariable("MAPSET") self.mapname, self.mapset = self.vectmap.split("@") self.icon = '' Modified: trunk/grassaddons/gui/gui_modules/debug.py =================================================================== --- trunk/grassaddons/gui/gui_modules/debug.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/debug.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -18,14 +18,18 @@ for details. """ -import grassenv +import os +import sys +gmpath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") +sys.path.append(gmpath) + class DebugMsg: """ GRASS Debugging Usage: - import cmd + import cmd cmd.Command (cmd=["g.gisenv", "set=DEBUG=3"]) # only GUI debug messages DEBUG=GUI:3 @@ -41,8 +45,8 @@ self._update_level() def _update_level(self): - if grassenv.env.has_key ("DEBUG"): - debug = grassenv.env["DEBUG"].strip() + debug = os.getenv("GRASS_WX_DEBUG") + if debug is not None: try: # only GUI debug messages [GUI:level] level = int (debug[-1]) @@ -64,7 +68,6 @@ if __name__ == "__main__": import gcmd gcmd.Command (cmd=["g.gisenv", "set=DEBUG=3"]) - reload (grassenv) # reload GRASS environments ! for level in range (4): Debug.msg (level, "message level=%d" % level) Modified: trunk/grassaddons/gui/gui_modules/georect.py =================================================================== --- trunk/grassaddons/gui/gui_modules/georect.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/georect.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -58,7 +58,6 @@ import mapdisp import render import toolbars -import grassenv import menuform import select import disp_print Modified: trunk/grassaddons/gui/gui_modules/grassenv.py =================================================================== --- trunk/grassaddons/gui/gui_modules/grassenv.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/grassenv.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -17,56 +17,12 @@ import os import sys -gmpath = os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ) +gmpath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") sys.path.append(gmpath) import gcmd -env={} - -class NotInGRASSSession(Exception): - def __str__(self): - return "You must be in running GRASS session" - -class CouldNotStartMonitor(Exception): - def __init__(self,monitor): - self.monitor = monitor - - def __str__(self): - return "Could not start GRASS monitor <%s>" % self.monitor - -class CouldNotStopMonitor(Exception): - def __init__(self,monitor): - self.monitor = monitor - - def __str__(self): - return "Could not start GRASS monitor <%s>" % self.monitor - -class CouldNotExecute(Exception): - def __init__(self,command): - self.command = command - def __str__(self): - return "Could not execute GRASS command: %s" % self.command - - -if not os.getenv("GISBASE"): - raise NotInGRASSSession() -else: - env["GISBASE"] = os.getenv("GISBASE") - env["GIS_LOCK"] = os.getenv("GIS_LOCK") - env["GISRC"] = os.getenv("GISRC") - -for key in os.environ.keys(): - if key.find("GRASS") > -1: - env[key] = os.getenv(key) - -for line in os.popen("g.gisenv").readlines(): - key,val = line.strip().split("=") - val = val.replace("'","") - val = val.replace(";","") - env[key] = val - def GetGRASSVariable(var): - """Return GRASS variable""" + """Return GRASS variable or '' if variable is not defined""" gisEnv = gcmd.Command(['g.gisenv']) for item in gisEnv.ReadStdOutput(): Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -3201,11 +3201,12 @@ gm_map = MapApp(0) # set title - gm_map.mapFrm.SetTitle ("GRASS GIS - Map Display: " + title + " - Location: " + grassenv.env["LOCATION_NAME"]) + gm_map.mapFrm.SetTitle ("GRASS GIS - Map Display: " + title + " - Location: " + \ + grassenv.GetGRASSVariable("LOCATION_NAME")) gm_map.MainLoop() if grassenv.env.has_key("MONITOR"): - os.system("d.mon sel=%s" % grassenv.env["MONITOR"]) + os.system("d.mon sel=%s" % grassenv.GetGRASSVariable("MONITOR")) os.remove(cmdfilename) os.system("""g.gisenv set="GRASS_PYCMDFILE" """) Modified: trunk/grassaddons/gui/gui_modules/sqlbuilder.py =================================================================== --- trunk/grassaddons/gui/gui_modules/sqlbuilder.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/sqlbuilder.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -28,7 +28,7 @@ self.vectmap = vectmap print self.vectmap if not "@" in self.vectmap: - self.vectmap = self.vectmap+"@"+grassenv.env["MAPSET"] + self.vectmap = self.vectmap + "@" + grassenv.GetGRASSVariable ("MAPSET") self.mapname, self.mapset = self.vectmap.split("@") self.layer,self.tablename, self.column, self.database, self.driver =\ os.popen("v.db.connect -g map=%s" %\ Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -628,7 +628,8 @@ # select vector map layer in the current mapset layerNameList = [] - self.layers = self.mapcontent.GetListOfLayers(l_type="vector", l_mapset=grassenv.env["MAPSET"]) + self.layers = self.mapcontent.GetListOfLayers(l_type="vector", + l_mapset=grassenv.GetGRASSVariable('MAPSET')) for layer in self.layers: if not layer.name in layerNameList: # do not duplicate layer layerNameList.append (layer.name) Modified: trunk/grassaddons/gui/gui_modules/utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/utils.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/utils.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -41,3 +41,14 @@ return os.path.join(path, file) except: return Node + +def GetGRASSVariable(var): + """Return GRASS environment variable""" + + gisEnv = gcmd.Command(['g.gisenv']) + + for item in gisEnv.ReadStdOutput(): + if var in item: + return item.split('=')[1].replace("'",'').replace(';','').strip() + + return '' Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -101,7 +101,7 @@ # title self.mapdisplay.SetTitle(_("GRASS GIS - Map Display: " + \ str(self.disp_idx) + \ - " - Location: " + grassenv.env["LOCATION_NAME"])) + " - Location: " + grassenv.GetGRASSVariable("LOCATION_NAME"))) #show new display self.mapdisplay.Show() @@ -245,7 +245,7 @@ layer = self.GetPyData(self.layer_selected)[0]['maplayer'] # enable editing only for vector map layers available in the current mapset digit = self.mapdisplay.digittoolbar - if layer.GetMapset() != grassenv.env["MAPSET"]: + if layer.GetMapset() != grassenv.GetGRASSVariable("MAPSET"): # only vector map in current mapset can be edited self.popupMenu.Enable (self.popupID5, False) self.popupMenu.Enable (self.popupID6, False) @@ -898,6 +898,7 @@ # update layer data self.SetPyData(layer, (self.GetPyData(layer)[0], params)) + self.GetPyData(layer)[0]['cmd'] = dcmd self.GetPyData(layer)[0]['propwin'] = propwin # check layer as active @@ -950,12 +951,11 @@ chk = self.IsItemChecked(item) hidden = not self.IsVisible(item) elif type != 'group': - if self.GetPyData(item)[0] != None: + if self.GetPyData(item)[0] is not None: cmdlist = self.GetPyData(item)[0]['cmd'] opac = float(self.GetItemWindow(item).GetValue())/100 chk = self.IsItemChecked(item) hidden = not self.IsVisible(item) - maplayer = self.Map.ChangeLayer(layer=self.GetPyData(item)[0]['maplayer'], type=type, command=cmdlist, name=self.GetItemText(item), l_active=chk, l_hidden=hidden, l_opacity=opac, l_render=False) Modified: trunk/grassaddons/gui/icons/icon.py =================================================================== --- trunk/grassaddons/gui/icons/icon.py 2007-10-17 20:39:08 UTC (rev 1139) +++ trunk/grassaddons/gui/icons/icon.py 2007-10-18 14:49:05 UTC (rev 1140) @@ -18,6 +18,8 @@ """ import os +import sys + import wx iconpath_default = os.path.join(os.getenv("GISBASE"), "etc", "gui", "icons") @@ -111,23 +113,30 @@ } # merge icons dictionaries, join paths -if iconpath and iconpath.find('silk') > -1: # silk icon theme - from silk import IconsSilk as icons_img - # use default icons if needed - for key, img in icons_default.iteritems(): - if not icons_img.has_key(key): # add key - icons_img[key] = img - if key[0:3] == 'dig': - iconpath_tmp = iconpath_vdigit +try: + if not os.path.exists(iconpath): + raise OSError + if iconpath is not None and iconpath.find('silk') > -1: # silk icon theme + from silk import IconsSilk as icons_img + # use default icons if needed + for key, img in icons_default.iteritems(): + if not icons_img.has_key(key): # add key + icons_img[key] = img + if key[0:3] == 'dig': + iconpath_tmp = iconpath_vdigit + else: + iconpath_tmp = iconpath_default else: - iconpath_tmp = iconpath_default - else: - iconpath_tmp = iconpath + iconpath_tmp = iconpath - if icons_img[key]: # join paths - if type (icons_img[key]) == type(''): - icons_img[key] = os.path.join(iconpath_tmp, icons_img[key]) -else: # default icons + if icons_img[key]: # join paths + if type (icons_img[key]) == type(''): + icons_img[key] = os.path.join(iconpath_tmp, icons_img[key]) +except: + print >> sys.stderr, _("Unable to load icon theme, using default icon theme...") + iconpath = None + +if iconpath is None: # default icons icons_img = icons_default for key, img in icons_img.iteritems(): if img and type (icons_img[key]) == type(''): From landa at grass.itc.it Thu Oct 18 18:47:06 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 18 18:47:07 2007 Subject: [grass-addons] r1141 - trunk/grassaddons/gui Message-ID: <200710181647.l9IGl6WV000430@grass.itc.it> Author: landa Date: 2007-10-18 18:46:53 +0200 (Thu, 18 Oct 2007) New Revision: 1141 Modified: trunk/grassaddons/gui/gis_set.py Log: cmd -> gcmd Modified: trunk/grassaddons/gui/gis_set.py =================================================================== --- trunk/grassaddons/gui/gis_set.py 2007-10-18 14:49:05 UTC (rev 1140) +++ trunk/grassaddons/gui/gis_set.py 2007-10-18 16:46:53 UTC (rev 1141) @@ -1,6 +1,4 @@ #!/usr/bin/env python -# -*- coding: UTF-8 -*- -# generated by wxGlade 0.4.1 on Mon Feb 26 18:29:42 2007 """ MODULE: gis_set.py @@ -32,7 +30,7 @@ import glob import shutil import wx.lib.rcsizer as rcs -import gui_modules.cmd as cmd +import gui_modules.gcmd as gcmd import shutil def read_grassrc(): From landa at grass.itc.it Fri Oct 19 15:04:00 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 19 15:04:02 2007 Subject: [grass-addons] r1142 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710191304.l9JD404W015220@grass.itc.it> Author: landa Date: 2007-10-19 15:03:56 +0200 (Fri, 19 Oct 2007) New Revision: 1142 Modified: trunk/grassaddons/gui/gui_modules/menudata.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/wxgui.py Log: Minor fixes for workspace file support. Modified: trunk/grassaddons/gui/gui_modules/menudata.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-18 16:46:53 UTC (rev 1141) +++ trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-19 13:03:56 UTC (rev 1142) @@ -29,7 +29,7 @@ ("New", "Create new workspace file (erase current workspace settings first)", "self.OnWorkspaceNew", ""), ("Open", "Open existing workspace file", "self.OnWorkspaceOpen", ""), ("Save", "Save current workspace to file", "self.OnWorkspaceSave", ""), - ("Save as", "Save current workspace as", "self.OnWorkspaceSave", ""), + ("Save as", "Save current workspace as", "self.OnWorkspaceSaveAs", ""), )), ("","","", ""), ("Import raster map", ( Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-18 16:46:53 UTC (rev 1141) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-19 13:03:56 UTC (rev 1142) @@ -379,17 +379,21 @@ # add layer to the layer tree if self.layer_selected and self.layer_selected != self.GetRootItem(): if self.GetPyData(self.layer_selected)[0]['type'] != 'group': - if lgroup is None or lgroup is True: + if lgroup is False: + # last child of root + layer = self.AppendItem(parentId=self.root, + text='', ct_type=1, wnd=ctrl) + elif lgroup is None or lgroup is True: + # insert item on given position parent = self.GetItemParent(self.layer_selected) - else: - parent = self.root - layer = self.InsertItem(parent, self.GetPrevSibling(self.layer_selected), - text='', ct_type=1, wnd=ctrl) - else: # group + layer = self.InsertItem(parentId=parent, input=self.GetPrevSibling(self.layer_selected), + text='', ct_type=1, wnd=ctrl) + + else: # group (first child of self.layer_selected) layer = self.PrependItem(parent=self.layer_selected, text='', ct_type=1, wnd=ctrl) self.Expand(self.layer_selected) - else: # add first layer to the layer tree + else: # add first layer to the layer tree (first child of root) layer = self.PrependItem(parent=self.root, text='', ct_type=1, wnd=ctrl) # layer is initially unchecked as inactive (beside 'command') @@ -398,8 +402,8 @@ checked = lchecked self.CheckItem(layer, checked=checked) - # select item - self.SelectItem(layer) + # select new item + self.SelectItem(layer, select=True) self.layer_selected = layer # add text and icons for each layer ltype @@ -448,13 +452,6 @@ self.SetItemImage(layer, self.folder) self.SetItemText(layer, grouptext) - # use predefined layer name if given - if lname: - if ltype != 'command': - self.SetItemText(layer, lname) - else: - ctrl.SetValue(lname) - self.first = False if ltype != 'group': @@ -497,7 +494,14 @@ 'maplayer' : None, 'prowin' : None}, None)) - + + # use predefined layer name if given + if lname: + if ltype != 'command': + self.SetItemText(layer, lname) + else: + ctrl.SetValue(lname) + return layer def PropertiesDialog (self, layer, show=True): @@ -642,16 +646,13 @@ cmd = event.GetString() layer = None - vislayer = self.GetFirstVisibleItem() + layer = self.GetFirstVisibleItem() - for item in range(0, self.GetCount()): - if self.GetPyData(vislayer)[0]['ctrl'] == ctrl: - layer = vislayer - - if not self.GetNextVisible(vislayer): + while layer and layer.IsOk(): + if self.GetPyData(layer)[0]['ctrl'] == ctrl: break - else: - vislayer = self.GetNextVisible(vislayer) + + layer = self.GetNextVisible(layer) # change parameters for item in layers list in render.Map if layer and self.drag == False: Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-18 16:46:53 UTC (rev 1141) +++ trunk/grassaddons/gui/wxgui.py 2007-10-19 13:03:56 UTC (rev 1142) @@ -436,7 +436,7 @@ caption=_("Save current settings?"), style=wx.OK | wx.CANCEL | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_OK: - self.OnWorkspaceSave(None) + self.OnWorkspaceSaveAs(None) dlg.Destroy() # delete all items @@ -455,6 +455,9 @@ if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() + if filename == '': + return + Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename) self.LoadGrcXmlToLayerTree(filename) @@ -492,34 +495,35 @@ self.OnWorkspaceNew(None) # read file and fix patch to dtd -# try: - file = open(filename, "r") + try: + file = open(filename, "r") - fileStream = ''.join(file.readlines()) - p = re.compile( '(grass-grc.dtd)') - p.search(fileStream) - fileStream = p.sub(dtdFilename, fileStream) + fileStream = ''.join(file.readlines()) + p = re.compile( '(grass-grc.dtd)') + p.search(fileStream) + fileStream = p.sub(dtdFilename, fileStream) - # sax - grcXml = ProcessGrcXml() - xml.sax.parseString(fileStream, grcXml) - maptree = self.curr_page.maptree - for layer in grcXml.layers: - newItem = maptree.AddLayer(ltype=layer['type'], - lname=layer['name'], - lchecked=layer['checked'], - lopacity=layer['opacity'], - lcmd=layer['cmd'], - lgroup=layer['group']) - maptree.PropertiesDialog(newItem, show=False) + # sax + grcXml = ProcessGrcXml() + xml.sax.parseString(fileStream, grcXml) + + maptree = self.curr_page.maptree + for layer in grcXml.layers: + newItem = maptree.AddLayer(ltype=layer['type'], + lname=layer['name'], + lchecked=layer['checked'], + lopacity=layer['opacity'], + lcmd=layer['cmd'], + lgroup=layer['group']) + maptree.PropertiesDialog(newItem, show=False) - file.close() - # except: -# dlg = wx.MessageDialog(self, _("Unable to read workspace file <%s>.") % filename, -# _("Error"), wx.OK | wx.ICON_ERROR) -# dlg.ShowModal() -# dlg.Destroy() -# return False + file.close() + except: + dlg = wx.MessageDialog(self, _("Unable to read workspace file <%s>.") % filename, + _("Error"), wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False return True @@ -551,13 +555,21 @@ Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename) self.SaveLayerTreeToGrcXml(filename) - + self.workspaceFile = filename + def OnWorkspaceSave(self, event): """Save file with workspace definition""" if self.workspaceFile: - Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile) - self.SaveLayerTreeToGrcXml(self.workspaceFile) + dlg = wx.MessageDialog(self, message=_("Workspace file <%s> already exists. " + "Do you want to overwrite this file?") % \ + self.workspaceFile, + caption=_("File exits"), style=wx.OK | wx.CANCEL | wx.ICON_QUESTION) + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + else: + Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile) + self.SaveLayerTreeToGrcXml(self.workspaceFile) else: self.OnWorkspaceSaveAs(None) @@ -575,6 +587,7 @@ if type == 'command': file.write(' \n' % \ (type, ' '.join(cmd), checked)); + file.write(' \n'); elif type == 'group': name = mapTree.GetItemText(item) file.write(' \n' % \ @@ -1225,7 +1238,6 @@ self.inGrc = True elif name == 'group': - self.inGroup = True self.groupName = attrs.get('name', None) self.groupChecked = attrs.get('checked', None) self.layers.append({ @@ -1234,7 +1246,8 @@ "checked" : int(self.groupChecked), "opacity" : None, "cmd" : None, - "group" : None}) + "group" : self.inGroup}) + self.inGroup = True elif name == 'layer': self.inLayer = True From landa at grass.itc.it Fri Oct 19 15:47:52 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 19 15:47:54 2007 Subject: [grass-addons] r1143 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710191347.l9JDlqQ0019005@grass.itc.it> Author: landa Date: 2007-10-19 15:47:48 +0200 (Fri, 19 Oct 2007) New Revision: 1143 Modified: trunk/grassaddons/gui/gui_modules/render.py trunk/grassaddons/gui/wxgui.py Log: Workspace file support: fix order of map layers. Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-10-19 13:03:56 UTC (rev 1142) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-10-19 13:47:48 UTC (rev 1143) @@ -905,7 +905,11 @@ return 1 self.layers = [] + def ReverseListOfLayers(self): + """Reverse list of layers""" + return self.layers.reverse() + if __name__ == "__main__": """ Test of Display class. Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-19 13:03:56 UTC (rev 1142) +++ trunk/grassaddons/gui/wxgui.py 2007-10-19 13:47:48 UTC (rev 1143) @@ -161,7 +161,6 @@ # initialize variables self.mapdisplays = {} # dictionary to index open map displays self.disp_idx = 0 # index value for map displays and layer trees - self.maptree = {} # dictionary to index a layer tree to accompanying a map display self.mapfocus = 0 # track which display currently has focus self.curr_page = '' # currently selected page for layer tree notebook self.curr_pagenum = '' # currently selected page number for layer tree notebook @@ -506,7 +505,6 @@ # sax grcXml = ProcessGrcXml() xml.sax.parseString(fileStream, grcXml) - maptree = self.curr_page.maptree for layer in grcXml.layers: newItem = maptree.AddLayer(ltype=layer['type'], @@ -516,7 +514,10 @@ lcmd=layer['cmd'], lgroup=layer['group']) maptree.PropertiesDialog(newItem, show=False) - + + # reverse list of map layers + maptree.Map.ReverseListOfLayers() + file.close() except: dlg = wx.MessageDialog(self, _("Unable to read workspace file <%s>.") % filename, From landa at grass.itc.it Fri Oct 19 20:43:21 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 19 20:43:23 2007 Subject: [grass-addons] r1144 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710191843.l9JIhL3c024817@grass.itc.it> Author: landa Date: 2007-10-19 20:43:16 +0200 (Fri, 19 Oct 2007) New Revision: 1144 Modified: trunk/grassaddons/gui/gui_modules/grass-grc.dtd trunk/grassaddons/gui/gui_modules/menudata.py trunk/grassaddons/gui/wxgui.py Log: Workspace file support: * multiple displays implemented * Close file implemented Modified: trunk/grassaddons/gui/gui_modules/grass-grc.dtd =================================================================== --- trunk/grassaddons/gui/gui_modules/grass-grc.dtd 2007-10-19 13:47:48 UTC (rev 1143) +++ trunk/grassaddons/gui/gui_modules/grass-grc.dtd 2007-10-19 18:43:16 UTC (rev 1144) @@ -14,8 +14,13 @@ - + + + + Modified: trunk/grassaddons/gui/gui_modules/menudata.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-19 13:47:48 UTC (rev 1143) +++ trunk/grassaddons/gui/gui_modules/menudata.py 2007-10-19 18:43:16 UTC (rev 1144) @@ -30,6 +30,7 @@ ("Open", "Open existing workspace file", "self.OnWorkspaceOpen", ""), ("Save", "Save current workspace to file", "self.OnWorkspaceSave", ""), ("Save as", "Save current workspace as", "self.OnWorkspaceSaveAs", ""), + ("Close", "Close selected workspace file", "self.OnWorkspaceClose", ""), )), ("","","", ""), ("Import raster map", ( Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-19 13:47:48 UTC (rev 1143) +++ trunk/grassaddons/gui/wxgui.py 2007-10-19 18:43:16 UTC (rev 1144) @@ -159,9 +159,7 @@ os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE" # initialize variables - self.mapdisplays = {} # dictionary to index open map displays self.disp_idx = 0 # index value for map displays and layer trees - self.mapfocus = 0 # track which display currently has focus self.curr_page = '' # currently selected page for layer tree notebook self.curr_pagenum = '' # currently selected page number for layer tree notebook self.encoding = 'ISO-8859-1' # default encoding for display fonts @@ -420,11 +418,13 @@ wx.AboutBox(info) - def OnWorkspaceNew(self, event): + def OnWorkspaceNew(self, event=None): """Create new workspace file Erase current workspace settings first""" + Debug.msg(4, "GMFrame.OnWorkspaceNew():") + maptree = self.curr_page.maptree # ask user to save current settings @@ -435,7 +435,7 @@ caption=_("Save current settings?"), style=wx.OK | wx.CANCEL | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_OK: - self.OnWorkspaceSaveAs(None) + self.OnWorkspaceSaveAs() dlg.Destroy() # delete all items @@ -445,7 +445,7 @@ maptree.root = maptree.AddRoot("Map Layers") self.curr_page.maptree.SetPyData(maptree.root, (None,None)) - def OnWorkspaceOpen(self, event): + def OnWorkspaceOpen(self, event=None): """Open file with workspace definition""" dlg = wx.FileDialog(parent=self, message=_("Choose workspace file"), defaultDir=os.getcwd(), wildcard="*.grc") @@ -491,7 +491,7 @@ return False # delete current layer tree content - self.OnWorkspaceNew(None) + self.OnWorkspaceNew() # read file and fix patch to dtd try: @@ -505,8 +505,11 @@ # sax grcXml = ProcessGrcXml() xml.sax.parseString(fileStream, grcXml) - maptree = self.curr_page.maptree for layer in grcXml.layers: + if layer['display'] >= self.disp_idx: + # create new map display window if needed + self.NewDisplay() + maptree = self.gm_cb.GetPage(layer['display']).maptree newItem = maptree.AddLayer(ltype=layer['type'], lname=layer['name'], lchecked=layer['checked'], @@ -528,7 +531,7 @@ return True - def OnWorkspaceSaveAs(self, event): + def OnWorkspaceSaveAs(self, event=None): """Save workspace definition to selected file""" dlg = wx.FileDialog(parent=self, message=_("Choose file to save current workspace"), @@ -558,7 +561,7 @@ self.SaveLayerTreeToGrcXml(filename) self.workspaceFile = filename - def OnWorkspaceSave(self, event): + def OnWorkspaceSave(self, event=None): """Save file with workspace definition""" if self.workspaceFile: @@ -572,10 +575,11 @@ Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile) self.SaveLayerTreeToGrcXml(self.workspaceFile) else: - self.OnWorkspaceSaveAs(None) + self.OnWorkspaceSaveAs() def WriteLayersToGrcXml(self, file, mapTree, item): """Write bunch of layers to GRC XML file""" + self.indent += 4 while item and item.IsOk(): type = mapTree.GetPyData(item)[0]['type'] if type != 'group': @@ -586,34 +590,46 @@ checked = int(item.IsChecked()) cmd = mapTree.GetPyData(item)[0]['cmd'] if type == 'command': - file.write(' \n' % \ - (type, ' '.join(cmd), checked)); - file.write(' \n'); + file.write('%s\n' % \ + (' ' * self.indent, type, ' '.join(cmd), checked)); + file.write('%s\n' % (' ' * self.indent)); elif type == 'group': name = mapTree.GetItemText(item) - file.write(' \n' % \ - (name, checked)); + file.write('%s\n' % \ + (' ' * self.indent, name, checked)); + self.indent += 4 subItem = mapTree.GetFirstChild(item)[0] self.WriteLayersToGrcXml(file, mapTree, subItem) - file.write(' \n'); + self.indent -= 4 + file.write('%s\n' % (' ' * self.indent)); else: name = mapTree.GetItemText(item) opacity = maplayer.GetOpacity(float=True) - file.write(' \n' % \ - (type, name, checked, opacity)); + file.write('%s\n' % \ + (' ' * self.indent, type, name, checked, opacity)); # layer properties - file.write(' \n' % cmd[0]) + self.indent += 4 + file.write('%s\n' % (' ' * self.indent, cmd[0])) + self.indent += 4 for option in cmd[1:]: if option[0] == '-': # flag - file.write(' \n' % option[1]) + file.write('%s\n' % + (' ' * self.indent, option[1])) else: # parameter key, value = option.split('=') - file.write(' \n' % key) - file.write(' %s\n' % value) - file.write(' \n'); - file.write(' \n'); - file.write(' \n'); + file.write('%s\n' % + (' ' * self.indent, key)) + self.indent += 4 + file.write('%s%s\n' % + (' ' * self.indent, value)) + self.indent -= 4 + file.write('%s\n' % (' ' * self.indent)); + self.indent -= 4 + file.write('%s\n' % (' ' * self.indent)); + self.indent -= 4 + file.write('%s\n' % (' ' * self.indent)); item = mapTree.GetNextSibling(item) + self.indent -= 4 def SaveLayerTreeToGrcXml(self, filename): """Save layer tree layout to workspace file @@ -631,15 +647,23 @@ return False try: + self.indent = 0 # number of spaces # write header file.write('\n') file.write('\n') - file.write('\n') - # list of layers - mapTree = self.curr_page.maptree - item = mapTree.GetFirstChild(mapTree.root)[0] - self.WriteLayersToGrcXml(file, mapTree, item) - file.write('\n') + file.write('%s\n' % (' ' * self.indent)) + # list of displays + for page in range(0, self.gm_cb.GetPageCount()): + self.indent =+ 4 + file.write('%s\n' % (' ' * self.indent)) + mapTree = self.gm_cb.GetPage(page).maptree + # list of layers + item = mapTree.GetFirstChild(mapTree.root)[0] + self.WriteLayersToGrcXml(file, mapTree, item) + file.write('%s\n' % (' ' * self.indent)) + self.indent =- 4 + file.write('%s\n' % (' ' * self.indent)) + del self.indent except: dlg = wx.MessageDialog(self, _("Writing current settings to workspace file failed."), _("Error"), wx.OK | wx.ICON_ERROR) @@ -651,14 +675,16 @@ return True - def OnWorkspaceClose(self, event): + def OnWorkspaceClose(self, event=None): """Close file with workspace definition If workspace has been modified ask user to save the changes. """ - pass + Debug.msg(4, "GMFrame.OnWorkspaceClose(): file=%s" % self.workspaceFile) + self.workspaceFile = None + def RulesCmd(self, event): """ Launches dialog for commands that need rules @@ -861,6 +887,8 @@ create an associated map display frame """ + Debug.msg(3, "GMFrame.NewDisplay(): idx=%d" % self.disp_idx) + # make a new page in the bookcontrol for the layer tree (on page 0 of the notebook) self.pg_panel = wx.Panel(self.gm_cb, id=wx.ID_ANY, style= wx.EXPAND) self.gm_cb.AddPage(self.pg_panel, text="Display "+ str(self.disp_idx), select = True) @@ -884,15 +912,15 @@ self.disp_idx += 1 -# self._auimgr.SetManagedWindow(self.curr_page.maptree.testframe) -# -# self._auimgr.AddPane(self.curr_page.maptree.testframe, -# wx.aui.AuiPaneInfo().Right(). -# BestSize((-1,-1)). -# CloseButton(True).MinimizeButton(True). -# DestroyOnClose(True).Layer(2)) -# -# self._auimgr.Update() + # self._auimgr.SetManagedWindow(self.curr_page.maptree.testframe) + # + # self._auimgr.AddPane(self.curr_page.maptree.testframe, + # wx.aui.AuiPaneInfo().Right(). + # BestSize((-1,-1)). + # CloseButton(True).MinimizeButton(True). + # DestroyOnClose(True).Layer(2)) + # + # self._auimgr.Update() # toolBar button handlers def OnRaster(self, event): @@ -1229,15 +1257,21 @@ self.inFlag = False self.inValue = False self.inGroup = False + self.inDisplay = False # list of layers self.layers = [] self.cmd = [] + self.displayIndex = -1 # first display has index '0' def startElement(self, name, attrs): if name == 'grc': self.inGrc = True - + + elif name == 'display': + self.inDisplay = True + self.displayIndex += 1 + elif name == 'group': self.groupName = attrs.get('name', None) self.groupChecked = attrs.get('checked', None) @@ -1247,7 +1281,8 @@ "checked" : int(self.groupChecked), "opacity" : None, "cmd" : None, - "group" : self.inGroup}) + "group" : self.inGroup, + "display" : self.displayIndex}) self.inGroup = True elif name == 'layer': @@ -1280,6 +1315,9 @@ if name == 'grc': self.inGrc = False + elif name == 'display': + self.inDisplay = False + elif name == 'group': self.inGroup = False self.groupName = self.groupChecked = None @@ -1292,7 +1330,9 @@ "checked" : int(self.layerChecked), "opacity" : None, "cmd" : None, - "group" : self.inGroup}) + "group" : self.inGroup, + "display" : self.displayIndex}) + if self.layerOpacity: self.layers[-1]["opacity"] = float(self.layerOpacity) if self.cmd: From landa at grass.itc.it Fri Oct 19 21:05:41 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 19 21:05:42 2007 Subject: [grass-addons] r1145 - trunk/grassaddons/gui Message-ID: <200710191905.l9JJ5feX024842@grass.itc.it> Author: landa Date: 2007-10-19 21:05:38 +0200 (Fri, 19 Oct 2007) New Revision: 1145 Modified: trunk/grassaddons/gui/README Log: README updated. Modified: trunk/grassaddons/gui/README =================================================================== --- trunk/grassaddons/gui/README 2007-10-19 18:43:16 UTC (rev 1144) +++ trunk/grassaddons/gui/README 2007-10-19 19:05:38 UTC (rev 1145) @@ -1,14 +1,10 @@ -GRASS graphical user interface -============================== +wxPython GRASS graphical user interface +======================================= -AUTHORS: Michael Barton, Jachym Cepicky, Martin Landa +0 - REQUIREMENTS -$LastChangedDate$ + Python >= 2.4 and wxPython >= 2.8.1.1 ---------------------------------------------------------------------- -Requirements: - Python >=2.4 and wxPython >=2.8.1.1 - Get wxPython 2.8.x packages from: * Source: http://www.wxpython.org/download.php * Debian GNU/Linux: http://wiki.wxpython.org/InstallingOnUbuntuOrDebian @@ -29,51 +25,48 @@ Get Python from: * Python.org for Source, MS-Windows, OS X: http://www.python.org/download/ * ActiveStates for AIX, HP-UX, Linux (x86), Linux 64-bit (x86_64 AMD64), Mac OS X, - Solaris (SPARC), Windows: http://www.activestate.com/store/download.aspx?prdGUID=b08b04e0-6872-4d9d-a722-7a0c2dea2758 ---------------------------------------------------------------------- + Solaris (SPARC), Windows: + http://www.activestate.com/store/download.aspx?prdGUID=b08b04e0-6872-4d9d-a722-7a0c2dea2758 -How to start: +1 - INSTALLATION -Download fresh source code from subversion: -$~ svn co https://grasssvn.itc.it/svn/grassaddons/trunk/grassaddons/gui grassaddons/gui +Download fresh source code from Subversion repository: +$ svn co https://grasssvn.itc.it/svn/grassaddons/trunk/grassaddons/gui grassaddons/gui + Or update your local repository -$~ svn up grassaddons/gui +$ svn up grassaddons/gui Change to GUI devel directory: -$~ cd grassaddons/gui +$ cd grassaddons/gui - -1 - INSTALLATION - -1.a) Put everything from gui into a new directory $GISBASE/etc/wx. - Or, easier, in GRASS: +1) Copy everything from gui directory into a new directory $GISBASE/etc/wx. + Or easier, create symlink (in running GRASS session): cd /path/to/grassaddons/gui - ln -s `pwd` $GISBASE/etc/wx + ln -s `pwd` $GISBASE/etc/wx -1.b) Move the script "wxgrass" into $GISBASE/scripts. - Or, easier, in GRASS: +2) Move the script "wxgrass" into $GISBASE/scripts. + Or easier, create symlink (in running GRASS session): cd /path/to/grassaddons/gui ln -s `pwd`/wxgrass $GISBASE/scripts 2 - STARTUP WITH GRASS INITIALIZATION -If you want to start the wxgrass GUI automatically when you start +If you want to run wxPython GUI automatically when you start GRASS, edit your .grassrc6 file to replace... GRASS_GUI: tcktk (or whatever you have here) -...with... +with GRASS_GUI: wx 3 - STARTUP FROM GRASS TERMINAL -Simply type wxgrass& from the GRASS terminal to start the GUI using the wxgrass script. +Simply type wxgrass from the GRASS terminal. - 4 - CLI Display scripts This is going to be replacement for command line tools like d.rast and From landa at grass.itc.it Sat Oct 20 00:17:35 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:46 2007 Subject: [grass-addons] r1146 - in trunk/grassaddons/gui: . icons Message-ID: <200710192217.l9JMHZeb026959@grass.itc.it> Author: landa Date: 2007-10-20 00:17:26 +0200 (Sat, 20 Oct 2007) New Revision: 1146 Modified: trunk/grassaddons/gui/gis_set.py trunk/grassaddons/gui/icons/icon.py Log: Code cleaning (basic) of GRASS start-up screen. Modified: trunk/grassaddons/gui/gis_set.py =================================================================== --- trunk/grassaddons/gui/gis_set.py 2007-10-19 19:05:38 UTC (rev 1145) +++ trunk/grassaddons/gui/gis_set.py 2007-10-19 22:17:26 UTC (rev 1146) @@ -7,16 +7,13 @@ * GRASSStartup * StartUp -PURPOSE: Initialization module for wxPython GUI for GRASS GIS. Includes - location/mapset selection, location/mapset creation, - location/mapset management. +PURPOSE: Initialization module for wxPython GRASS GUI. + Location/mapset management (selection, creation, etc.). - Usage: - python "$GISBASE/etc/wx/wxgui.py" -name wxgui_py - AUTHORS: The GRASS Development Team Michael Barton Jachym Cepicky + Martin Landa COPYRIGHT: (C) 2006-2007 by the GRASS Development Team This program is free software under the GNU General Public @@ -24,130 +21,140 @@ for details. """ - -import wx import os +import sys import glob import shutil -import wx.lib.rcsizer as rcs -import gui_modules.gcmd as gcmd -import shutil -def read_grassrc(): - """ - Read variables from $HOME/.grassrc6 file - """ +import wx +import wx.lib.rcsizer as rcs +import wx.lib.filebrowsebutton as filebrowse - grassrc = {} - - if os.path.isfile(os.getenv("GISRC")): - rc = open(os.getenv("GISRC"), "r") - for line in rc.readlines(): - key,val = line.split(":") - grassrc[key.strip()] = val.strip() - rc.close() - - return grassrc - class GRASSStartup(wx.Frame): - def __init__(self, *args, **kwds): - kwds["style"] = wx.DEFAULT_FRAME_STYLE - wx.Frame.__init__(self, *args, **kwds) + """GRASS start-up screen""" + def __init__(self, parent=None, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE): # - # variables + # GRASS variables # - self.grassrc = read_grassrc() - self.gisbase=os.getenv("GISBASE") - self.gisdbase=self._getRCValue("GISDBASE") + self.gisbase = os.getenv("GISBASE") + self.grassrc = self._read_grassrc() + self.gisdbase = self._getRCValue("GISDBASE") + + # + # list of locations/mapsets + # self.listOfLocations = [] self.listOfMapsets = [] + wx.Frame.__init__(self, parent=parent, id=id, style=style) + # # graphical elements # + # image try: - self.hbitmap = wx.StaticBitmap(self, -1, - wx.Bitmap(os.path.join(self.gisbase,"etc","gintro.gif"), wx.BITMAP_TYPE_ANY)) + name = os.path.join(self.gisbase, "etc", "gintro.gif") + self.hbitmap = wx.StaticBitmap(self, wx.ID_ANY, + wx.Bitmap(name=name, + type=wx.BITMAP_TYPE_GIF)) except: - self.hbitmap = wx.StaticBitmap(self, -1, wx.EmptyBitmap(530,150)) + self.hbitmap = wx.StaticBitmap(self, wx.ID_ANY, wx.EmptyBitmap(530,150)) # labels - self.lwelcome = wx.StaticText(self, -1, - "Welcome to GRASS GIS Version 6.3.cvs\n"+\ - "The world's leading open source GIS", - style=wx.ALIGN_CENTRE) - self.ltitle = wx.StaticText(self, -1, - "Select an existing project location and mapset\n"+\ - "or define a new location", - style=wx.ALIGN_CENTRE) - self.ldbase = wx.StaticText(self, -1, "GIS Data Directory:") - self.llocation = wx.StaticText(self, -1, "Project Location\n(projection/coordinate system)", style=wx.ALIGN_CENTRE) - self.lmapset = wx.StaticText(self, -1, "Accessible Mapsets\n(directories of GIS files)", style=wx.ALIGN_CENTRE) - self.lmanage = wx.StaticText(self, -1, "Manage Locations\nand Mapsets", style=wx.ALIGN_CENTRE) - self.lcreate = wx.StaticText(self, -1, "Create new mapset\nin selected location", style=wx.ALIGN_CENTRE) - self.ldefine = wx.StaticText(self, -1, "Define new location", style=wx.ALIGN_CENTRE) - self.lmanageloc = wx.StaticText(self, -1, "Rename/delete selected\nmapset or location", style=wx.ALIGN_CENTRE) + versionCmd = gcmd.Command(['g.version']) + grassVersion = versionCmd.ReadStdOutput()[0].replace('GRASS', '').strip() + self.lwelcome = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Welcome to GRASS GIS %s\n" + "The world's leading open source GIS") % grassVersion, + style=wx.ALIGN_CENTRE) + self.ltitle = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Select an existing project location and mapset\n" + "or define a new location"), + style=wx.ALIGN_CENTRE) + self.ldbase = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("GIS Data Directory:")) + self.llocation = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Project location\n(projection/coordinate system)"), + style=wx.ALIGN_CENTRE) + self.lmapset = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Accessible mapsets\n(directories of GIS files)"), + style=wx.ALIGN_CENTRE) + self.lcreate = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Create new mapset\nin selected location"), + style=wx.ALIGN_CENTRE) + self.ldefine = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Define new location"), + style=wx.ALIGN_CENTRE) + self.lmanageloc = wx.StaticText(parent=self, id=wx.ID_ANY, + label=_("Rename/delete selected\nmapset or location"), + style=wx.ALIGN_CENTRE) + # buttons - buttonsize1 = (150,-1) - buttonsize2 = (150, -1) - - self.bstart = wx.Button(self, -1, "Start GRASS", size=buttonsize2) + self.bstart = wx.Button(parent=self, id=wx.ID_ANY, + label=_("Start GRASS"), size=(200, -1)) self.bstart.SetDefault() - self.bexit = wx.Button(self, -1, "Exit", size=buttonsize2) - self.bhelp = wx.Button(self, -1, "Help", size=buttonsize2) - self.bbrowse = wx.Button(self, -1, "Browse ...", size=(-1,-1)) - self.bmapset = wx.Button(self, -1, "Create mapset", size=buttonsize1) - self.bwizard = wx.Button(self, -1, "Location wizard", size=buttonsize1) - choicelist = ['Rename mapset','Rename location', 'Delete mapset', 'Delete location'] - self.manageloc = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, choices=choicelist) + self.bexit = wx.Button(parent=self, id=wx.ID_EXIT) + self.bhelp = wx.Button(parent=self, id=wx.ID_HELP) + self.bbrowse = wx.Button(parent=self, id=wx.ID_ANY, + label=_("Browse")) + self.bmapset = wx.Button(parent=self, id=wx.ID_ANY, + label=_("Create mapset")) + self.bwizard = wx.Button(parent=self, id=wx.ID_ANY, + label=_("Location wizard")) + self.manageloc = wx.Choice(parent=self, id=wx.ID_ANY, + choices=['Rename mapset','Rename location', + 'Delete mapset', 'Delete location']) # textinputs - self.tgisdbase = wx.TextCtrl(self, -1, "", size=(300, 20), - style=wx.TE_LEFT) - self.tnewmapset = wx.TextCtrl(self,-1, "", size=(150,20)) + self.tgisdbase = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(300, -1), + style=wx.TE_LEFT) # Locations - self.lpanel = wx.Panel(self,-1) - self.lblocations = wx.ListBox(self.lpanel, - id=26, pos=wx.DefaultPosition, size=(150, 200), - choices=self.listOfLocations, style=wx.LB_SINGLE) + self.lpanel = wx.Panel(parent=self,id=wx.ID_ANY) + self.lblocations = wx.ListBox(parent=self.lpanel, + id=wx.ID_ANY, size=(150, 200), + choices=self.listOfLocations, + style=wx.LB_SINGLE) # Mapsets - self.mpanel = wx.Panel(self,-1) - self.lbmapsets = wx.ListBox(self.mpanel, - id=26, pos=wx.DefaultPosition, size=(150, 200), - choices=self.listOfMapsets, style=wx.LB_SINGLE) + self.mpanel = wx.Panel(parent=self,id=wx.ID_ANY) + self.lbmapsets = wx.ListBox(parent=self.mpanel, + id=wx.ID_ANY, size=(150, 200), + choices=self.listOfMapsets, + style=wx.LB_SINGLE) # layout & properties - self.__set_properties() - self.__do_layout() + self._set_properties() + self._do_layout() # events - self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) - self.bstart.Bind(wx.EVT_BUTTON, self.OnStart) - self.bexit.Bind(wx.EVT_BUTTON, self.OnExit) - self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp) - self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset) - self.bwizard.Bind(wx.EVT_BUTTON, self.OnWizard) - self.manageloc.Bind(wx.EVT_CHOICE, self.OnManageLoc) + self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) + self.bstart.Bind(wx.EVT_BUTTON, self.OnStart) + self.bexit.Bind(wx.EVT_BUTTON, self.OnExit) + self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp) + self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset) + self.bwizard.Bind(wx.EVT_BUTTON, self.OnWizard) + self.manageloc.Bind(wx.EVT_CHOICE, self.OnManageLoc) self.lblocations.Bind(wx.EVT_LISTBOX, self.OnSelectLocation) - self.lbmapsets.Bind(wx.EVT_LISTBOX, self.OnSelectMapset) - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressedInDbase, self.tgisdbase) - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressedInMapset, self.tnewmapset) - self.Bind(wx.EVT_CLOSE, self.onCloseWindow) + self.lbmapsets.Bind(wx.EVT_LISTBOX, self.OnSelectMapset) + self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressedInDbase, self.tgisdbase) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) - def __set_properties(self): - self.SetTitle("Welcome to GRASS GIS") - self.SetIcon(wx.Icon(os.path.join(self.gisbase,"etc","dm","grass.gif"), - wx.BITMAP_TYPE_GIF)) + def _set_properties(self): + """Set frame properties""" + self.SetTitle(_("Welcome to GRASS GIS")) + self.SetIcon(wx.Icon(os.path.join(self.gisbase, "etc", "dm", "grass.gif"), + wx.BITMAP_TYPE_GIF)) + self.lwelcome.SetForegroundColour(wx.Colour(35, 142, 35)) self.lwelcome.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.bstart.SetForegroundColour(wx.Colour(35, 142, 35)) - self.bstart.SetToolTipString("Enter GRASS session") - #self.bstart.Enable(False) - #self.bmapset.Enable(False) + self.bstart.SetToolTipString(_("Enter GRASS session")) + # self.bstart.Enable(False) + # self.bmapset.Enable(False) # set database if not self.gisdbase: @@ -172,98 +179,183 @@ mapset =self._getRCValue("MAPSET") if mapset: self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset)) - #self.bstart.Enable(True) + # self.bstart.Enable(True) - def __do_layout(self): + def _do_layout(self): label_style = wx.ADJUST_MINSIZE | wx.ALIGN_CENTER_HORIZONTAL - sizer = wx.BoxSizer(wx.VERTICAL) - dbase_sizer=wx.BoxSizer(wx.HORIZONTAL) - grid_sizer = wx.FlexGridSizer(4, 3, 4, 4) - mapset_sizer = wx.BoxSizer(wx.VERTICAL) - dbase_sizer.Add(self.ldbase, 0, wx.ALIGN_CENTER_VERTICAL| - wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) - dbase_sizer.Add(self.tgisdbase, 0, wx.ALIGN_CENTER_VERTICAL - |wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) - dbase_sizer.Add(self.bbrowse, 0, wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) + sizer = wx.BoxSizer(wx.VERTICAL) + dbase_sizer = wx.BoxSizer(wx.HORIZONTAL) + location_sizer = wx.FlexGridSizer(rows=1, cols=2, vgap=4, hgap=4) + select_box = wx.StaticBox (parent=self, id=wx.ID_ANY, + label=" %s " % _("Choose location and mapset")) + select_boxsizer = wx.StaticBoxSizer(select_box, wx.VERTICAL) + select_sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=4, hgap=4) + manage_box = wx.StaticBox (parent=self, id=wx.ID_ANY, + label=" %s " % _("Manage")) + manage_boxsizer = wx.StaticBoxSizer(manage_box, wx.VERTICAL) + manage_sizer = wx.BoxSizer(wx.VERTICAL) + btns_sizer = wx.BoxSizer(wx.HORIZONTAL) - mapset_sizer.Add(self.ldefine, 0, label_style|wx.RIGHT|wx.LEFT|wx.BOTTOM, 5) - mapset_sizer.Add(self.bwizard, 0, label_style|wx.BOTTOM, 8) - mapset_sizer.Add(self.lcreate, 0, label_style|wx.TOP|wx.RIGHT|wx.LEFT, 5) - mapset_sizer.Add(self.tnewmapset, 0, label_style|wx.ALL, 5) - mapset_sizer.Add(self.bmapset, 0, label_style|wx.BOTTOM, 8) - mapset_sizer.Add(self.lmanageloc, 0, label_style|wx.TOP|wx.RIGHT|wx.LEFT, 5) - mapset_sizer.Add(self.manageloc, 0, label_style|wx.ALL, 5) - mapset_sizer.Add((5,0)) + # gis data directory + dbase_sizer.Add(item=self.ldbase, proportion=0, + flag=wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, + border=5) + dbase_sizer.Add(item=self.tgisdbase, proportion=0, + flag=wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, + border=5) + dbase_sizer.Add(item=self.bbrowse, proportion=0, + flag=wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, + border=5) - grid_sizer.Add(self.llocation, 0,label_style|wx.ALL, 5) - grid_sizer.Add(self.lmapset, 0,label_style|wx.ALL, 5) - grid_sizer.Add(self.lmanage, 0,label_style|wx.ALL, 5) + # select sizer + select_sizer.Add(item=self.llocation, proportion=0, + flag=label_style | wx.ALL, + border=5) + select_sizer.Add(item=self.lmapset, proportion=0, + flag=label_style | wx.ALL, + border=5) + select_sizer.Add(item=self.lpanel, proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL) + select_sizer.Add(item=self.mpanel, proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL) - grid_sizer.Add(self.lpanel, 0, wx.ADJUST_MINSIZE| - wx.ALIGN_CENTER_VERTICAL| - wx.ALIGN_CENTER_HORIZONTAL, 0) - grid_sizer.Add(self.mpanel, 0, wx.ADJUST_MINSIZE| - wx.ALIGN_CENTER_VERTICAL| - wx.ALIGN_CENTER_HORIZONTAL, 0) - grid_sizer.Add(mapset_sizer, 0, wx.ADJUST_MINSIZE| - wx.ALIGN_CENTER_VERTICAL| - wx.ALIGN_CENTER_HORIZONTAL, 0) + select_boxsizer.Add(item=select_sizer, proportion=0) - grid_sizer.Add(self.bstart, 0, wx.ADJUST_MINSIZE| - wx.ALIGN_TOP| - wx.ALIGN_CENTER_HORIZONTAL| - wx.BOTTOM, 10) - grid_sizer.Add(self.bexit, 0, wx.ADJUST_MINSIZE| - wx.ALIGN_CENTER_VERTICAL| - wx.ALIGN_CENTER_HORIZONTAL| - wx.BOTTOM, 10) - grid_sizer.Add(self.bhelp, 0, wx.ADJUST_MINSIZE| - wx.ALIGN_CENTER_VERTICAL| - wx.ALIGN_CENTER_HORIZONTAL| - wx.BOTTOM, 10) + # define new location and mapset + manage_sizer.Add(item=self.ldefine, proportion=0, + flag=label_style | wx.ALL, + border=5) + manage_sizer.Add(item=self.bwizard, proportion=0, + flag=label_style | wx.BOTTOM, + border=8) + manage_sizer.Add(item=self.lcreate, proportion=0, + flag=label_style | wx.ALL, + border=5) + manage_sizer.Add(item=self.bmapset, proportion=0, + flag=label_style | wx.BOTTOM, + border=8) + manage_sizer.Add(item=self.lmanageloc, proportion=0, + flag=label_style | wx.ALL, + border=5) + manage_sizer.Add(item=self.manageloc, proportion=0, + flag=label_style | wx.BOTTOM, + border=8) + + manage_boxsizer.Add(item=manage_sizer, proportion=0) - # adding to main VERTICAL sizer - sizer.Add(self.hbitmap, 0, wx.ADJUST_MINSIZE | - wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.BOTTOM, 5) # image - sizer.Add(self.lwelcome, # welcome message - 0,wx.ADJUST_MINSIZE | - wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.EXPAND | - wx.BOTTOM, 10) - sizer.Add(self.ltitle, # controls title - 0,wx.ADJUST_MINSIZE | - wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.EXPAND | - wx.BOTTOM, 5) - sizer.Add(dbase_sizer,0,wx.ADJUST_MINSIZE | - wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.RIGHT | wx.LEFT, 5) # GISDBASE setting - sizer.Add(grid_sizer, 1, wx.ADJUST_MINSIZE | - wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.RIGHT | wx.LEFT, 5) + # location sizer + location_sizer.Add(item=select_boxsizer, proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.RIGHT | wx.LEFT, + border=5) # GISDBASE setting + location_sizer.Add(item=manage_boxsizer, proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_TOP | + wx.ALIGN_CENTER_HORIZONTAL | + wx.RIGHT, + border=5) + + # buttons + btns_sizer.Add(item=self.bstart, proportion=0, + flag=wx.ALIGN_CENTER_HORIZONTAL | + wx.ALL, + border=10) + btns_sizer.Add(item=self.bexit, proportion=0, + flag=wx.ALIGN_CENTER_HORIZONTAL | + wx.ALL, + border=10) + btns_sizer.Add(item=self.bhelp, proportion=0, + flag=wx.ALIGN_CENTER_HORIZONTAL | + wx.ALL, + border=10) + + # main sizer + sizer.Add(item=self.hbitmap, proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.BOTTOM | wx.TOP, + border=5) # image + sizer.Add(item=self.lwelcome, # welcome message + proportion=0, + flag= wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.EXPAND | + wx.BOTTOM, + border=10) + sizer.Add(item=self.ltitle, # title + proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.EXPAND | + wx.BOTTOM, + border=5) + sizer.Add(item=dbase_sizer, proportion=0, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.RIGHT | wx.LEFT, + border=5) # GISDBASE setting + sizer.Add(item=location_sizer, proportion=1, + flag=wx.ADJUST_MINSIZE | + wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.RIGHT | wx.LEFT, + border=5) + sizer.Add(item=btns_sizer, proportion=0, + flag=wx.ALIGN_CENTER_VERTICAL | + wx.ALIGN_CENTER_HORIZONTAL | + wx.RIGHT | wx.LEFT, + border=5) + self.SetAutoLayout(True) self.SetSizer(sizer) sizer.Fit(self) sizer.SetSizeHints(self) self.Layout() - # end wxGlade - def _getRCValue(self,value): + def _read_grassrc(self): + """ + Read variables from $HOME/.grassrc6 file + """ + grassrc = {} + + gisrc = os.getenv("GISRC") + + if gisrc and os.path.isfile(gisrc): + try: + rc = open(gisrc, "r") + for line in rc.readlines(): + key, val = line.split(":") + grassrc[key.strip()] = val.strip() + finally: + rc.close() + + return grassrc + + def _getRCValue(self, value): + "Return GRASS variable (read from GISRC)""" + if self.grassrc.has_key(value): return self.grassrc[value] else: return None def OnWizard(self,event): + """Location wizard started""" import location_wizard reload(location_wizard) gWizard = location_wizard.GWizard(self, self.tgisdbase.GetValue()) @@ -290,7 +382,7 @@ def RenameMapset(self): """ - Renames selected mapset + Rename selected mapset """ location = location=self.listOfLocations[self.lblocations.GetSelection()] @@ -313,7 +405,7 @@ def RenameLocation(self): """ - Renames selected location + Rename selected location """ location = location=self.listOfLocations[self.lblocations.GetSelection()] @@ -337,7 +429,7 @@ def DeleteMapset(self): """ - Deletes selected mapset + Delete selected mapset """ location = location=self.listOfLocations[self.lblocations.GetSelection()] @@ -357,7 +449,7 @@ def DeleteLocation(self): """ - Deletes selected location + Delete selected location """ location = location=self.listOfLocations[self.lblocations.GetSelection()] @@ -374,7 +466,7 @@ dlg.Destroy() def UpdateLocations(self,dbase): - + """Update list of locations""" self.listOfLocations = [] for location in glob.glob(os.path.join(dbase,"*")): try: @@ -387,7 +479,7 @@ return self.listOfLocations def UpdateMapsets(self,location): - + """Update list of mapsets""" self.listOfMapsets = [] for mapset in glob.glob(os.path.join(location,"*")): if os.path.isdir(mapset): @@ -397,6 +489,7 @@ return self.listOfMapsets def OnSelectLocation(self,event): + """Location selected""" if self.lblocations.GetSelection() > -1: self.UpdateMapsets(os.path.join( self.gisdbase,self.listOfLocations[self.lblocations.GetSelection()])) @@ -406,10 +499,12 @@ self.lbmapsets.InsertItems(self.listOfMapsets,0) def OnSelectMapset(self,event): + """Mapset selected""" #self.bstart.Enable(True) pass def OnSetDatabase(self,event): + """Database set""" self.gisdbase = self.tgisdbase.GetValue() self.UpdateLocations(self.gisdbase) self.lblocations.Clear() @@ -418,7 +513,7 @@ self.OnSelectLocation(event) def OnBrowse(self, event): - + """'Browse' button clicked""" grassdata = None dlg = wx.DirDialog(self, "Choose a GRASS directory:", @@ -437,31 +532,33 @@ event.Skip() def OnCreateMapset(self,event): + """Create new mapset""" self.gisdbase = self.tgisdbase.GetValue() location = self.listOfLocations[self.lblocations.GetSelection()] - try: - mapset = self.tnewmapset.GetValue() - os.mkdir(os.path.join(self.gisdbase,location,mapset)) - # copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r - shutil.copy(os.path.join(self.gisdbase,location,'PERMANENT','WIND'), - os.path.join(self.gisdbase,location,mapset)) -# os.chmod(os.path.join(database,location,mapset,'WIND'), 0644) - self.OnSelectLocation(None) - self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset)) - except StandardError, e: - dlg = wx.MessageDialog(self, "Could not create new mapset: %s" - % e,"Can not create mapset", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() + dlg = wx.TextEntryDialog(parent=self, + message=_('Enter name for new mapset:'), + caption='Rename selected mapset') - def OnKeyPressedInMapset(self,event): - if wx.WXK_RETURN == event.KeyCode: - self.OnCreateMapset(None) - else: - #self.bmapset.Enable(True) - event.Skip() + if dlg.ShowModal() == wx.ID_OK: + mapset = dlg.GetValue() + try: + os.mkdir(os.path.join(self.gisdbase, location, mapset)) + # copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r + shutil.copy(os.path.join(self.gisdbase, location, 'PERMANENT', 'WIND'), + os.path.join(self.gisdbase, location, mapset)) + # os.chmod(os.path.join(database,location,mapset,'WIND'), 0644) + self.OnSelectLocation(None) + self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset)) + except StandardError, e: + dlg = wx.MessageDialog(parent=self, message=_("Unable to create new mapset: %s") % e, + caption=_("Error"), style=wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False + return True + def OnStart(self, event): print "g.gisenv set=GISDBASE='%s';" % self.tgisdbase.GetValue() print "g.gisenv set=LOCATION_NAME='%s';" % self.listOfLocations[self.lblocations.GetSelection()] @@ -469,28 +566,37 @@ self.Destroy() def OnExit(self, event): - print "exit" + """'Exit' button clicked""" self.Destroy() def OnHelp(self, event): + """'Help' button clicked""" wx.MessageBox("Help not yet implemented") event.Skip() - def onCloseWindow(self, event): - print "exit" + def OnCloseWindow(self, event): + """Close window event""" event.Skip() class StartUp(wx.App): + """Start-up application""" + def OnInit(self): wx.InitAllImageHandlers() - StartUp = GRASSStartup(None, -1, "") + StartUp = GRASSStartup() self.SetTopWindow(StartUp) StartUp.Show() return 1 -# end of class StartUp - if __name__ == "__main__": + + if os.getenv("GISBASE") is None: + print >> sys.stderr, "Failed to start GUI, GRASS GIS is not running." + else: + import gettext + gettext.install("GRASSStartUp") # replace with the appropriate catalog name + + import gui_modules.gcmd as gcmd - GRASSStartUp = StartUp(0) - GRASSStartUp.MainLoop() + GRASSStartUp = StartUp(0) + GRASSStartUp.MainLoop() Modified: trunk/grassaddons/gui/icons/icon.py =================================================================== --- trunk/grassaddons/gui/icons/icon.py 2007-10-19 19:05:38 UTC (rev 1145) +++ trunk/grassaddons/gui/icons/icon.py 2007-10-19 22:17:26 UTC (rev 1146) @@ -114,7 +114,7 @@ # merge icons dictionaries, join paths try: - if not os.path.exists(iconpath): + if iconpath and not os.path.exists(iconpath): raise OSError if iconpath is not None and iconpath.find('silk') > -1: # silk icon theme from silk import IconsSilk as icons_img From landa at grass.itc.it Sat Oct 20 00:25:12 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:46 2007 Subject: [grass-addons] r1147 - trunk/grassaddons/gui Message-ID: <200710192225.l9JMPCK9027002@grass.itc.it> Author: landa Date: 2007-10-20 00:25:07 +0200 (Sat, 20 Oct 2007) New Revision: 1147 Modified: trunk/grassaddons/gui/gis_set.py Log: Center on screen Modified: trunk/grassaddons/gui/gis_set.py =================================================================== --- trunk/grassaddons/gui/gis_set.py 2007-10-19 22:17:26 UTC (rev 1146) +++ trunk/grassaddons/gui/gis_set.py 2007-10-19 22:25:07 UTC (rev 1147) @@ -1,5 +1,3 @@ -#!/usr/bin/env python - """ MODULE: gis_set.py @@ -584,6 +582,7 @@ def OnInit(self): wx.InitAllImageHandlers() StartUp = GRASSStartup() + StartUp.CenterOnScreen() self.SetTopWindow(StartUp) StartUp.Show() return 1 From landa at grass.itc.it Sat Oct 20 00:28:25 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:46 2007 Subject: [grass-addons] r1148 - trunk/grassaddons/gui Message-ID: <200710192228.l9JMSPRq027024@grass.itc.it> Author: landa Date: 2007-10-20 00:28:09 +0200 (Sat, 20 Oct 2007) New Revision: 1148 Modified: trunk/grassaddons/gui/gis_set.py trunk/grassaddons/gui/wxgui.py Log: Delete prop:executable. Property changes on: trunk/grassaddons/gui/gis_set.py ___________________________________________________________________ Name: svn:executable - * Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-19 22:25:07 UTC (rev 1147) +++ trunk/grassaddons/gui/wxgui.py 2007-10-19 22:28:09 UTC (rev 1148) @@ -1,5 +1,3 @@ -#!/usr/bin python - """ MODULE: wxgui.py Property changes on: trunk/grassaddons/gui/wxgui.py ___________________________________________________________________ Name: svn:executable - * From landa at grass.itc.it Sat Oct 20 11:51:52 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:46 2007 Subject: [grass-addons] r1149 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710200951.l9K9pq1n026747@grass.itc.it> Author: landa Date: 2007-10-20 11:51:46 +0200 (Sat, 20 Oct 2007) New Revision: 1149 Added: trunk/grassaddons/gui/gui_modules/location_wizard.py trunk/grassaddons/gui/gui_modules/states.txt Removed: trunk/grassaddons/gui/location_wizard.py trunk/grassaddons/gui/states.txt Modified: trunk/grassaddons/gui/gis_set.py Log: Cleaning of gis_set.py, some bugs fixed. location_wizard module moved to gui_modules directory. Modified: trunk/grassaddons/gui/gis_set.py =================================================================== --- trunk/grassaddons/gui/gis_set.py 2007-10-19 22:28:09 UTC (rev 1148) +++ trunk/grassaddons/gui/gis_set.py 2007-10-20 09:51:46 UTC (rev 1149) @@ -3,6 +3,7 @@ CLASSES: * GRASSStartup + * HelpWindow * StartUp PURPOSE: Initialization module for wxPython GRASS GUI. @@ -25,9 +26,12 @@ import shutil import wx +import wx.html import wx.lib.rcsizer as rcs import wx.lib.filebrowsebutton as filebrowse +from gui_modules import location_wizard + class GRASSStartup(wx.Frame): """GRASS start-up screen""" def __init__(self, parent=None, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE): @@ -354,7 +358,6 @@ def OnWizard(self,event): """Location wizard started""" - import location_wizard reload(location_wizard) gWizard = location_wizard.GWizard(self, self.tgisdbase.GetValue()) if gWizard.location != None: @@ -383,21 +386,23 @@ Rename selected mapset """ - location = location=self.listOfLocations[self.lblocations.GetSelection()] - mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] - dlg = wx.TextEntryDialog( - self, 'Current name: %s\nEnter new name:' % mapset, - 'Rename selected mapset') + location = self.listOfLocations[self.lblocations.GetSelection()] + mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] + dlg = wx.TextEntryDialog(parent=self, + message=_('Current name: %s\nEnter new name:') % mapset, + caption=_('Rename selected mapset')) + if dlg.ShowModal() == wx.ID_OK: newmapset = dlg.GetValue() - try: - os.rename(os.path.join(self.gisdbase,location,mapset),\ - os.path.join(self.gisdbase,location,newmapset)) - self.OnSelectLocation(None) - self.lbmapsets.SetSelection(self.listOfMapsets.index(newmapset)) - except: - wx.MessageBox('Mapset could not be renamed') + if newmapset != mapset: + try: + os.rename(os.path.join(self.gisdbase, location, mapset), + os.path.join(self.gisdbase, location, newmapset)) + self.OnSelectLocation(None) + self.lbmapsets.SetSelection(self.listOfMapsets.index(newmapset)) + except: + wx.MessageBox(message=_('Unable to rename mapset')) dlg.Destroy() @@ -406,23 +411,25 @@ Rename selected location """ - location = location=self.listOfLocations[self.lblocations.GetSelection()] - dlg = wx.TextEntryDialog( - self, 'Current name: %s\nEnter new name:' % location, - 'Rename selected location') + location = self.listOfLocations[self.lblocations.GetSelection()] + dlg = wx.TextEntryDialog(parent=self, + message=_('Current name: %s\nEnter new name:') % location, + caption=_('Rename selected location')) + if dlg.ShowModal() == wx.ID_OK: newlocation = dlg.GetValue() - mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] - try: - os.rename(os.path.join(self.gisdbase,location),\ - os.path.join(self.gisdbase,newlocation)) - self.UpdateLocations(self.gisdbase) - self.lblocations.SetSelection(self.listOfLocations.index(newlocation)) + if newlocation != location: + mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] + try: + os.rename(os.path.join(self.gisdbase, location), + os.path.join(self.gisdbase, newlocation)) + self.UpdateLocations(self.gisdbase) + self.lblocations.SetSelection(self.listOfLocations.index(newlocation)) + self.UpdateMapsets(newlocation) + except: + wx.MessageBox(message=_('Unable to rename location')) - except: - wx.MessageBox('Location could not be renamed') - dlg.Destroy() def DeleteMapset(self): @@ -430,18 +437,23 @@ Delete selected mapset """ - location = location=self.listOfLocations[self.lblocations.GetSelection()] - mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] - dlg = wx.MessageDialog(self, "Do you want to continue with deleting the mapset?", - "WARNING! Mapset '%s', and ALL MAPS it contains will be PERMANENTLY DELETED!" - % mapset,wx.YES_NO|wx.NO_DEFAULT|wx.ICON_EXCLAMATION) + location = self.listOfLocations[self.lblocations.GetSelection()] + mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] + + dlg = wx.MessageDialog(parent=self, message=_("Do you want to continue with deleting mapset <%s> " + "from location <%s>?\n\n" + "ALL MAPS included in this mapset will be " + "PERMANENTLY DELETED!") % (mapset, location), + caption=_("Delete selected mapset"), + style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_YES: try: - shutil.rmtree(os.path.join(self.gisdbase,location,mapset)) + shutil.rmtree(os.path.join(self.gisdbase, location, mapset)) self.OnSelectLocation(None) self.lbmapsets.SetSelection(0) except: - wx.MessageBox('Mapset could not be deleted') + wx.MessageBox(message=_('Unable to delete mapset')) dlg.Destroy() @@ -450,64 +462,84 @@ Delete selected location """ - location = location=self.listOfLocations[self.lblocations.GetSelection()] - dlg = wx.MessageDialog(self, "Do you want to continue with deleting the location?", - "WARNING! Location '%s', and ALL MAPSETS and MAPS it contains will be PERMANENTLY DELETED!" - % location,wx.YES_NO|wx.NO_DEFAULT|wx.ICON_EXCLAMATION) + location = self.listOfLocations[self.lblocations.GetSelection()] + + dlg = wx.MessageDialog(parent=self, message=_("Do you want to continue with deleting " + "location <%s>?\n\n" + "ALL MAPS included in this location will be " + "PERMANENTLY DELETED!") % (location), + caption=_("Delete selected location"), + style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_YES: try: - shutil.rmtree(os.path.join(self.gisdbase,location)) + shutil.rmtree(os.path.join(self.gisdbase, location)) self.UpdateLocations(self.gisdbase) + self.lblocations.SetSelection(0) + self.OnSelectLocation(None) + self.lbmapsets.SetSelection(0) except: - wx.MessageBox('Location could not be deleted') + wx.MessageBox(message=_('Unable to delete location')) dlg.Destroy() - def UpdateLocations(self,dbase): + def UpdateLocations(self, dbase): """Update list of locations""" self.listOfLocations = [] - for location in glob.glob(os.path.join(dbase,"*")): + + for location in glob.glob(os.path.join(dbase, "*")): try: - if os.path.join(location,"PERMANENT") in glob.glob(os.path.join(location,"*")): + if os.path.join(location, "PERMANENT") in glob.glob(os.path.join(location, "*")): self.listOfLocations.append(os.path.basename(location)) except: pass + self.lblocations.Clear() - self.lblocations.InsertItems(self.listOfLocations,0) + self.lblocations.InsertItems(self.listOfLocations, 0) + return self.listOfLocations - def UpdateMapsets(self,location): + def UpdateMapsets(self, location): """Update list of mapsets""" self.listOfMapsets = [] - for mapset in glob.glob(os.path.join(location,"*")): + + for mapset in glob.glob(os.path.join(self.gisdbase, location, "*")): if os.path.isdir(mapset): self.listOfMapsets.append(os.path.basename(mapset)) + self.lbmapsets.Clear() self.lbmapsets.InsertItems(self.listOfMapsets,0) + return self.listOfMapsets - def OnSelectLocation(self,event): + def OnSelectLocation(self, event): """Location selected""" if self.lblocations.GetSelection() > -1: - self.UpdateMapsets(os.path.join( - self.gisdbase,self.listOfLocations[self.lblocations.GetSelection()])) + self.UpdateMapsets(os.path.join(self.gisdbase, + self.listOfLocations[self.lblocations.GetSelection()])) else: self.listOfMapsets = [] + self.lbmapsets.Clear() - self.lbmapsets.InsertItems(self.listOfMapsets,0) - + self.lbmapsets.InsertItems(self.listOfMapsets, 0) + self.lbmapsets.SetSelection(0) + def OnSelectMapset(self,event): """Mapset selected""" - #self.bstart.Enable(True) - pass + # self.bstart.Enable(True) + event.Skip() def OnSetDatabase(self,event): """Database set""" self.gisdbase = self.tgisdbase.GetValue() + self.UpdateLocations(self.gisdbase) self.lblocations.Clear() self.lblocations.InsertItems(self.listOfLocations,0) - if self.listOfLocations != []: self.lblocations.SetSelection(0) + + if self.listOfLocations != []: + self.lblocations.SetSelection(0) + self.OnSelectLocation(event) def OnBrowse(self, event): @@ -515,7 +547,7 @@ grassdata = None dlg = wx.DirDialog(self, "Choose a GRASS directory:", - style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON) + style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON) if dlg.ShowModal() == wx.ID_OK: self.gisdbase = dlg.GetPath() self.tgisdbase.SetValue(self.gisdbase) @@ -524,6 +556,7 @@ self.OnSetDatabase(event) def OnKeyPressedInDbase(self,event): + """GIS data directory changed""" if wx.WXK_RETURN == event.KeyCode: self.OnSetDatabase(event) else: @@ -558,24 +591,64 @@ return True def OnStart(self, event): - print "g.gisenv set=GISDBASE='%s';" % self.tgisdbase.GetValue() - print "g.gisenv set=LOCATION_NAME='%s';" % self.listOfLocations[self.lblocations.GetSelection()] - print "g.gisenv set=MAPSET='%s';" % self.listOfMapsets[self.lbmapsets.GetSelection()] + """'Start GRASS' button clicked""" + gcmd.Command(["g.gisenv", + "set=GISDBASE=%s" % self.tgisdbase.GetValue()]) + gcmd.Command(["g.gisenv", + "set=LOCATION_NAME=%s" % self.listOfLocations[self.lblocations.GetSelection()]]) + gcmd.Command(["g.gisenv", + "set=MAPSET=%s" % self.listOfMapsets[self.lbmapsets.GetSelection()]]) + self.Destroy() + sys.exit(0) def OnExit(self, event): """'Exit' button clicked""" self.Destroy() + sys.exit (2) def OnHelp(self, event): """'Help' button clicked""" - wx.MessageBox("Help not yet implemented") + file=os.path.join(self.gisbase, "docs", "html", "helptext.html") + + helpFrame = HelpWindow(parent=self, id=wx.ID_ANY, + title=_("GRASS Quickstart"), + size=(640, 480), + file=file) + helpFrame.Show(True) + event.Skip() def OnCloseWindow(self, event): """Close window event""" event.Skip() + sys.exit(2) +class HelpWindow(wx.Frame): + """GRASS Quickstart help window""" + def __init__(self, parent, id, title, size, file): + + wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size) + + sizer = wx.BoxSizer(wx.VERTICAL) + + # text + helpFrame = wx.html.HtmlWindow(parent=self, id=wx.ID_ANY) + helpFrame.SetStandardFonts (size = 10) + helpFrame.SetBorders(10) + wx.InitAllImageHandlers() + + helpFrame.LoadFile(file) + self.Ok = True + + sizer.Add(item=helpFrame, proportion=1, flag=wx.EXPAND) + + self.SetAutoLayout(True) + self.SetSizer(sizer) + # sizer.Fit(self) + # sizer.SetSizeHints(self) + self.Layout() + class StartUp(wx.App): """Start-up application""" Copied: trunk/grassaddons/gui/gui_modules/location_wizard.py (from rev 1148, trunk/grassaddons/gui/location_wizard.py) =================================================================== --- trunk/grassaddons/gui/gui_modules/location_wizard.py (rev 0) +++ trunk/grassaddons/gui/gui_modules/location_wizard.py 2007-10-20 09:51:46 UTC (rev 1149) @@ -0,0 +1,1863 @@ +""" +MODULE: location_wizard.py + +CLASSES: + * TitledPage + * DatabasePage + * CoordinateSystemPage + * ProjectionsPage + * ProjTypePage + * DatumPage + * EllipsePage + * GeoreferencedFilePage + * EPSGPage + * CustomPage + * SummaryPage + * RegionDef + * GWizard + +PURPOSE: Create a new GRASS location. User can choose from multiple methods + +AUTHORS: The GRASS Development Team + Michael Barton + Jachym Cepicky + +COPYRIGHT: (C) 2006-2007 by the GRASS Development Team + This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" +import os +import shutil +import re +import string +import sys + +import wx +import wx.lib.mixins.listctrl as listmix +import wx.lib.rcsizer as rcs +import wx.wizard as wiz + +import gui_modules +import gui_modules.gcmd as gcmd +try: + import subprocess +except: + from compat import subprocess + + +gmpath = gui_modules.__path__[0] +sys.path.append(gmpath) + + +global coordsys +global north +global south +global east +global west +global resolution +global wizerror + +coordsys = '' +north = '' +south = '' +east = '' +west = '' +resolution = '' + +class TitledPage(wiz.WizardPageSimple): + """ + Class to make wizard pages. Generic methods to make + labels, text entries, and buttons. + """ + def __init__(self, parent, title): + wiz.WizardPageSimple.__init__(self, parent) + + self.title = wx.StaticText(self,-1,title) + self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD)) + + self.sizer = rcs.RowColSizer() + tmpsizer = wx.BoxSizer(wx.VERTICAL) + + tmpsizer.Add(self.title, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + tmpsizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) + tmpsizer.Add(self.sizer, wx.EXPAND) + + self.SetSizer(tmpsizer) + self.SetAutoLayout(True) + + def MakeRLabel(self, text=""): + """Make right-aligned label""" + try: + if text[-1] != " ": + text += " " + except: + pass + return wx.StaticText(self, -1, text, style=wx.ALIGN_RIGHT) + + def MakeLLabel(self, text=""): + """Make left-aligned label""" + try: + if text[-1] != " ": + text += " " + except: + pass + return wx.StaticText(self, -1, text, style=wx.ALIGN_LEFT) + + def MakeTextCtrl(self,text='', size=(100,-1)): + """Generic text control""" + return wx.TextCtrl(self,-1, text, size=size) + + def MakeButton(self,text, size=(75,25)): + """Generic button""" + return wx.Button(self, -1, text, + style=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, + size=size) + + +class DatabasePage(TitledPage): + """ + Wizard page for setting GIS data directory and location name + """ + def __init__(self, wizard, parent, grassdatabase): + TitledPage.__init__(self, wizard, "Define GRASS database and new Location Name") + + self.grassdatabase = grassdatabase + self.location = '' + + # buttons + self.bbrowse = self.MakeButton("Browse...") + + # text controls + self.tgisdbase = self.MakeTextCtrl(grassdatabase, size=(300, -1)) + self.tlocation = self.MakeTextCtrl("newLocation", size=(300, -1)) + + # layout + self.sizer.Add(self.MakeRLabel("GIS Data Directory:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, + row=1, col=2) + self.sizer.Add(self.tgisdbase,0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, + row=1, col=3) + self.sizer.Add(self.bbrowse, 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, + row=1, col=4) + # + self.sizer.Add(self.MakeRLabel("Project Location"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, + row=2, col=2) + self.sizer.Add(self.tlocation,0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, + row=2, col=3) + self.sizer.Add(self.MakeRLabel("(projection/coordinate system)"), 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, + row=2, col=4) + + # bindings + self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged) + + def OnBrowse(self, event): + dlg = wx.DirDialog(self, "Choose GRASS data directory:", os.getcwd(),wx.DD_DEFAULT_STYLE) + if dlg.ShowModal() == wx.ID_OK: + self.grassdatabase = dlg.GetPath() + self.tgisdbase.SetValue(self.grassdatabase) + dlg.Destroy() + + def onPageChanging(self,event=None): + if os.path.isdir(os.path.join(self.tgisdbase.GetValue(),self.tlocation.GetValue())): + dlg = wx.MessageDialog(self, "Could not create new location: <%s> directory exists "\ + % str(self.tlocation.GetValue()),"Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + event.Veto() + return + + if not self.tlocation.GetValue(): + dlg = wx.MessageDialog(self, "Could not create new location: location not set "\ + ,"Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + event.Veto() + return + + self.location = self.tlocation.GetValue() + self.grassdatabase = self.tgisdbase.GetValue() + + def OnPageChanged(self,event=None): + self.grassdatabase = self.tgisdbase.GetValue() + self.location = self.tlocation.GetValue() + + +class CoordinateSystemPage(TitledPage): + """ + Wizard page for choosing method for location creation + """ + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Choose method for creating a new location") + + self.parent = parent + global coordsys + + # toggles + self.radio1 = wx.RadioButton( self, -1, " Select coordinate system " , style = wx.RB_GROUP) + self.radio2 = wx.RadioButton( self, -1, " Select EPSG code for coordinate system " ) + self.radio3 = wx.RadioButton( self, -1, " Use coordinate system of selected georeferenced file " ) + self.radio4 = wx.RadioButton( self, -1, " Create custom PROJ.4 parameters string for coordinate system " ) + self.radio5 = wx.RadioButton( self, -1, " Create arbitrary non-earth coordinate system (XY)" ) + + # layout + self.sizer.Add(self.radio1, 0, wx.ALIGN_LEFT, row=1, col=2) + self.sizer.Add(self.radio2, 0, wx.ALIGN_LEFT, row=2, col=2) + self.sizer.Add(self.radio3, 0, wx.ALIGN_LEFT, row=3, col=2) + self.sizer.Add(self.radio4, 0, wx.ALIGN_LEFT, row=4, col=2) + self.sizer.Add(self.radio5, 0, wx.ALIGN_LEFT, row=5, col=2) + + # bindings + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio1.GetId()) + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio2.GetId()) + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio3.GetId()) + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio4.GetId()) + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio5.GetId()) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + + def OnPageChange(self,event=None): + global coordsys + if event.GetDirection() and not coordsys: + wx.MessageBox('You must select a coordinate system') + event.Veto() + + def SetVal(self,event): + global coordsys + if event.GetId() == self.radio1.GetId(): + coordsys = "proj" + self.SetNext(self.parent.projpage) + self.parent.sumpage.SetPrev(self.parent.datumpage) + elif event.GetId() == self.radio2.GetId(): + coordsys = "epsg" + self.SetNext(self.parent.epsgpage) + self.parent.sumpage.SetPrev(self.parent.epsgpage) + elif event.GetId() == self.radio3.GetId(): + coordsys = "file" + self.SetNext(self.parent.filepage) + self.parent.sumpage.SetPrev(self.parent.filepage) + elif event.GetId() == self.radio4.GetId(): + coordsys = "custom" + self.SetNext(self.parent.custompage) + self.parent.sumpage.SetPrev(self.parent.custompage) + elif event.GetId() == self.radio5.GetId(): + coordsys = "xy" + self.SetNext(self.parent.sumpage) + set.parent.sumpage.SetPrev(self.parent.csystemspage) + +class ProjectionsPage(TitledPage): + """ + Wizard page for selecting projection (select coordinate system option) + """ + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Choose projection") + + self.parent = parent + self.proj = '' + self.projdesc = '' + + # text input + self.tproj = self.MakeTextCtrl("", size=(200,-1)) + + # search box + self.searchb = wx.SearchCtrl(self, size=(200,-1), + style=wx.TE_PROCESS_ENTER) + + self.projlist = wx.ListCtrl(self, id=wx.ID_ANY, + size=(650,275), + style=wx.LC_REPORT | + wx.LC_HRULES | + wx.EXPAND) + self.projlist.InsertColumn(0, 'Code') + self.projlist.InsertColumn(1, 'Description') + self.projlist.SetColumnWidth(0, 100) + self.projlist.SetColumnWidth(1, 500) + + # layout + self.sizer.Add(self.MakeRLabel("Projection code:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=2) + self.sizer.Add(self.tproj, 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=3) + + self.sizer.Add(self.MakeRLabel("Search in projection description"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2, col=2) + self.sizer.Add(self.searchb, 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2, col=3) + + self.sizer.Add(self.projlist, + wx.EXPAND | + wx.ALIGN_LEFT | + wx.ALL, 5, row=3, col=1, colspan=4) + + # events + self.Bind(wx.EVT_TEXT, self.OnText, self.tproj) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.projlist) + self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + + self._onBrowseProj(None, None) + + def OnPageChange(self,event): + if event.GetDirection() and self.proj not in self.parent.projections: + wx.MessageBox('You must select a valid projection in order to continue') + event.Veto() + if self.proj == 'utm': + self.parent.projtypepage.text_utm.SetEditable(True) + self.parent.projtypepage.hemischoices = ['north','south'] + else: + self.parent.projtypepage.text_utm.SetValue('') + self.parent.projtypepage.text_utm.SetEditable(False) + self.parent.projtypepage.hemischoices = [] + + def OnText(self, event): + self.proj = event.GetString() + if self.proj in self.parent.projections: + self.projdesc = self.parent.projections[self.proj] + + def OnDoSearch(self,event): + str = self.searchb.GetValue() + listItem = self.projlist.GetColumn(1) + + for i in range(self.projlist.GetItemCount()): + listItem = self.projlist.GetItem(i,1) + if listItem.GetText().find(str) > -1: + self.proj = self.projlist.GetItem(i, 0).GetText() + self.tproj.SetValue(self.proj) + break + + self._onBrowseProj(None,str) + + def OnItemSelected(self,event): + index = event.m_itemIndex + item = event.GetItem() + + self.proj = item.GetText() + self.projdesc = self.projlist.GetItem(index, 1).GetText() + self.tproj.SetValue(self.proj) + + def _onBrowseProj(self,event,search=None): + try: + projlist = self.parent.projections.items() + projlist.sort() + self.projlist.DeleteAllItems() + for proj,desc in projlist: + entry = self.projlist.GetItemCount() + if search and (proj.lower().find(search.lower()) > -1 or \ + desc.lower().find(search.lower()) > -1) or \ + not search: + index = self.projlist.InsertStringItem(entry,proj) + self.projlist.SetStringItem(index,1,desc) + + self.projlist.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.projlist.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.projlist.SendSizeEvent() + + except StandardError, e: + dlg = wx.MessageDialog(self, "Could not read projections list: %s " % e, + "Could not read projections", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + +class ProjTypePage(TitledPage): + """ + Wizard page for selecting method of setting coordinate system parameters + (select coordinate system option) + """ + + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Choose method of specifying georeferencing parameters") + global coordsys + + self.utmzone = '' + self.utmhemisphere = '' + self.hemischoices = ["north","south"] + self.parent = parent + + self.radio1 = wx.RadioButton( self, -1, " Select datum with associated ellipsoid", style = wx.RB_GROUP ) + self.radio2 = wx.RadioButton( self, -1, " Select ellipsoid" ) + self.title_utm = self.MakeLLabel("Set zone for UTM projection") + self.text_utm = self.MakeTextCtrl(size=(100,-1)) + self.label_utm = self.MakeRLabel("Zone: ") + self.hemisphere = wx.Choice(self, -1, (100, 50), choices = self.hemischoices) + self.label_hemisphere = self.MakeRLabel("Hemisphere for zone: ") + + # layout + self.sizer.Add(self.radio1, 0, wx.ALIGN_LEFT, row=1, col=2) + self.sizer.Add(self.radio2, 0, wx.ALIGN_LEFT, row=2, col=2) + self.sizer.Add(self.title_utm, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=4,col=2) + self.sizer.Add(self.label_utm, 0, wx.ALIGN_RIGHT|wx.ALL, 5, row=5,col=1) + self.sizer.Add(self.text_utm, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=5,col=2) + self.sizer.Add(self.label_hemisphere, 0, wx.ALIGN_RIGHT|wx.ALL, 5, row=6,col=1) + self.sizer.Add(self.hemisphere, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=6,col=2) + + self.title_utm.Hide() + self.text_utm.Hide() + self.label_utm.Hide() + self.hemisphere.Hide() + self.label_hemisphere.Hide() + + # bindings + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio1.GetId()) + self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio2.GetId()) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) + + def OnPageChange(self,event=None): + if event.GetDirection() and self.parent.projpage.proj == 'utm' and self.utmzone == '': + wx.MessageBox('You must set a zone for a UTM projection') + event.Veto() + self.title_utm.Hide() + self.text_utm.Hide() + self.label_utm.Hide() + self.hemisphere.Hide() + self.label_hemisphere.Hide() + + def OnEnterPage(self,event): + if self.parent.projpage.proj == 'utm': + self.title_utm.Show() + self.text_utm.Show() + self.label_utm.Show() + self.hemisphere.Show() + self.label_hemisphere.Show() + + self.Bind(wx.EVT_CHOICE, self.OnHemisphere, self.hemisphere) + self.Bind(wx.EVT_TEXT, self.GetUTM, self.text_utm) + + def SetVal(self, event): + global coordsys + if event.GetId() == self.radio1.GetId(): + self.SetNext(self.parent.datumpage) + self.parent.sumpage.SetPrev(self.parent.datumpage) + elif event.GetId() == self.radio2.GetId(): + self.SetNext(self.parent.ellipsepage) + self.parent.sumpage.SetPrev(self.parent.ellipsepage) + + def GetUTM(self, event): + self.utmzone = event.GetString() + + def OnHemisphere(self, event): + self.utmhemisphere = event.GetString() + + +class DatumPage(TitledPage): + """ + Wizard page for selecting datum (with associated ellipsoid) + and datum transformation parameters (select coordinate system option) + """ + + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Specify geodetic datum") + + self.parent = parent + self.datum = '' + self.datumdesc = '' + self.ellipsoid = '' + self.datumparams = '' + self.transform = '' + self.transregion = '' + self.transparams = '' + self.hastransform = False + self.proj4params = '' + + # text input + self.tdatum = self.MakeTextCtrl("", size=(200,-1)) + self.ttrans = self.MakeTextCtrl("", size=(200,-1)) + + # search box + self.searchb = wx.SearchCtrl(self, size=(200,-1), + style=wx.TE_PROCESS_ENTER) + + # button +# self.bupdate = self.MakeButton("Update trans. parms.", +# size=(-1,-1)) + + # create list control for datum/elipsoid list + self.datumlist = wx.ListCtrl(self, id=wx.ID_ANY, + size=(650,150), + style=wx.LC_REPORT| + wx.LC_HRULES| + wx.EXPAND) + self.datumlist.InsertColumn(0, 'Code') + self.datumlist.InsertColumn(1, 'Description') + self.datumlist.InsertColumn(2, 'Ellipsoid') + self.datumlist.SetColumnWidth(0, 100) + self.datumlist.SetColumnWidth(1, 250) + self.datumlist.SetColumnWidth(2, 100) + + # create list control for datum transformation parameters list + self.transformlist = wx.ListCtrl(self, id=wx.ID_ANY, + size=(650,125), + style=wx.LC_REPORT | + wx.LC_HRULES | + wx.EXPAND) + self.transformlist.InsertColumn(0, 'Code') + self.transformlist.InsertColumn(1, 'Datum') + self.transformlist.InsertColumn(2, 'Description') + self.transformlist.SetColumnWidth(0, 50) + self.transformlist.SetColumnWidth(1, 125) + self.transformlist.SetColumnWidth(2, 250) + + # layout + self.sizer.Add(self.MakeRLabel("Datum code:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, col=1, row=1) + self.sizer.Add(self.tdatum, 0 , + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=2) +# self.sizer.Add(self.bupdate, 0 , +# wx.ALIGN_LEFT | +# wx.ALIGN_CENTER_VERTICAL | +# wx.ALL, 5, row=1, col=3) + self.sizer.Add(self.MakeRLabel("Search in description:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, col=1, row=2) + self.sizer.Add(self.searchb, 0 , + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2, col=2) + + self.sizer.Add(self.datumlist, + wx.EXPAND | + wx.ALIGN_LEFT | + wx.ALL, 5, row=3, col=1, colspan=4) + + self.sizer.Add(self.MakeRLabel("Transformation parameters:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, col=1, row=5) + self.sizer.Add(self.ttrans, 0 , + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=5, col=2) + + self.sizer.Add(self.transformlist, + wx.EXPAND | + wx.ALIGN_LEFT | + wx.ALL, 5, row=6, col=1, colspan=4) + + # events + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected, self.datumlist) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnTransformSelected, self.transformlist) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) +# self.bupdate.Bind(wx.EVT_BUTTON, self._onBrowseParams) + self.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) + self.Bind(wx.EVT_TEXT, self.OnDText, self.tdatum) + + self._onBrowseDatums(None,None) + + def OnPageChange(self,event): + self.proj4params = '' + if event.GetDirection() and self.datum not in self.parent.datums: + wx.MessageBox('You must select a valid datum in order to continue') + event.Veto() +# if self.hastransform == True and self.transform == '': +# wx.MessageBox('You must select a datum transform') +# event.Veto() + self.GetNext().SetPrev(self) + self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipsoid][1] + self.GetNext().SetPrev(self) + + def OnDText(self, event): + self.datum = event.GetString() + if self.datum in self.parent.datums: + self.datumdesc = self.parent.datums[self.datum][0] + self.ellipsoid = self.parent.datums[self.datum][1] + self.datumparams = self.parent.datums[self.datum][2] + + self._onBrowseParams(None,self.datum) + + def OnTText(self, event): + self.transform = event.GetString() + if self.transform in self.parent.transforms: + self.transdatum = self.parent.transforms[self.transform][0] + self.transregion = self.parent.transforms[self.transform][1] + self.transparams = self.parent.transforms[self.transform][2] + + def OnDoSearch(self,event): + str = self.searchb.GetValue() + listItem = self.datumlist.GetColumn(1) + + for i in range(self.datumlist.GetItemCount()): + listItem = self.datumlist.GetItem(i,1) + if listItem.GetText().find(str) > -1: + datum = self.datumlist.GetItem(i, 0) + self.tdatum.SetValue(datum.GetText()) + break + + self._onBrowseDatums(None,str) + + def OnTransformSelected(self,event): + index = event.m_itemIndex + item = event.GetItem() + + self.transform = item.GetText() + self.transdatum = self.parent.transforms[self.transform][0] + self.transregion = self.parent.transforms[self.transform][1] + self.transparams = self.parent.transforms[self.transform][2] + + self.ttrans.SetValue(str(self.transform)) + + def OnDatumSelected(self,event): + index = event.m_itemIndex + item = event.GetItem() + + self.datum = item.GetText() + self.datumdesc = self.parent.datums[self.datum][0] + self.ellipsoid = self.parent.datums[self.datum][1] + self.datumparams = self.parent.datums[self.datum][2] + + self.tdatum.SetValue(self.datum) + self._onBrowseParams(None, self.datum) + event.Skip() + + def _onBrowseParams(self, event=None, search=None): + search = self.datum.strip() + try: + self.transform = '' + self.transformlist.DeleteAllItems() + for item in self.parent.transforms: + transdatum = self.parent.transforms[item][0] + transregion = self.parent.transforms[item][1] + entry = self.transformlist.GetItemCount() + if (transdatum.lower() == search.lower()): + index = self.transformlist.InsertStringItem(entry,item) + self.transformlist.SetStringItem(index,1,transdatum) + self.transformlist.SetStringItem(index,2,transregion) + self.hastransform = True + + self.transformlist.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.transformlist.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.transformlist.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.transformlist.SendSizeEvent() + + except IOError, e: + self.transformlist.DeleteAllItems() + dlg = wx.MessageDialog(self, "Could not read datum params: %s " % e, + "Could not read file", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + def _onBrowseDatums(self,event,search=None): + try: + self.datum = '' + self.datumlist.DeleteAllItems() + + datumlist = self.parent.datums.items() + datumlist.sort() + for datum,info in datumlist: + datumdesc = info[0] + ellipse = info[1] + entry = self.datumlist.GetItemCount() + if search and (datum.lower().find(search.lower()) > -1 or\ + datumdesc.lower().find(search.lower()) > -1 or\ + ellipse.lower().find(search.lower()) > -1) or\ + not search: + index = self.datumlist.InsertStringItem(entry,datum) + self.datumlist.SetStringItem(index,1,datumdesc) + self.datumlist.SetStringItem(index,2,ellipse) + + self.datumlist.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.datumlist.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.datumlist.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.datumlist.SendSizeEvent() + + except IOError, e: + dlg = wx.MessageDialog(self, "Could not read datums: %s " % e, + "Could not read datums list", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +class EllipsePage(TitledPage): + """ + Wizard page for selecting ellipsoid (select coordinate system option) + """ + + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Specify ellipsoid") + + self.parent = parent + self.ellipse = '' + self.ellipsedesc = '' + self.ellipseparams = '' + self.proj4params = '' + + # text input + self.tellipse = self.MakeTextCtrl("", size=(200,-1)) + + # search box + self.searchb = wx.SearchCtrl(self, size=(200,-1), + style=wx.TE_PROCESS_ENTER) + + # create list control for ellipse list + self.ellipselist = wx.ListCtrl(self, id=wx.ID_ANY, + size=(650,250), + style=wx.LC_REPORT| + wx.LC_HRULES| + wx.EXPAND) + self.ellipselist.InsertColumn(0, 'Code') + self.ellipselist.InsertColumn(1, 'Description') + self.ellipselist.SetColumnWidth(0, 100) + self.ellipselist.SetColumnWidth(1, 250) + + # layout + self.sizer.Add(self.MakeRLabel("Ellipse code:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=1) + self.sizer.Add(self.tellipse, 0 , + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=2) + self.sizer.Add(self.MakeRLabel("Search in description:"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2, col=1) + self.sizer.Add(self.searchb, 0 , + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2, col=2) + + self.sizer.Add(self.ellipselist, 0 , + wx.EXPAND | + wx.ALIGN_LEFT | + wx.ALL, 5, row=3, col=1, colspan=3) + + # events + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnEllipseSelected, self.ellipselist) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) + self.Bind(wx.EVT_TEXT, self.OnText, self.tellipse) + + self._onBrowseEllipse(None,None) + + def OnPageChange(self,event): + self.proj4params = '' + if event.GetDirection() and self.ellipse not in self.parent.ellipsoids: + wx.MessageBox('You must select a valid ellipsoid in order to continue') + event.Veto() + self.GetNext().SetPrev(self) + self.parent.datumpage.datumparams = '' + self.parent.datumpage.transparams = '' + self.GetNext().SetPrev(self) + + def OnText(self, event): + self.ellipse = event.GetString() + if self.ellipse in self.parent.ellipsoids: + self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0] + self.ellipseparams = self.parent.ellipsoids[self.ellipse][1] + + def OnDoSearch(self,event): + str = self.searchb.GetValue() + listItem = self.ellipselist.GetColumn(1) + + for i in range(self.ellipselist.GetItemCount()): + item = self.ellipselist.GetItem(i,0) + itemdesc = self.ellipselist.GetItem(i,1) + if itemdesc.GetText().find(str) > -1: + self.ellipse = item.GetText() + self.tellipse.SetValue(self.ellipse) + self.ellipselist.EnsureVisible(long(self.ellipselist.GetItem(i))) + break + + self._onBrowseEllipse(None,str) + + def OnEllipseSelected(self,event): + index = event.m_itemIndex + item = event.GetItem() + + self.ellipse = item.GetText() + self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0] + self.ellipseparams = self.parent.ellipsoids[self.ellipse][1] + + self.tellipse.SetValue(self.ellipse) + self._onBrowseEllipse(None) + + def _onBrowseEllipse(self,event,search=None): + try: + ellipselist = self.parent.ellipsoids.items() + ellipselist.sort() + self.ellipselist.DeleteAllItems() + for ellipsoid,info in ellipselist: + desc = info[0] + entry = self.ellipselist.GetItemCount() + if search and (ellipsoid.lower().find(search.lower()) > -1 or \ + desc.lower().find(search.lower()) > -1) or \ + not search: + index = self.ellipselist.InsertStringItem(entry,ellipsoid) + self.ellipselist.SetStringItem(index,1,desc) + + self.ellipselist.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.ellipselist.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.ellipselist.SendSizeEvent() + except IOError, e: + dlg = wx.MessageDialog(self, "Could not read ellipse information: %s " % e, + "Problem parsing ellipse list", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +class GeoreferencedFilePage(TitledPage): + """ + Wizard page for selecting georeferenced file to use + for setting coordinate system parameters + """ + + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Select georeferenced file") + + self.georeffile = '' + + # create controls + self.lfile= wx.StaticText(self, -1, "Georeferenced file: ", + style=wx.ALIGN_RIGHT) + self.tfile = wx.TextCtrl(self,-1, "", size=(300,-1)) + self.bbrowse = wx.Button(self, -1, "Browse...") + + # do layout + self.sizer.Add(self.lfile, 0, wx.ALIGN_RIGHT | + wx.ALIGN_CENTRE_VERTICAL | + wx.ALL, 5, row=1, col=2) + self.sizer.Add(self.tfile, 0, wx.ALIGN_LEFT | + wx.ALIGN_CENTRE_VERTICAL | + wx.ALL, 5, row=1, col=3) + self.sizer.Add(self.bbrowse, 0, wx.ALIGN_LEFT | + wx.ALL, 5, row=1, col=4) + + self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) + self.Bind(wx.EVT_TEXT, self.OnText, self.tfile) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + + def OnPageChange(self, event): + if event.GetDirection() and self.georeffile == '': + wx.MessageBox('You must select a georeferenced file in order to continue') + event.Veto() + self.GetNext().SetPrev(self) + + def OnText(self, event): + self.georeffile = event.GetString() + + def OnBrowse(self, event): + + dlg = wx.FileDialog(self, "Choose a georeferenced file:", os.getcwd(), "", "*.*", wx.OPEN) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.tfile.SetValue(path) + dlg.Destroy() + + def OnCreate(self, event): + pass + + +class EPSGPage(TitledPage): + """ + Wizard page for selecting EPSG code for + setting coordinate system parameters + """ + + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Choose EPSG Code") + self.parent = parent + self.epsgcode = '' + self.epsgdesc = '' + + + # labels + self.lfile= wx.StaticText(self, -1, "Path to the EPSG-codes file: ", + style=wx.ALIGN_RIGHT) + self.lcode= wx.StaticText(self, -1, "EPSG code: ", + style=wx.ALIGN_RIGHT) + self.lsearch= wx.StaticText(self, -1, "Search in code description: ", + style=wx.ALIGN_RIGHT) + + # text input + epsgdir = os.path.join(os.environ["GRASS_PROJSHARE"], 'epsg') + self.tfile = wx.TextCtrl(self,-1, epsgdir, size=(200,-1)) + self.tcode = wx.TextCtrl(self,-1, "", size=(200,-1)) + + # buttons + self.bbrowse = wx.Button(self, -1, "Browse...") + self.bbcodes = wx.Button(self, -1, "Browse Codes...") + + # search box + self.searchb = wx.SearchCtrl(self, size=(200,-1), style=wx.TE_PROCESS_ENTER) + + self.epsglist = wx.ListCtrl(self, id=wx.ID_ANY, + size=(650,275), + style=wx.LC_REPORT| + wx.LC_HRULES| + wx.EXPAND) + self.epsglist.InsertColumn(0, 'Code', wx.LIST_FORMAT_CENTRE) + self.epsglist.InsertColumn(1, 'Description', wx.LIST_FORMAT_LEFT) + self.epsglist.InsertColumn(2, 'Parameters', wx.LIST_FORMAT_LEFT) + self.epsglist.SetColumnWidth(0, 50) + self.epsglist.SetColumnWidth(1, 300) + self.epsglist.SetColumnWidth(2, 325) + + # layout + self.sizer.Add(self.lfile, 0, wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, col=1, row=1) + self.sizer.Add(self.tfile, 0, wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=2) + self.sizer.Add(self.bbrowse, 0, wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=1, col=3) + + self.sizer.Add(self.lcode, 0, wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, col=1, row=2) + self.sizer.Add(self.tcode, 0, wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2, col=2) + + self.sizer.Add(self.lsearch, 0, wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, col=1, row=3) + self.sizer.Add(self.searchb, 0, wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=3, col=2) + self.sizer.Add(self.bbcodes, 0 , wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=3, col=3) + + self.sizer.Add(self.epsglist, wx.ALIGN_LEFT|wx.EXPAND, 0, row=4, col=1, colspan=5) + + # events + self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse) + self.Bind(wx.EVT_BUTTON, self.OnBrowseCodes, self.bbcodes) + self.Bind(wx.EVT_TEXT, self.OnText, self.tcode) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.epsglist) + self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + + def OnPageChange(self, event): + if event.GetDirection() and not self.epsgcode: + wx.MessageBox('You must select an EPSG code') + event.Veto() + self.GetNext().SetPrev(self) + + def OnText(self, event): + self.epsgcode = event.GetString() + + def OnDoSearch(self,event): + str = self.searchb.GetValue() + listItem = self.epsglist.GetColumn(1) + + for i in range(self.epsglist.GetItemCount()): + listItem = self.epsglist.GetItem(i,1) + if listItem.GetText().find(str) > -1: + self.epsgcode = self.epsglist.GetItem(i, 0) + self.tcode.SetValue(self.epsgcode.GetText()) + break + + self.OnBrowseCodes(None,str) + + def OnBrowse(self, event): + + dlg = wx.FileDialog(self, "Choose EPSG codes file:", + "/", "", "*.*", wx.OPEN) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.tfile.SetValue(path) + dlg.Destroy() + + def OnItemSelected(self,event): + index = event.m_itemIndex + item = event.GetItem() + + self.epsgcode = item.GetText() + self.epsgdesc = self.epsglist.GetItem(index, 1).GetText() + self.tcode.SetValue(str(self.epsgcode)) + + def OnBrowseCodes(self,event,search=None): + try: + self.epsglist.DeleteAllItems() + f = open(self.tfile.GetValue(),"r") + i=1 + j = 0 + descr = None + code = None + params = "" + #self.epsglist.ClearAll() + for line in f.readlines(): + line = line.strip() + if line.find("#") == 0: + descr = line[1:].strip() + elif line.find("<") == 0: + code = line.split(" ")[0] + for par in line.split(" ")[1:]: + params += par + " " + code = code[1:-1] + if code == None: code = 'no code' + if descr == None: descr = 'no description' + if params == None: params = 'no parameters' + if i%2 == 0: + if search and descr.lower().find(search.lower()) > -1 or\ + not search: + index = self.epsglist.InsertStringItem(j, code) + self.epsglist.SetStringItem(index, 1, descr) + self.epsglist.SetStringItem(index, 2, params) + j += 1 + # reset + descr = None; code = None; params = "" +# if i%2 == 0: +# self.epsglist.SetItemBackgroundColour(i, "grey") + i += 1 + f.close() + self.epsglist.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.epsglist.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.SendSizeEvent() + except StandardError, e: + dlg = wx.MessageDialog(self, "Could not read EPGS codes: %s " % e, + "Could not read file", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +class CustomPage(TitledPage): + """ + Wizard page for entering custom PROJ.4 string + for setting coordinate system parameters + """ + + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Choose method of specifying georeferencing parameters") + global coordsys + self.customstring = '' + self.parent = parent + + self.text_proj4string = self.MakeTextCtrl(size=(400,100)) + self.label_proj4string = self.MakeRLabel("Enter PROJ.4 parameters string: ") + self.sizer.Add(self.label_proj4string, 0, wx.ALIGN_RIGHT|wx.ALL, 5, row=5,col=1) + self.sizer.Add(self.text_proj4string, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=5,col=2) + + self.Bind(wx.EVT_TEXT, self.GetProjstring, self.text_proj4string) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) + + def OnPageChange(self, event): + if event.GetDirection() and not self.customstring: + wx.MessageBox('You must enter a PROJ.4 string') + event.Veto() + self.GetNext().SetPrev(self) + + def GetProjstring(self, event): + self.customstring = event.GetString() + + +class SummaryPage(TitledPage): + """ + Shows summary result of choosing coordinate system parameters + prior to creating location + """ + def __init__(self, wizard, parent): + TitledPage.__init__(self, wizard, "Summary") + + self.parent = parent + + # labels + self.ldatabase = self.MakeLLabel("") + self.llocation = self.MakeLLabel("") + self.lprojection = self.MakeLLabel("") + + self.lprojection.Wrap(500) + + self.sizer.Add(self.MakeRLabel("GRASS database:"), 1, flag=wx.ALIGN_RIGHT|wx.ALL, border=5, row=1, col=0) + self.sizer.Add(self.ldatabase, 1, flag=wx.ALIGN_LEFT|wx.ALL, border=5, row=1, col=1) + self.sizer.Add(self.MakeRLabel("Location name:"), 1, flag=wx.ALIGN_RIGHT|wx.ALL, border=5, row=2, col=0) + self.sizer.Add(self.llocation, 1, flag=wx.ALIGN_LEFT|wx.ALL, border=5, row=2, col=1) + self.sizer.Add(wx.StaticLine(self, -1), 0, wx.ALIGN_RIGHT|wx.EXPAND|wx.ALL, 0, row=3, col=0, colspan=2) + self.sizer.Add((10,10), 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, border=5, row=4, col=0) + self.sizer.Add(self.MakeRLabel("Projection: "), 1, flag=wx.ALIGN_RIGHT|wx.ALL, border=5, row=5, col=0) + self.sizer.Add(self.lprojection, 1, flag=wx.ALIGN_LEFT|wx.ALL, border=5, row=5, col=1) + self.sizer.Add((10,20), 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, border=5, row=6, col=0) + self.sizer.Add(self.MakeLLabel("You can set the default extents and resolution after creating new location"), \ + 1, flag=wx.ALIGN_CENTRE|wx.ALL, border=5, row=7, col=0, colspan=2) + self.sizer.Add(self.MakeLLabel("or you can set them during a working session."), \ + 1, flag=wx.ALIGN_CENTRE|wx.ALL, border=5, row=8, col=0, colspan=2) + + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChange) + + def OnPageChange(self,event): + """ + Insert values into text controls for summary of location creation options + """ + + database = self.parent.startpage.grassdatabase + location = self.parent.startpage.location + + global coordsys + if not coordsys: + coordsys = 0 + + projection = self.parent.projpage.proj + projdesc = self.parent.projpage.projdesc + utmzone = self.parent.projtypepage.utmzone + utmhemisphere = self.parent.projtypepage.utmhemisphere + ellipse = self.parent.ellipsepage.ellipse + ellipsedesc = self.parent.ellipsepage.ellipsedesc + datum = self.parent.datumpage.datum + datumdesc = self.parent.datumpage.datumdesc + ellipsoid = self.parent.datumpage.ellipsoid + datumparams = self.parent.datumpage.datumparams + transform = self.parent.datumpage.transform + transregion = self.parent.datumpage.transregion + transparams = self.parent.datumpage.transparams + + self.ldatabase.SetLabel(str(database)) + self.llocation.SetLabel(str(location)) + label = '' + if coordsys == 'epsg': + label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode,self.parent.epsgpage.epsgdesc) + self.lprojection.SetLabel(label) + elif coordsys == 'file': + label = 'matches file %s' % self.parent.filepage.georeffile + self.lprojection.SetLabel(label) + elif coordsys == 'proj': + label = ('%s, %s%s' % (projdesc, datumdesc, ellipsedesc)) + self.lprojection.SetLabel(label) + elif coordsys == 'xy': + label = ('XY coordinate system. Not projected') + self.lprojection.SetLabel(label) + elif coordsys == 'custom': + label = ('%s' % self.parent.custompage.customstring) + self.lprojection.SetLabel(label) + +class RegionDef(wx.Frame): + """ + Page for setting default region extents and resolution + """ + + def __init__(self,parent,id=wx.ID_ANY, title="Set default region values", location=None): + wx.Frame.__init__(self, parent, id, title, size=(650,300)) + + self.parent = parent + self.location = location + + # inputs + self.ttop = self.MakeTextCtrl("1", size=(150, -1)) + self.tbottom = self.MakeTextCtrl("0", size=(150, -1)) + self.tleft = self.MakeTextCtrl("0", size=(150, -1)) + self.tright = self.MakeTextCtrl("1", size=(150, -1)) + self.tres = self.MakeTextCtrl("1", size=(150, -1)) + + self.north = 1.0 + self.south = 0.0 + self.east = 1.0 + self.west = 0.0 + self.res = 1.0 + + # labels + self.lmessage = wx.StaticText(self,-1, "", size=(300,50)) + + # buttons + self.bset = self.MakeButton("Set coordinates", size=(150,-1)) + self.bcancel = self.MakeButton("Cancel", size=(150,-1)) + + #Set current working environment to PERMANENT mapset in selected location in order to set default region (WIND) + envval = {} + cmdlist = ['g.gisenv'] + p = gcmd.Command(cmdlist) + if p.returncode == 0: + output = p.module_stdout.read().strip("'").split(';\n') + for line in output: + line = line.strip() + if '=' in line: key,val = line.split('=') + envval[key] = val + self.currlocation = envval['LOCATION_NAME'].strip("';") + self.currmapset = envval['MAPSET'].strip("';") + if self.currlocation == self.location and self.currmapset == 'PERMANENT': + pass + else: + cmdlist = ['g.mapset', 'location=%s' % self.location, 'mapset=PERMANENT'] + gcmd.Command(cmdlist) + else: + wx.MessageBox('A valid location must be selected') + return + + #Get current region settings + region = {} + cmdlist = ['g.region', '-gp'] + p = gcmd.Command(cmdlist) + if p.returncode == 0: + output = p.module_stdout.read().split('\n') + for line in output: + line = line.strip() + if '=' in line: key,val = line.split('=') + region[key] = float(val) + else: + wx.MessageBox('Invalid region') + return + + self.north = region['n'] + self.south = region['s'] + self.east = region['e'] + self.west = region['w'] + self.res = region['ewres'] + + # Insert current region settings into text controls + self.ttop.SetValue(str(self.north)) + self.tbottom.SetValue(str(self.south)) + self.tleft.SetValue(str(self.west)) + self.tright.SetValue(str(self.east)) + self.tres.SetValue(str(self.res)) + + # layout + self.sizer = rcs.RowColSizer() + + self.sizer.Add(self.MakeLLabel("Region extents and resolution:"), 3, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 10, row=0,col=0, colspan=2) + + self.sizer.Add(self.MakeRLabel("North"), 0, + wx.ALIGN_CENTER_HORIZONTAL | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 0, row=1,col=2) + self.sizer.Add(self.ttop, 0, + wx.ALIGN_CENTER_HORIZONTAL | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=2,col=2) + + self.sizer.Add(self.MakeRLabel("West"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 0, row=3,col=0) + self.sizer.Add(self.tleft, 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=3,col=1) + + self.sizer.Add(self.tright, 0, + wx.ALIGN_CENTER_HORIZONTAL | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=3,col=3) + self.sizer.Add(self.MakeRLabel("East"), 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 0, row=3,col=4) + + self.sizer.Add(self.tbottom, 0, + wx.ALIGN_CENTER_HORIZONTAL | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=4,col=2) + self.sizer.Add(self.MakeRLabel("South"), 0, + wx.ALIGN_CENTER_HORIZONTAL | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 0, row=5,col=2) + + self.sizer.Add(self.MakeRLabel("Resolution"), 0, + wx.ALIGN_RIGHT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=6,col=1) + self.sizer.Add(self.tres, 0, + wx.ALIGN_CENTER_HORIZONTAL | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=6,col=2) + + self.sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0, row=7, col=0, colspan=6) + + self.sizer.Add(self.bset, 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=8, col=3 ) + + self.sizer.Add(self.bcancel, 0, + wx.ALIGN_LEFT | + wx.ALIGN_CENTER_VERTICAL | + wx.ALL, 5, row=8, col=1 ) + + + self.SetSizer(self.sizer) + self.SetAutoLayout(True) + self.Layout() + + self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel) + self.Bind(wx.EVT_TEXT, self.OnNorth, self.ttop) + self.Bind(wx.EVT_TEXT, self.OnSouth, self.tbottom) + self.Bind(wx.EVT_TEXT, self.OnEast, self.tright) + self.Bind(wx.EVT_TEXT, self.OnWest, self.tleft) + self.Bind(wx.EVT_TEXT, self.OnRes, self.tres) + + def MakeRLabel(self, text=""): + """Make right-aligned label""" + try: + if text[-1] != " ": + text += " " + except: + pass + return wx.StaticText(self, -1, text, style=wx.ALIGN_RIGHT) + + def MakeLLabel(self, text=""): + """Make left-aligned label""" + try: + if text[-1] != " ": + text += " " + except: + pass + return wx.StaticText(self, -1, text, style=wx.ALIGN_LEFT) + + def MakeTextCtrl(self,text='', size=(100,-1)): + """Generic text control""" + return wx.TextCtrl(self,-1, text, size=size) + + def MakeButton(self,text, size=(75,25)): + """Generic button""" + return wx.Button(self, -1, text, + style=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, + size=size) + + def OnNorth(self,event): + self.north = event.GetString() + + def OnSouth(self, event): + self.south = event.GetString() + + def OnEast(self,event): + self.east = event.GetString() + + def OnWest(self,event): + self.west = event.GetString() + + def OnRes(self,event): + self.res = event.GetString() + + def OnSetButton(self,event=None): + cmdlist = ['g.region', '-sgpa', 'n=%s' % self.north, 's=%s' % self.south, \ + 'e=%s' % self.east, 'w=%s' % self.west, 'res=%s' % self.res] + p = gcmd.Command(cmdlist) + if p.returncode == 0: + output = p.module_stdout.read() + wx.MessageBox('New default region:\n%s' % output) + else: + wx.MessageBox('Setting default region failed\n%s %s' % \ + (p.module_stderr.read(),p.module_stdout.read())) + self.Destroy() + + def OnCancel(self, event): + self.Destroy() + +class GWizard: + """ + Start wizard here and finish wizard here + """ + + def __init__(self, parent, grassdatabase): + wizbmp = wx.Image(os.path.join(os.getenv("GISBASE"),"etc","wx","images","wizard.png"), wx.BITMAP_TYPE_PNG) + wizbmp.Rescale(250,600) + wizbmp = wizbmp.ConvertToBitmap() + + global coordsys + self.parent = parent + # get georeferencing information from tables in $GISBASE/etc + + # make projections dictionary + f = open(os.path.join(os.getenv("GISBASE"), "etc","projections"),"r") + self.projections = {} + for line in f.readlines(): + line = line.expandtabs(1) + line = line.strip() + if not line: + continue + if line == '' or line[0] == "#": + continue + proj,projdesc = line.split(":", 1) + proj = proj.strip() + projdesc = projdesc.strip() + self.projections[proj] = projdesc + f.close() + + f = open(os.path.join(os.getenv("GISBASE"), "etc","datum.table"),"r") + self.datums = {} + paramslist = [] + for line in f.readlines(): + line = line.expandtabs(1) + line = line.strip() + if not line: + continue + if line == '' or line[0] == "#": + continue + datum,info = line.split(" ", 1) + info = info.strip() + datumdesc,params = info.split(" ",1) + datumdesc = datumdesc.strip('"') + paramlist = params.split() + ellipsoid = paramlist.pop(0) + self.datums[datum] = (datumdesc,ellipsoid,paramlist) + f.close() + + # make datum transforms dictionary + f = open(os.path.join(os.getenv("GISBASE"), "etc","datumtransform.table"),"r") + self.transforms = {} + j = 1 + for line in f.readlines(): + transcode = 'T'+str(j) + line = line.expandtabs(1) + line = line.strip() + if not line: + continue + if line == '' or line[0] == "#": + continue + datum,rest = line.split(" ", 1) + rest = rest.strip('" ') + params,rest = rest.split('"', 1) + params = params.strip() + rest = rest.strip('" ') + try: + region,info = rest.split('"', 1) + info = info.strip('" ') + info = region+': '+info + except: + info = rest + self.transforms[transcode] = (datum,info,params) + j+=1 + f.close() + + # make ellipsiods dictionary + f = open(os.path.join(os.getenv("GISBASE"), "etc","ellipse.table"),"r") + self.ellipsoids = {} + for line in f.readlines(): + line = line.expandtabs(1) + line = line.strip() + if not line: + continue + if line == '' or line[0] == "#": + continue + ellipse,rest = line.split(" ", 1) + rest = rest.strip('" ') + desc,params = rest.split('"', 1) + desc = desc.strip('" ') + paramslist = params.split() + self.ellipsoids[ellipse] = (desc,paramslist) + f.close() + + # define wizard pages + self.wizard = wiz.Wizard(parent, -1, "Define new Location", + bitmap=wizbmp) + self.startpage = DatabasePage(self.wizard, self, grassdatabase) + self.csystemspage = CoordinateSystemPage(self.wizard, self) + self.projpage = ProjectionsPage(self.wizard, self) + self.projtypepage = ProjTypePage(self.wizard,self) + self.epsgpage = EPSGPage(self.wizard, self) + self.filepage = GeoreferencedFilePage(self.wizard, self) + self.datumpage = DatumPage(self.wizard, self) + self.ellipsepage = EllipsePage(self.wizard, self) + self.custompage = CustomPage(self.wizard, self) + self.sumpage = SummaryPage(self.wizard, self) + + + # Set the initial order of the pages + # it should follow the epsg line + self.startpage.SetNext(self.csystemspage) + + self.csystemspage.SetPrev(self.startpage) + self.csystemspage.SetNext(self.sumpage) + + self.projpage.SetPrev(self.csystemspage) + self.projpage.SetNext(self.projtypepage) + + self.projtypepage.SetPrev(self.projpage) + self.projtypepage.SetNext(self.datumpage) + + self.datumpage.SetPrev(self.projtypepage) + self.datumpage.SetNext(self.sumpage) + + self.ellipsepage.SetPrev(self.projtypepage) + self.ellipsepage.SetNext(self.sumpage) + + self.epsgpage.SetPrev(self.csystemspage) + self.epsgpage.SetNext(self.sumpage) + + self.filepage.SetPrev(self.csystemspage) + self.filepage.SetNext(self.sumpage) + + self.custompage.SetPrev(self.csystemspage) + self.custompage.SetNext(self.sumpage) + + self.sumpage.SetPrev(self.csystemspage) + + self.wizard.FitToPage(self.datumpage) + + self.location = None #New location created + + success = False + + if self.wizard.RunWizard(self.startpage): + success = self.onWizFinished() + if success == True: + self.location = self.startpage.location + dlg = wx.MessageDialog(self.wizard, + "Do you want to set the default region extents and resolution now?", + "New location '%s' created"% self.location, + wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_YES: + dlg.Destroy() + defineRegion = RegionDef(None, location=self.location) + defineRegion.Show() + else: + dlg.Destroy() + + else: + wx.MessageBox("Unable to create new location.") + else: + wx.MessageBox("Location wizard canceled. New location not created.") + +# self.wizard.Destroy() + + def onWizFinished(self): + database = self.startpage.grassdatabase + location = self.startpage.location + global coordsys + success = False + +# wx.MessageBox("finished database: %s, location: %s, coordsys: %s" % (database, location, coordsys)) + if os.path.isdir(os.path.join(database,location)): + dlg = wx.MessageDialog(self, "Could not create new location: %s already exists" + % os.path.join(database,location),"Could not create location", + wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + if coordsys == "xy": + success = self.XYCreate() + elif coordsys == "latlong": + rows = int(round((float(north)-float(south))/float(resolution))) + cols = int(round((float(east)-float(west))/float(resolution))) + cells = int(rows*cols) + success = self.LatlongCreate() + elif coordsys == "proj": + success = self.Proj4Create() + elif coordsys == 'custom': + success = self.CustomCreate() + elif coordsys == "epsg": + success = self.EPSGCreate() + elif coordsys == "file": + success = self.FileCreate() + + return success + + def XYCreate(self): + """ + Create an XY location + """ + database = self.startpage.grassdatabase + location = self.startpage.location + + dlg = wx.MessageDialog(self.wizard, "New XY location '%s' will be created (not projected or georeferenced)" + % location, + "Create new XY location?", + wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_NO: + dlg.Destroy() + return False + else: + dlg.Destroy() + + #Make location folder and PERMANT mapset + os.mkdir(os.path.join(database,location)) + os.mkdir(os.path.join(database,location,'PERMANENT')) + + #Make DEFAULT_WIND and WIND files + regioninfo = ['proj: 0', + 'zone: 0', + 'north: 1', + 'south: 0', + 'east: 1', + 'west: 0', + 'cols: 1', + 'rows: 1', + 'e-w resol: 1', + 'n-s resol: 1', + 'top: 1', + 'bottom: 0', + 'cols3: 1', + 'rows3: 1', + 'depths: 1', + 'e-w resol3: 1', + 'n-s resol3: 1', + 't-b resol: 1'] + + try: + defwind = open(os.path.join(database,location,"PERMANENT","DEFAULT_WIND"),'w') + for param in regioninfo: + defwind.write(param+'\n') + defwind.close() + shutil.copy(os.path.join(database,location,"PERMANENT","DEFAULT_WIND"),\ + os.path.join(database,location,"PERMANENT","WIND")) + + #Make MYNAME file + myname = open(os.path.join(database,location,"PERMANENT","MYNAME"),'w') + myname.write('') + myname.close() + return True + except: + return False + + def Proj4Create(self): + """ + Create a new location for selected projection + """ + + location = self.startpage.location + proj = self.projpage.proj + projdesc = self.projpage.projdesc + + utmzone = self.projtypepage.utmzone + utmhemisphere = self.projtypepage.utmhemisphere + + datum = self.datumpage.datum + if self.datumpage.datumdesc: + datumdesc = self.datumpage.datumdesc+' - '+self.datumpage.ellipsoid + else: datumdesc = '' + datumparams = self.datumpage.datumparams + transparams = self.datumpage.transparams + + ellipse = self.ellipsepage.ellipse + ellipsedesc = self.ellipsepage.ellipsedesc + ellipseparams = self.ellipsepage.ellipseparams + + # Creating PROJ.4 string + if proj == 'll': + proj = 'longlat' + + if proj == 'utm' and utmhemisphere == 'south': + proj4string = '+proj=%s +zone=%s +south' % (proj, utmzone) + elif proj == 'utm': + proj4string = '+proj=%s +zone=%s' % (proj, utmzone) + else: + proj4string = '+proj=%s ' % (proj) + + proj4params = '' + # set ellipsoid parameters + for item in ellipseparams: + if item[:4] == 'f=1/': + item = '+rf='+item[4:] + else: + item = '+'+item + proj4params = '%s %s' % (proj4params, item) + # set datum and transform parameters if relevant + if datumparams: + for item in datumparams: + proj4params = '%s +%s' % (proj4params,item) + if transparams: + proj4params = '%s +no_defs +%s' % (proj4params,transparams) + else: + proj4params = '%s +no_defs' % proj4params + else: + proj4params = '%s +no_defs' % proj4params + + proj4string = '%s %s' % (proj4string, proj4params) + + msgtext = "New location '%s' will be created georeferenced to" % location + georeftext = '%s: %s%s' % (projdesc,datumdesc,ellipsedesc) + p4text = '(PROJ.4 string: %s)' % proj4string + + dlg = wx.MessageDialog(self.wizard, msgtext+' '+georeftext+' '+p4text, + "Create new location?", + wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_NO: + dlg.Destroy() + return False + else: + dlg.Destroy() + + # Creating location from PROJ.4 string passed to g.proj + try: + cmdlist = ['g.proj', '-c', 'proj4=%s' % proj4string, 'location=%s' % location] + p = gcmd.Command(cmdlist) + if p.module.returncode == 0: + return True + else: + return False + + except StandardError, e: + dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + def CustomCreate(self): + proj4string = self.custompage.customstring + location = self.startpage.location + + dlg = wx.MessageDialog(self.wizard, "New location '%s' will be created using PROJ.4 string: %s" + % (location,proj4string), + "Create new location?", + wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_NO: + dlg.Destroy() + return False + else: + dlg.Destroy() + + try: + cmdlist = ['g.proj','-c','proj4=%s' % proj4string,'location=%s' % location] + p = gcmd.Command(cmdlist) + if p.module.returncode == 0: + return True + else: + return False + + except StandardError, e: + dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + + def EPSGCreate(self): + """ + Create a new location from an EPSG code. + """ + epsgcode = self.epsgpage.epsgcode + epsgdesc = self.epsgpage.epsgdesc + location = self.startpage.location + cmdlist = [] + + if not epsgcode: + dlg = wx.MessageDialog(self.wizard, "Could not create new location: EPSG Code value missing", + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + dlg = wx.MessageDialog(self.wizard, "New location '%s' will be created georeferenced to EPSG code %s: %s" + % (location, epsgcode, epsgdesc), + "Create new location from EPSG code?", + wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_NO: + dlg.Destroy() + return False + else: + dlg.Destroy() + + # creating location + try: + cmdlist = ['g.proj','epsg=%s' % epsgcode,'datumtrans=-1'] + p = gcmd.Command(cmdlist) + dtoptions = p.module_stdout.read() + if dtoptions != None: + dtrans = '' + # open a dialog to select datum transform number + dlg = wx.TextEntryDialog(self.wizard, dtoptions, + caption='Select the number of a datum transformation to use', + defaultValue='1', + style=wx.TE_WORDWRAP|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX| + wx.RESIZE_BORDER|wx.VSCROLL| + wx.OK|wx.CANCEL) + + if dlg.ShowModal() == wx.ID_CANCEL: + dlg.Destroy() + return False + else: + dtrans = dlg.GetValue() + if dtrans != '': + dlg.Destroy() + else: + wx.MessageBox('You must select a datum transform') + return False + + cmdlist = ['g.proj','-c','epsg=%s' % epsgcode,'location=%s' % location,'datumtrans=%s' % dtrans] + else: + cmdlist = ['g.proj','-c','epsg=%s' % epsgcode,'location=%s' % location,'datumtrans=1'] + + p = gcmd.Command(cmdlist) + if p.module.returncode == 0: + return True + else: + return False + + except StandardError, e: + dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + def FileCreate(self): + """ + Create a new location from a georeferenced file + """ + georeffile = self.filepage.georeffile + location = self.startpage.location + + cmdlist = [] + + dlg = wx.MessageDialog(self.wizard, "New location '%s' will be created georeferenced to file '%s'" + % (location, georeffile), "Create new location from georeferenced file?", + wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) + if dlg.ShowModal() == wx.ID_NO: + dlg.Destroy() + return False + else: + dlg.Destroy() + + if not os.path.isfile(georeffile): + dlg = wx.MessageDialog(self.wizard, "Could not create new location: could not find file %s" % georeffile, + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + if not georeffile: + dlg = wx.MessageDialog(self.wizard, "Could not create new location: georeferenced file not set", + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + + # creating location + try: + cmdlist = ['g.proj','-c','georef=%s' % georeffile,'location=%s' % location] + p = gcmd.Command(cmdlist) + if p.module.returncode == 0: + return True + else: + return False + + except StandardError, e: + dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), + "Could not create location", wx.OK|wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + return False + +if __name__ == "__main__": + gWizard = GWizard(None, "") + GRASSStartUp = GWizard.StartUp(0) + GRASSStartUp.MainLoop() + #app.MainLoop() Copied: trunk/grassaddons/gui/gui_modules/states.txt (from rev 1148, trunk/grassaddons/gui/states.txt) =================================================================== --- trunk/grassaddons/gui/gui_modules/states.txt (rev 0) +++ trunk/grassaddons/gui/gui_modules/states.txt 2007-10-20 09:51:46 UTC (rev 1149) @@ -0,0 +1,185 @@ +Afghanistan; 59.9,28.66 75.65,39.11 +Africa; -20.2,-37.6 53.4,35.75 +Albania; 19.36,39.42 21.39,42.71 +Algeria; -9.47,17.94 13.19,38.14 +Angola; 11.31,-18.68 24.97,-3.84 +Antarctic; -180,-90 180,-66 +Antarctica; -180,-90 180,-62.83 +Arctic; -180,66 180,90 +Argentina; -74.97,-56.71 -51.76,-20.25 +Armenia; 43.53,38.68 47.07,41.48 +Asia; 40,-10 180,83.5 +Australia; 111.22,-45.73 155.72,-8.88 +Austria; 9.27,45.99 17.93,49.38 +Azerbaijan; 44.58,38.04 50.96,42.2 +Bangladesh; 87.95,20.75 93.07,26.62 +Belgium; 2.54,49.31 6.69,51.69 +Belize; -89.18,15.78 -87.78,18.64 +Benin; 0.74,5.97 4.34,12.66 +Bhutan; 88.8,26.54 92.37,28.46 +Bolivia; -70.05,-23.63 -56.72,-9.13 +Bosnia and Herzegovina; 15.76,42.38 20.02,45.45 +Botswana; 19.57,-27.41 29.94,-17.32 +Brazil; -75.64,-35.81 -32.74,7.12 +Brunei; 114.22,3.96 115.42,5.09 +Bulgaria; 22.19,40.86 29.02,44.59 +Burkina Faso; -5.72,9.19 2.98,15.54 +Burma; 91.41,9.22 102.13,29.34 +Burundi; 28.98,-4.85 31.17,-2.35 +Byelarus; 22.91,50.82 33.38,56.65 +Cambodia; 102.28,10.07 107.98,14.86 +Cameroon; 8.22,1.06 16.85,13.65 +Canada; -145.27,37.3 -48.11,87.61 +Caribbean; -91.4,27.36 -55.4,6.48 +Central African Republic; 13.96,1.5 28.11,11.67 +Central America; -94.1,21.8 -75.8,6.61 +Chad; 12.88,6.67 24.97,24.19 +Chile; -77.16,-56.79 -64.9,-15.72 +China; 70.83,15.06 137.97,56.58 +Colombia; -79.69,-5 -66.15,13.28 +Congo; 10.93,-5.41 19.19,3.98 +Costa Rica; -85.83,7.9 -82.18,11.38 +Croatia; 13.47,42.09 19.92,46.84 +Cuba; -85.03,19.36 -73.44,23.68 +Cyprus; 32.23,34.44 34.78,35.78 +Czech Republic; 12.13,48.23 19.38,51.42 +Denmark; 8.02,54.68 12.89,58 +Djibouti; 41.89,10.78 43.77,12.81 +Dominican Republic; -71.87,17.54 -67.99,20.12 +East Pacific Ocean; -180,64.8 -72.7,-75.6 +Ecuador; -81.08,-5.35 -74.68,1.72 +Egypt; 24.29,21.29 37.61,32.14 +El Salvador; -90.05,13.07 -87.41,14.6 +Equatorial Guinea; 8.39,0.76 11.59,3.82 +Eritrea; 36.31,12 43.58,18.41 +Estonia; 23.3,57.29 28.59,59.75 +Ethiopia; 32.49,2.63 48.85,15.56 +Europe; -25.1,71.3 35,34.9 +Finland; 20.46,59.3 32.14,70.44 +France; -5.29,40.65 10.4,51.82 +French Guiana; -54.37,1.84 -51.23,5.89 +Gabon; 8.71,-4.23 15.01,2.6 +Gambia; -16.71,13.02 -13.66,13.96 +Germany; 5.68,46.86 15.68,55.41 +Ghana; -3.31,4.39 1.7,11.47 +Greece; 19.99,34.62 27.19,42.01 +Greenland; -75.34,56.78 -9.36,86.6 +Guatemala; -92.24,13.59 -87.87,18.06 +Guinea; -15.19,6.77 -6.87,13.02 +Guinea-Bissau; -16.51,10.97 -13.34,12.8 +Guyana; -61.41,0.81 -56.12,8.79 +Haiti; -74.38,17.88 -71.34,20.1 +Honduras; -89.47,12.75 -82.92,16.31 +Hungary; 16.12,45.44 23.57,48.95 +Iceland; -24.55,62.81 -12.79,67.01 +India; 66.79,6.58 99.01,36.96 +Indian Ocean; 22.3,-55.4 119.5,25.2 +Indonesia; 93.11,-12.65 143.45,7.88 +Iran; 43.31,24.08 64.42,40.73 +Iraq; 38.47,28.5 49.25,37.84 +Ireland; -10.52,51.23 -5.62,55.49 +Israel; 34.17,29.25 36.09,33.31 +Italy; 6.11,36.15 19.33,47.71 +Ivory Coast; -8.64,4.03 -2.01,10.96 +Jamaica; -78.22,17.72 -76,18.63 +Japan; 128.74,30.1 146.46,46.26 +Jordan; 34.97,28.87 39.75,33.44 +Kazakhstan; 44.73,38.62 89.65,57.49 +Kenya; 33,-5.3 42.44,5.07 +Democratic People's Republic of Korea; 124.02,43.29 37.55,130.95 +Republic of Korea; 125.95,38.76 33.06,129.88 +Kuwait; 46.62,28.34 48.74,30 +Kyrgyzstan; 69.01,38.7 81.03,43.77 +Laos; 99.77,13.47 108.1,22.98 +Latvia; 20.76,55.32 28.76,58.44 +Lebanon; 35.09,32.84 36.79,34.63 +Lesotho; 27.16,-30.89 29.76,-28.59 +Liberia; -11.47,4.16 -6.95,8.66 +Libya; 8.79,18.7 26.1,33.95 +Lithuania; 20.86,53.6 27.25,56.73 +Luxembourg; 5.9,49.42 6.77,50.21 +Macedonia; 20.62,40.62 23.27,42.48 +Madagascar; 42.83,-26.31 51.38,-11.58 +Malawi; 32.55,-17.51 36.46,-9.26 +Malaysia; 99.4,-0.2 120.19,7.86 +Mali; -12.77,9.25 5.27,25.83 +Mauritania; -17.47,14.21 -4.04,27.81 +Mexico; -118.48,13.05 -85.18,34.17 +Middle East; 25,10.7 59.7,36.1 +Moldova; 26.64,45.31 30.47,48.64 +Mongolia; 86.47,40 121.62,53.65 +Montenegro; 18.56,41.77 20.67,43.64 +Morocco; -13.52,26.96 -0.28,36.48 +Mozambique; 29.67,-27.82 41.89,-9.63 +Namibia; 11.32,-29.61 25.86,-16.31 +Nepal; 79.9,26 88.84,30.88 +Netherlands; 3.54,50.56 7.62,53.59 +New Hampshire; -72.68,42.57 -70.58,45.43 +New Jersey; -75.69,38.8 -73.78,41.47 +New Mexico; -109.35,31.04 -102.7,37.3 +New Zealand; 166.05,-47.31 179.41,-33.89 +Nicaragua; -87.7,10.55 -82.87,15.24 +Niger; -0.39,10.95 16.95,24.28 +Nigeria; 2.33,3.72 15.34,14.4 +North America; -168.5,18 -50.4,85.7 +North Atlantic Ocean; -82,0 12,80 +Northern Temperate; -180,23 180,60 +Norway; 3.88,56.69 32.56,81.95 +Oman; 51.53,16.19 60.52,26.73 +Pakistan; 60.18,22.94 78.66,37.86 +Panama; -83.06,6.9 -76.63,9.95 +Papua New Guinea; 140.37,-11.3 153.05,-2.2 +Paraguay; -62.83,-27.85 -53.6,-18.87 +Peru; -82.13,-19.35 -67.52,0.79 +Philippines; 116.68,4.85 127.23,19.22 +Poland; 13.77,48.57 24.85,55.24 +Portugal; -9.6,36.75 -5.65,42.36 +Qatar; 50.97,24.33 51.89,26.17 +Romania; 20.05,43.29 30.38,48.76 +Russia; 25,23.21 180,71 +Rwanda; 28.9,-3.01 31.2,-1.03 +Saudi Arabia; 33.9,14.01 57.3,33.22 +Senegal; -17.53,12.02 -10.89,17.14 +Serbia; 18.8,41.66 23.35,46.39 +Sierra Leone; -13.16,6.71 -10.02,10.09 +Slovakia; 16.84,47.61 23.06,49.93 +Slovenia; 13.39,45.28 16.87,47.06 +Somalia; 40.53,-2.55 52.14,12.66 +South Africa; 13.68,-35.9 33.98,-21.27 +South America; -84.9,-57.6 -32.4,13.7 +South Atlantic Ocean; -67,-55.4 23,0 +Southern Ocean; -180,-77 180,-32 +Southern Temperate; -180,-60 180,-23 +Spain; -9.69,35.4 3.98,44.38 +Sri Lanka; 79.69,5.76 82.26,9.89 +Sudan; 21.06,2.6 39.77,22.86 +Suriname; -58.01,1.53 -53.42,6.23 +Swaziland; 30.93,-27.52 32.45,-25.72 +Sweden; 10.56,54.63 24.84,69.68 +Switzerland; 5.92,45.66 10.84,48.02 +Syria; 35.36,31.84 43.11,37.69 +Taiwan; 119.99,21.78 122.14,25.31 +Tajikistan; 67.34,36.34 75.59,41.46 +Tanzania United Republic of; 0,-0.54 28.96,41.23 +Thailand; 96.83,4.8 106.42,21.22 +Togo; -0.09,5.85 2.21,11.33 +Trinidad; -61.88,10.01 -60.86,10.89 +Tropics; -180,-23 180,23 +Tunisia; 7.38,29.87 12.03,37.65 +Turkey; 25.29,34.91 45.94,43 +Turkmenistan; 52.05,34.56 67.66,43.46 +Uganda; 29.45,-1.82 35.52,4.32 +Ukraine; 21.4,43.61 41.24,53.31 +United Arab Emirates; 51.06,21.82 56.87,26.25 +United Kingdom; -8.41,49.49 2.39,59.07 +United States; -180,13.71 -61.48,76.63 +Uruguay; -58.46,-35.26 -52.77,-29.97 +Uzbekistan; 55.44,36.08 74.31,46.46 +Venezuela; -73.81,-0.11 -58.91,12.92 +Vietnam; 101.43,7.75 110.25,24.05 +Virginia; -84.1,36.12 -74.82,39.88 +Western Sahara; -17.23,20.87 -8.01,28 +Yemen; 42.45,12.12 53.74,19.51 +Zaire; 11.45,-14.4 32.4,6.28 +Zambia; 21.55,-18.7 34.45,-7.69 +Zimbabwe; 25.11,-22.93 33.65,15.22 Deleted: trunk/grassaddons/gui/location_wizard.py =================================================================== --- trunk/grassaddons/gui/location_wizard.py 2007-10-19 22:28:09 UTC (rev 1148) +++ trunk/grassaddons/gui/location_wizard.py 2007-10-20 09:51:46 UTC (rev 1149) @@ -1,1863 +0,0 @@ -""" -MODULE: location_wizard.py - -CLASSES: - * TitledPage - * DatabasePage - * CoordinateSystemPage - * ProjectionsPage - * ProjTypePage - * DatumPage - * EllipsePage - * GeoreferencedFilePage - * EPSGPage - * CustomPage - * SummaryPage - * RegionDef - * GWizard - -PURPOSE: Create a new GRASS location. User can choose from multiple methods - -AUTHORS: The GRASS Development Team - Michael Barton - Jachym Cepicky - -COPYRIGHT: (C) 2006-2007 by the GRASS Development Team - This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. -""" -import os -import shutil -import re -import string -import sys - -import wx -import wx.lib.mixins.listctrl as listmix -import wx.lib.rcsizer as rcs -import wx.wizard as wiz - -import gui_modules -import gui_modules.gcmd as gcmd -try: - import subprocess -except: - from compat import subprocess - - -gmpath = gui_modules.__path__[0] -sys.path.append(gmpath) - - -global coordsys -global north -global south -global east -global west -global resolution -global wizerror - -coordsys = '' -north = '' -south = '' -east = '' -west = '' -resolution = '' - -class TitledPage(wiz.WizardPageSimple): - """ - Class to make wizard pages. Generic methods to make - labels, text entries, and buttons. - """ - def __init__(self, parent, title): - wiz.WizardPageSimple.__init__(self, parent) - - self.title = wx.StaticText(self,-1,title) - self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD)) - - self.sizer = rcs.RowColSizer() - tmpsizer = wx.BoxSizer(wx.VERTICAL) - - tmpsizer.Add(self.title, 0, wx.ALIGN_CENTRE|wx.ALL, 5) - tmpsizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) - tmpsizer.Add(self.sizer, wx.EXPAND) - - self.SetSizer(tmpsizer) - self.SetAutoLayout(True) - - def MakeRLabel(self, text=""): - """Make right-aligned label""" - try: - if text[-1] != " ": - text += " " - except: - pass - return wx.StaticText(self, -1, text, style=wx.ALIGN_RIGHT) - - def MakeLLabel(self, text=""): - """Make left-aligned label""" - try: - if text[-1] != " ": - text += " " - except: - pass - return wx.StaticText(self, -1, text, style=wx.ALIGN_LEFT) - - def MakeTextCtrl(self,text='', size=(100,-1)): - """Generic text control""" - return wx.TextCtrl(self,-1, text, size=size) - - def MakeButton(self,text, size=(75,25)): - """Generic button""" - return wx.Button(self, -1, text, - style=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, - size=size) - - -class DatabasePage(TitledPage): - """ - Wizard page for setting GIS data directory and location name - """ - def __init__(self, wizard, parent, grassdatabase): - TitledPage.__init__(self, wizard, "Define GRASS database and new Location Name") - - self.grassdatabase = grassdatabase - self.location = '' - - # buttons - self.bbrowse = self.MakeButton("Browse...") - - # text controls - self.tgisdbase = self.MakeTextCtrl(grassdatabase, size=(300, -1)) - self.tlocation = self.MakeTextCtrl("newLocation", size=(300, -1)) - - # layout - self.sizer.Add(self.MakeRLabel("GIS Data Directory:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, - row=1, col=2) - self.sizer.Add(self.tgisdbase,0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, - row=1, col=3) - self.sizer.Add(self.bbrowse, 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, - row=1, col=4) - # - self.sizer.Add(self.MakeRLabel("Project Location"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, - row=2, col=2) - self.sizer.Add(self.tlocation,0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, - row=2, col=3) - self.sizer.Add(self.MakeRLabel("(projection/coordinate system)"), 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, - row=2, col=4) - - # bindings - self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.onPageChanging) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged) - - def OnBrowse(self, event): - dlg = wx.DirDialog(self, "Choose GRASS data directory:", os.getcwd(),wx.DD_DEFAULT_STYLE) - if dlg.ShowModal() == wx.ID_OK: - self.grassdatabase = dlg.GetPath() - self.tgisdbase.SetValue(self.grassdatabase) - dlg.Destroy() - - def onPageChanging(self,event=None): - if os.path.isdir(os.path.join(self.tgisdbase.GetValue(),self.tlocation.GetValue())): - dlg = wx.MessageDialog(self, "Could not create new location: <%s> directory exists "\ - % str(self.tlocation.GetValue()),"Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - event.Veto() - return - - if not self.tlocation.GetValue(): - dlg = wx.MessageDialog(self, "Could not create new location: location not set "\ - ,"Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - event.Veto() - return - - self.location = self.tlocation.GetValue() - self.grassdatabase = self.tgisdbase.GetValue() - - def OnPageChanged(self,event=None): - self.grassdatabase = self.tgisdbase.GetValue() - self.location = self.tlocation.GetValue() - - -class CoordinateSystemPage(TitledPage): - """ - Wizard page for choosing method for location creation - """ - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Choose method for creating a new location") - - self.parent = parent - global coordsys - - # toggles - self.radio1 = wx.RadioButton( self, -1, " Select coordinate system " , style = wx.RB_GROUP) - self.radio2 = wx.RadioButton( self, -1, " Select EPSG code for coordinate system " ) - self.radio3 = wx.RadioButton( self, -1, " Use coordinate system of selected georeferenced file " ) - self.radio4 = wx.RadioButton( self, -1, " Create custom PROJ.4 parameters string for coordinate system " ) - self.radio5 = wx.RadioButton( self, -1, " Create arbitrary non-earth coordinate system (XY)" ) - - # layout - self.sizer.Add(self.radio1, 0, wx.ALIGN_LEFT, row=1, col=2) - self.sizer.Add(self.radio2, 0, wx.ALIGN_LEFT, row=2, col=2) - self.sizer.Add(self.radio3, 0, wx.ALIGN_LEFT, row=3, col=2) - self.sizer.Add(self.radio4, 0, wx.ALIGN_LEFT, row=4, col=2) - self.sizer.Add(self.radio5, 0, wx.ALIGN_LEFT, row=5, col=2) - - # bindings - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio1.GetId()) - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio2.GetId()) - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio3.GetId()) - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio4.GetId()) - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio5.GetId()) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - - def OnPageChange(self,event=None): - global coordsys - if event.GetDirection() and not coordsys: - wx.MessageBox('You must select a coordinate system') - event.Veto() - - def SetVal(self,event): - global coordsys - if event.GetId() == self.radio1.GetId(): - coordsys = "proj" - self.SetNext(self.parent.projpage) - self.parent.sumpage.SetPrev(self.parent.datumpage) - elif event.GetId() == self.radio2.GetId(): - coordsys = "epsg" - self.SetNext(self.parent.epsgpage) - self.parent.sumpage.SetPrev(self.parent.epsgpage) - elif event.GetId() == self.radio3.GetId(): - coordsys = "file" - self.SetNext(self.parent.filepage) - self.parent.sumpage.SetPrev(self.parent.filepage) - elif event.GetId() == self.radio4.GetId(): - coordsys = "custom" - self.SetNext(self.parent.custompage) - self.parent.sumpage.SetPrev(self.parent.custompage) - elif event.GetId() == self.radio5.GetId(): - coordsys = "xy" - self.SetNext(self.parent.sumpage) - set.parent.sumpage.SetPrev(self.parent.csystemspage) - -class ProjectionsPage(TitledPage): - """ - Wizard page for selecting projection (select coordinate system option) - """ - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Choose projection") - - self.parent = parent - self.proj = '' - self.projdesc = '' - - # text input - self.tproj = self.MakeTextCtrl("", size=(200,-1)) - - # search box - self.searchb = wx.SearchCtrl(self, size=(200,-1), - style=wx.TE_PROCESS_ENTER) - - self.projlist = wx.ListCtrl(self, id=wx.ID_ANY, - size=(650,275), - style=wx.LC_REPORT | - wx.LC_HRULES | - wx.EXPAND) - self.projlist.InsertColumn(0, 'Code') - self.projlist.InsertColumn(1, 'Description') - self.projlist.SetColumnWidth(0, 100) - self.projlist.SetColumnWidth(1, 500) - - # layout - self.sizer.Add(self.MakeRLabel("Projection code:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=2) - self.sizer.Add(self.tproj, 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=3) - - self.sizer.Add(self.MakeRLabel("Search in projection description"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2, col=2) - self.sizer.Add(self.searchb, 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2, col=3) - - self.sizer.Add(self.projlist, - wx.EXPAND | - wx.ALIGN_LEFT | - wx.ALL, 5, row=3, col=1, colspan=4) - - # events - self.Bind(wx.EVT_TEXT, self.OnText, self.tproj) - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.projlist) - self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - - self._onBrowseProj(None, None) - - def OnPageChange(self,event): - if event.GetDirection() and self.proj not in self.parent.projections: - wx.MessageBox('You must select a valid projection in order to continue') - event.Veto() - if self.proj == 'utm': - self.parent.projtypepage.text_utm.SetEditable(True) - self.parent.projtypepage.hemischoices = ['north','south'] - else: - self.parent.projtypepage.text_utm.SetValue('') - self.parent.projtypepage.text_utm.SetEditable(False) - self.parent.projtypepage.hemischoices = [] - - def OnText(self, event): - self.proj = event.GetString() - if self.proj in self.parent.projections: - self.projdesc = self.parent.projections[self.proj] - - def OnDoSearch(self,event): - str = self.searchb.GetValue() - listItem = self.projlist.GetColumn(1) - - for i in range(self.projlist.GetItemCount()): - listItem = self.projlist.GetItem(i,1) - if listItem.GetText().find(str) > -1: - self.proj = self.projlist.GetItem(i, 0).GetText() - self.tproj.SetValue(self.proj) - break - - self._onBrowseProj(None,str) - - def OnItemSelected(self,event): - index = event.m_itemIndex - item = event.GetItem() - - self.proj = item.GetText() - self.projdesc = self.projlist.GetItem(index, 1).GetText() - self.tproj.SetValue(self.proj) - - def _onBrowseProj(self,event,search=None): - try: - projlist = self.parent.projections.items() - projlist.sort() - self.projlist.DeleteAllItems() - for proj,desc in projlist: - entry = self.projlist.GetItemCount() - if search and (proj.lower().find(search.lower()) > -1 or \ - desc.lower().find(search.lower()) > -1) or \ - not search: - index = self.projlist.InsertStringItem(entry,proj) - self.projlist.SetStringItem(index,1,desc) - - self.projlist.SetColumnWidth(0, wx.LIST_AUTOSIZE) - self.projlist.SetColumnWidth(1, wx.LIST_AUTOSIZE) - self.projlist.SendSizeEvent() - - except StandardError, e: - dlg = wx.MessageDialog(self, "Could not read projections list: %s " % e, - "Could not read projections", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - -class ProjTypePage(TitledPage): - """ - Wizard page for selecting method of setting coordinate system parameters - (select coordinate system option) - """ - - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Choose method of specifying georeferencing parameters") - global coordsys - - self.utmzone = '' - self.utmhemisphere = '' - self.hemischoices = ["north","south"] - self.parent = parent - - self.radio1 = wx.RadioButton( self, -1, " Select datum with associated ellipsoid", style = wx.RB_GROUP ) - self.radio2 = wx.RadioButton( self, -1, " Select ellipsoid" ) - self.title_utm = self.MakeLLabel("Set zone for UTM projection") - self.text_utm = self.MakeTextCtrl(size=(100,-1)) - self.label_utm = self.MakeRLabel("Zone: ") - self.hemisphere = wx.Choice(self, -1, (100, 50), choices = self.hemischoices) - self.label_hemisphere = self.MakeRLabel("Hemisphere for zone: ") - - # layout - self.sizer.Add(self.radio1, 0, wx.ALIGN_LEFT, row=1, col=2) - self.sizer.Add(self.radio2, 0, wx.ALIGN_LEFT, row=2, col=2) - self.sizer.Add(self.title_utm, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=4,col=2) - self.sizer.Add(self.label_utm, 0, wx.ALIGN_RIGHT|wx.ALL, 5, row=5,col=1) - self.sizer.Add(self.text_utm, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=5,col=2) - self.sizer.Add(self.label_hemisphere, 0, wx.ALIGN_RIGHT|wx.ALL, 5, row=6,col=1) - self.sizer.Add(self.hemisphere, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=6,col=2) - - self.title_utm.Hide() - self.text_utm.Hide() - self.label_utm.Hide() - self.hemisphere.Hide() - self.label_hemisphere.Hide() - - # bindings - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio1.GetId()) - self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id=self.radio2.GetId()) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage) - - def OnPageChange(self,event=None): - if event.GetDirection() and self.parent.projpage.proj == 'utm' and self.utmzone == '': - wx.MessageBox('You must set a zone for a UTM projection') - event.Veto() - self.title_utm.Hide() - self.text_utm.Hide() - self.label_utm.Hide() - self.hemisphere.Hide() - self.label_hemisphere.Hide() - - def OnEnterPage(self,event): - if self.parent.projpage.proj == 'utm': - self.title_utm.Show() - self.text_utm.Show() - self.label_utm.Show() - self.hemisphere.Show() - self.label_hemisphere.Show() - - self.Bind(wx.EVT_CHOICE, self.OnHemisphere, self.hemisphere) - self.Bind(wx.EVT_TEXT, self.GetUTM, self.text_utm) - - def SetVal(self, event): - global coordsys - if event.GetId() == self.radio1.GetId(): - self.SetNext(self.parent.datumpage) - self.parent.sumpage.SetPrev(self.parent.datumpage) - elif event.GetId() == self.radio2.GetId(): - self.SetNext(self.parent.ellipsepage) - self.parent.sumpage.SetPrev(self.parent.ellipsepage) - - def GetUTM(self, event): - self.utmzone = event.GetString() - - def OnHemisphere(self, event): - self.utmhemisphere = event.GetString() - - -class DatumPage(TitledPage): - """ - Wizard page for selecting datum (with associated ellipsoid) - and datum transformation parameters (select coordinate system option) - """ - - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Specify geodetic datum") - - self.parent = parent - self.datum = '' - self.datumdesc = '' - self.ellipsoid = '' - self.datumparams = '' - self.transform = '' - self.transregion = '' - self.transparams = '' - self.hastransform = False - self.proj4params = '' - - # text input - self.tdatum = self.MakeTextCtrl("", size=(200,-1)) - self.ttrans = self.MakeTextCtrl("", size=(200,-1)) - - # search box - self.searchb = wx.SearchCtrl(self, size=(200,-1), - style=wx.TE_PROCESS_ENTER) - - # button -# self.bupdate = self.MakeButton("Update trans. parms.", -# size=(-1,-1)) - - # create list control for datum/elipsoid list - self.datumlist = wx.ListCtrl(self, id=wx.ID_ANY, - size=(650,150), - style=wx.LC_REPORT| - wx.LC_HRULES| - wx.EXPAND) - self.datumlist.InsertColumn(0, 'Code') - self.datumlist.InsertColumn(1, 'Description') - self.datumlist.InsertColumn(2, 'Ellipsoid') - self.datumlist.SetColumnWidth(0, 100) - self.datumlist.SetColumnWidth(1, 250) - self.datumlist.SetColumnWidth(2, 100) - - # create list control for datum transformation parameters list - self.transformlist = wx.ListCtrl(self, id=wx.ID_ANY, - size=(650,125), - style=wx.LC_REPORT | - wx.LC_HRULES | - wx.EXPAND) - self.transformlist.InsertColumn(0, 'Code') - self.transformlist.InsertColumn(1, 'Datum') - self.transformlist.InsertColumn(2, 'Description') - self.transformlist.SetColumnWidth(0, 50) - self.transformlist.SetColumnWidth(1, 125) - self.transformlist.SetColumnWidth(2, 250) - - # layout - self.sizer.Add(self.MakeRLabel("Datum code:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, col=1, row=1) - self.sizer.Add(self.tdatum, 0 , - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=2) -# self.sizer.Add(self.bupdate, 0 , -# wx.ALIGN_LEFT | -# wx.ALIGN_CENTER_VERTICAL | -# wx.ALL, 5, row=1, col=3) - self.sizer.Add(self.MakeRLabel("Search in description:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, col=1, row=2) - self.sizer.Add(self.searchb, 0 , - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2, col=2) - - self.sizer.Add(self.datumlist, - wx.EXPAND | - wx.ALIGN_LEFT | - wx.ALL, 5, row=3, col=1, colspan=4) - - self.sizer.Add(self.MakeRLabel("Transformation parameters:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, col=1, row=5) - self.sizer.Add(self.ttrans, 0 , - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=5, col=2) - - self.sizer.Add(self.transformlist, - wx.EXPAND | - wx.ALIGN_LEFT | - wx.ALL, 5, row=6, col=1, colspan=4) - - # events - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected, self.datumlist) - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnTransformSelected, self.transformlist) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) -# self.bupdate.Bind(wx.EVT_BUTTON, self._onBrowseParams) - self.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) - self.Bind(wx.EVT_TEXT, self.OnDText, self.tdatum) - - self._onBrowseDatums(None,None) - - def OnPageChange(self,event): - self.proj4params = '' - if event.GetDirection() and self.datum not in self.parent.datums: - wx.MessageBox('You must select a valid datum in order to continue') - event.Veto() -# if self.hastransform == True and self.transform == '': -# wx.MessageBox('You must select a datum transform') -# event.Veto() - self.GetNext().SetPrev(self) - self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipsoid][1] - self.GetNext().SetPrev(self) - - def OnDText(self, event): - self.datum = event.GetString() - if self.datum in self.parent.datums: - self.datumdesc = self.parent.datums[self.datum][0] - self.ellipsoid = self.parent.datums[self.datum][1] - self.datumparams = self.parent.datums[self.datum][2] - - self._onBrowseParams(None,self.datum) - - def OnTText(self, event): - self.transform = event.GetString() - if self.transform in self.parent.transforms: - self.transdatum = self.parent.transforms[self.transform][0] - self.transregion = self.parent.transforms[self.transform][1] - self.transparams = self.parent.transforms[self.transform][2] - - def OnDoSearch(self,event): - str = self.searchb.GetValue() - listItem = self.datumlist.GetColumn(1) - - for i in range(self.datumlist.GetItemCount()): - listItem = self.datumlist.GetItem(i,1) - if listItem.GetText().find(str) > -1: - datum = self.datumlist.GetItem(i, 0) - self.tdatum.SetValue(datum.GetText()) - break - - self._onBrowseDatums(None,str) - - def OnTransformSelected(self,event): - index = event.m_itemIndex - item = event.GetItem() - - self.transform = item.GetText() - self.transdatum = self.parent.transforms[self.transform][0] - self.transregion = self.parent.transforms[self.transform][1] - self.transparams = self.parent.transforms[self.transform][2] - - self.ttrans.SetValue(str(self.transform)) - - def OnDatumSelected(self,event): - index = event.m_itemIndex - item = event.GetItem() - - self.datum = item.GetText() - self.datumdesc = self.parent.datums[self.datum][0] - self.ellipsoid = self.parent.datums[self.datum][1] - self.datumparams = self.parent.datums[self.datum][2] - - self.tdatum.SetValue(self.datum) - self._onBrowseParams(None, self.datum) - event.Skip() - - def _onBrowseParams(self, event=None, search=None): - search = self.datum.strip() - try: - self.transform = '' - self.transformlist.DeleteAllItems() - for item in self.parent.transforms: - transdatum = self.parent.transforms[item][0] - transregion = self.parent.transforms[item][1] - entry = self.transformlist.GetItemCount() - if (transdatum.lower() == search.lower()): - index = self.transformlist.InsertStringItem(entry,item) - self.transformlist.SetStringItem(index,1,transdatum) - self.transformlist.SetStringItem(index,2,transregion) - self.hastransform = True - - self.transformlist.SetColumnWidth(0, wx.LIST_AUTOSIZE) - self.transformlist.SetColumnWidth(1, wx.LIST_AUTOSIZE) - self.transformlist.SetColumnWidth(2, wx.LIST_AUTOSIZE) - self.transformlist.SendSizeEvent() - - except IOError, e: - self.transformlist.DeleteAllItems() - dlg = wx.MessageDialog(self, "Could not read datum params: %s " % e, - "Could not read file", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - - def _onBrowseDatums(self,event,search=None): - try: - self.datum = '' - self.datumlist.DeleteAllItems() - - datumlist = self.parent.datums.items() - datumlist.sort() - for datum,info in datumlist: - datumdesc = info[0] - ellipse = info[1] - entry = self.datumlist.GetItemCount() - if search and (datum.lower().find(search.lower()) > -1 or\ - datumdesc.lower().find(search.lower()) > -1 or\ - ellipse.lower().find(search.lower()) > -1) or\ - not search: - index = self.datumlist.InsertStringItem(entry,datum) - self.datumlist.SetStringItem(index,1,datumdesc) - self.datumlist.SetStringItem(index,2,ellipse) - - self.datumlist.SetColumnWidth(0, wx.LIST_AUTOSIZE) - self.datumlist.SetColumnWidth(1, wx.LIST_AUTOSIZE) - self.datumlist.SetColumnWidth(2, wx.LIST_AUTOSIZE) - self.datumlist.SendSizeEvent() - - except IOError, e: - dlg = wx.MessageDialog(self, "Could not read datums: %s " % e, - "Could not read datums list", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - - -class EllipsePage(TitledPage): - """ - Wizard page for selecting ellipsoid (select coordinate system option) - """ - - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Specify ellipsoid") - - self.parent = parent - self.ellipse = '' - self.ellipsedesc = '' - self.ellipseparams = '' - self.proj4params = '' - - # text input - self.tellipse = self.MakeTextCtrl("", size=(200,-1)) - - # search box - self.searchb = wx.SearchCtrl(self, size=(200,-1), - style=wx.TE_PROCESS_ENTER) - - # create list control for ellipse list - self.ellipselist = wx.ListCtrl(self, id=wx.ID_ANY, - size=(650,250), - style=wx.LC_REPORT| - wx.LC_HRULES| - wx.EXPAND) - self.ellipselist.InsertColumn(0, 'Code') - self.ellipselist.InsertColumn(1, 'Description') - self.ellipselist.SetColumnWidth(0, 100) - self.ellipselist.SetColumnWidth(1, 250) - - # layout - self.sizer.Add(self.MakeRLabel("Ellipse code:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=1) - self.sizer.Add(self.tellipse, 0 , - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=2) - self.sizer.Add(self.MakeRLabel("Search in description:"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2, col=1) - self.sizer.Add(self.searchb, 0 , - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2, col=2) - - self.sizer.Add(self.ellipselist, 0 , - wx.EXPAND | - wx.ALIGN_LEFT | - wx.ALL, 5, row=3, col=1, colspan=3) - - # events - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnEllipseSelected, self.ellipselist) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) - self.Bind(wx.EVT_TEXT, self.OnText, self.tellipse) - - self._onBrowseEllipse(None,None) - - def OnPageChange(self,event): - self.proj4params = '' - if event.GetDirection() and self.ellipse not in self.parent.ellipsoids: - wx.MessageBox('You must select a valid ellipsoid in order to continue') - event.Veto() - self.GetNext().SetPrev(self) - self.parent.datumpage.datumparams = '' - self.parent.datumpage.transparams = '' - self.GetNext().SetPrev(self) - - def OnText(self, event): - self.ellipse = event.GetString() - if self.ellipse in self.parent.ellipsoids: - self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0] - self.ellipseparams = self.parent.ellipsoids[self.ellipse][1] - - def OnDoSearch(self,event): - str = self.searchb.GetValue() - listItem = self.ellipselist.GetColumn(1) - - for i in range(self.ellipselist.GetItemCount()): - item = self.ellipselist.GetItem(i,0) - itemdesc = self.ellipselist.GetItem(i,1) - if itemdesc.GetText().find(str) > -1: - self.ellipse = item.GetText() - self.tellipse.SetValue(self.ellipse) - self.ellipselist.EnsureVisible(long(self.ellipselist.GetItem(i))) - break - - self._onBrowseEllipse(None,str) - - def OnEllipseSelected(self,event): - index = event.m_itemIndex - item = event.GetItem() - - self.ellipse = item.GetText() - self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0] - self.ellipseparams = self.parent.ellipsoids[self.ellipse][1] - - self.tellipse.SetValue(self.ellipse) - self._onBrowseEllipse(None) - - def _onBrowseEllipse(self,event,search=None): - try: - ellipselist = self.parent.ellipsoids.items() - ellipselist.sort() - self.ellipselist.DeleteAllItems() - for ellipsoid,info in ellipselist: - desc = info[0] - entry = self.ellipselist.GetItemCount() - if search and (ellipsoid.lower().find(search.lower()) > -1 or \ - desc.lower().find(search.lower()) > -1) or \ - not search: - index = self.ellipselist.InsertStringItem(entry,ellipsoid) - self.ellipselist.SetStringItem(index,1,desc) - - self.ellipselist.SetColumnWidth(0, wx.LIST_AUTOSIZE) - self.ellipselist.SetColumnWidth(1, wx.LIST_AUTOSIZE) - self.ellipselist.SendSizeEvent() - except IOError, e: - dlg = wx.MessageDialog(self, "Could not read ellipse information: %s " % e, - "Problem parsing ellipse list", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - - -class GeoreferencedFilePage(TitledPage): - """ - Wizard page for selecting georeferenced file to use - for setting coordinate system parameters - """ - - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Select georeferenced file") - - self.georeffile = '' - - # create controls - self.lfile= wx.StaticText(self, -1, "Georeferenced file: ", - style=wx.ALIGN_RIGHT) - self.tfile = wx.TextCtrl(self,-1, "", size=(300,-1)) - self.bbrowse = wx.Button(self, -1, "Browse...") - - # do layout - self.sizer.Add(self.lfile, 0, wx.ALIGN_RIGHT | - wx.ALIGN_CENTRE_VERTICAL | - wx.ALL, 5, row=1, col=2) - self.sizer.Add(self.tfile, 0, wx.ALIGN_LEFT | - wx.ALIGN_CENTRE_VERTICAL | - wx.ALL, 5, row=1, col=3) - self.sizer.Add(self.bbrowse, 0, wx.ALIGN_LEFT | - wx.ALL, 5, row=1, col=4) - - self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) - self.Bind(wx.EVT_TEXT, self.OnText, self.tfile) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - - def OnPageChange(self, event): - if event.GetDirection() and self.georeffile == '': - wx.MessageBox('You must select a georeferenced file in order to continue') - event.Veto() - self.GetNext().SetPrev(self) - - def OnText(self, event): - self.georeffile = event.GetString() - - def OnBrowse(self, event): - - dlg = wx.FileDialog(self, "Choose a georeferenced file:", os.getcwd(), "", "*.*", wx.OPEN) - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - self.tfile.SetValue(path) - dlg.Destroy() - - def OnCreate(self, event): - pass - - -class EPSGPage(TitledPage): - """ - Wizard page for selecting EPSG code for - setting coordinate system parameters - """ - - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Choose EPSG Code") - self.parent = parent - self.epsgcode = '' - self.epsgdesc = '' - - - # labels - self.lfile= wx.StaticText(self, -1, "Path to the EPSG-codes file: ", - style=wx.ALIGN_RIGHT) - self.lcode= wx.StaticText(self, -1, "EPSG code: ", - style=wx.ALIGN_RIGHT) - self.lsearch= wx.StaticText(self, -1, "Search in code description: ", - style=wx.ALIGN_RIGHT) - - # text input - epsgdir = os.path.join(os.environ["GRASS_PROJSHARE"], 'epsg') - self.tfile = wx.TextCtrl(self,-1, epsgdir, size=(200,-1)) - self.tcode = wx.TextCtrl(self,-1, "", size=(200,-1)) - - # buttons - self.bbrowse = wx.Button(self, -1, "Browse...") - self.bbcodes = wx.Button(self, -1, "Browse Codes...") - - # search box - self.searchb = wx.SearchCtrl(self, size=(200,-1), style=wx.TE_PROCESS_ENTER) - - self.epsglist = wx.ListCtrl(self, id=wx.ID_ANY, - size=(650,275), - style=wx.LC_REPORT| - wx.LC_HRULES| - wx.EXPAND) - self.epsglist.InsertColumn(0, 'Code', wx.LIST_FORMAT_CENTRE) - self.epsglist.InsertColumn(1, 'Description', wx.LIST_FORMAT_LEFT) - self.epsglist.InsertColumn(2, 'Parameters', wx.LIST_FORMAT_LEFT) - self.epsglist.SetColumnWidth(0, 50) - self.epsglist.SetColumnWidth(1, 300) - self.epsglist.SetColumnWidth(2, 325) - - # layout - self.sizer.Add(self.lfile, 0, wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, col=1, row=1) - self.sizer.Add(self.tfile, 0, wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=2) - self.sizer.Add(self.bbrowse, 0, wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=1, col=3) - - self.sizer.Add(self.lcode, 0, wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, col=1, row=2) - self.sizer.Add(self.tcode, 0, wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2, col=2) - - self.sizer.Add(self.lsearch, 0, wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, col=1, row=3) - self.sizer.Add(self.searchb, 0, wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=3, col=2) - self.sizer.Add(self.bbcodes, 0 , wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=3, col=3) - - self.sizer.Add(self.epsglist, wx.ALIGN_LEFT|wx.EXPAND, 0, row=4, col=1, colspan=5) - - # events - self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.bbrowse) - self.Bind(wx.EVT_BUTTON, self.OnBrowseCodes, self.bbcodes) - self.Bind(wx.EVT_TEXT, self.OnText, self.tcode) - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.epsglist) - self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.searchb) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - - def OnPageChange(self, event): - if event.GetDirection() and not self.epsgcode: - wx.MessageBox('You must select an EPSG code') - event.Veto() - self.GetNext().SetPrev(self) - - def OnText(self, event): - self.epsgcode = event.GetString() - - def OnDoSearch(self,event): - str = self.searchb.GetValue() - listItem = self.epsglist.GetColumn(1) - - for i in range(self.epsglist.GetItemCount()): - listItem = self.epsglist.GetItem(i,1) - if listItem.GetText().find(str) > -1: - self.epsgcode = self.epsglist.GetItem(i, 0) - self.tcode.SetValue(self.epsgcode.GetText()) - break - - self.OnBrowseCodes(None,str) - - def OnBrowse(self, event): - - dlg = wx.FileDialog(self, "Choose EPSG codes file:", - "/", "", "*.*", wx.OPEN) - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - self.tfile.SetValue(path) - dlg.Destroy() - - def OnItemSelected(self,event): - index = event.m_itemIndex - item = event.GetItem() - - self.epsgcode = item.GetText() - self.epsgdesc = self.epsglist.GetItem(index, 1).GetText() - self.tcode.SetValue(str(self.epsgcode)) - - def OnBrowseCodes(self,event,search=None): - try: - self.epsglist.DeleteAllItems() - f = open(self.tfile.GetValue(),"r") - i=1 - j = 0 - descr = None - code = None - params = "" - #self.epsglist.ClearAll() - for line in f.readlines(): - line = line.strip() - if line.find("#") == 0: - descr = line[1:].strip() - elif line.find("<") == 0: - code = line.split(" ")[0] - for par in line.split(" ")[1:]: - params += par + " " - code = code[1:-1] - if code == None: code = 'no code' - if descr == None: descr = 'no description' - if params == None: params = 'no parameters' - if i%2 == 0: - if search and descr.lower().find(search.lower()) > -1 or\ - not search: - index = self.epsglist.InsertStringItem(j, code) - self.epsglist.SetStringItem(index, 1, descr) - self.epsglist.SetStringItem(index, 2, params) - j += 1 - # reset - descr = None; code = None; params = "" -# if i%2 == 0: -# self.epsglist.SetItemBackgroundColour(i, "grey") - i += 1 - f.close() - self.epsglist.SetColumnWidth(1, wx.LIST_AUTOSIZE) - self.epsglist.SetColumnWidth(2, wx.LIST_AUTOSIZE) - self.SendSizeEvent() - except StandardError, e: - dlg = wx.MessageDialog(self, "Could not read EPGS codes: %s " % e, - "Could not read file", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - - -class CustomPage(TitledPage): - """ - Wizard page for entering custom PROJ.4 string - for setting coordinate system parameters - """ - - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Choose method of specifying georeferencing parameters") - global coordsys - self.customstring = '' - self.parent = parent - - self.text_proj4string = self.MakeTextCtrl(size=(400,100)) - self.label_proj4string = self.MakeRLabel("Enter PROJ.4 parameters string: ") - self.sizer.Add(self.label_proj4string, 0, wx.ALIGN_RIGHT|wx.ALL, 5, row=5,col=1) - self.sizer.Add(self.text_proj4string, 0, wx.ALIGN_LEFT|wx.ALL, 5, row=5,col=2) - - self.Bind(wx.EVT_TEXT, self.GetProjstring, self.text_proj4string) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange) - - def OnPageChange(self, event): - if event.GetDirection() and not self.customstring: - wx.MessageBox('You must enter a PROJ.4 string') - event.Veto() - self.GetNext().SetPrev(self) - - def GetProjstring(self, event): - self.customstring = event.GetString() - - -class SummaryPage(TitledPage): - """ - Shows summary result of choosing coordinate system parameters - prior to creating location - """ - def __init__(self, wizard, parent): - TitledPage.__init__(self, wizard, "Summary") - - self.parent = parent - - # labels - self.ldatabase = self.MakeLLabel("") - self.llocation = self.MakeLLabel("") - self.lprojection = self.MakeLLabel("") - - self.lprojection.Wrap(500) - - self.sizer.Add(self.MakeRLabel("GRASS database:"), 1, flag=wx.ALIGN_RIGHT|wx.ALL, border=5, row=1, col=0) - self.sizer.Add(self.ldatabase, 1, flag=wx.ALIGN_LEFT|wx.ALL, border=5, row=1, col=1) - self.sizer.Add(self.MakeRLabel("Location name:"), 1, flag=wx.ALIGN_RIGHT|wx.ALL, border=5, row=2, col=0) - self.sizer.Add(self.llocation, 1, flag=wx.ALIGN_LEFT|wx.ALL, border=5, row=2, col=1) - self.sizer.Add(wx.StaticLine(self, -1), 0, wx.ALIGN_RIGHT|wx.EXPAND|wx.ALL, 0, row=3, col=0, colspan=2) - self.sizer.Add((10,10), 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, border=5, row=4, col=0) - self.sizer.Add(self.MakeRLabel("Projection: "), 1, flag=wx.ALIGN_RIGHT|wx.ALL, border=5, row=5, col=0) - self.sizer.Add(self.lprojection, 1, flag=wx.ALIGN_LEFT|wx.ALL, border=5, row=5, col=1) - self.sizer.Add((10,20), 1, flag=wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, border=5, row=6, col=0) - self.sizer.Add(self.MakeLLabel("You can set the default extents and resolution after creating new location"), \ - 1, flag=wx.ALIGN_CENTRE|wx.ALL, border=5, row=7, col=0, colspan=2) - self.sizer.Add(self.MakeLLabel("or you can set them during a working session."), \ - 1, flag=wx.ALIGN_CENTRE|wx.ALL, border=5, row=8, col=0, colspan=2) - - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnPageChange) - - def OnPageChange(self,event): - """ - Insert values into text controls for summary of location creation options - """ - - database = self.parent.startpage.grassdatabase - location = self.parent.startpage.location - - global coordsys - if not coordsys: - coordsys = 0 - - projection = self.parent.projpage.proj - projdesc = self.parent.projpage.projdesc - utmzone = self.parent.projtypepage.utmzone - utmhemisphere = self.parent.projtypepage.utmhemisphere - ellipse = self.parent.ellipsepage.ellipse - ellipsedesc = self.parent.ellipsepage.ellipsedesc - datum = self.parent.datumpage.datum - datumdesc = self.parent.datumpage.datumdesc - ellipsoid = self.parent.datumpage.ellipsoid - datumparams = self.parent.datumpage.datumparams - transform = self.parent.datumpage.transform - transregion = self.parent.datumpage.transregion - transparams = self.parent.datumpage.transparams - - self.ldatabase.SetLabel(str(database)) - self.llocation.SetLabel(str(location)) - label = '' - if coordsys == 'epsg': - label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode,self.parent.epsgpage.epsgdesc) - self.lprojection.SetLabel(label) - elif coordsys == 'file': - label = 'matches file %s' % self.parent.filepage.georeffile - self.lprojection.SetLabel(label) - elif coordsys == 'proj': - label = ('%s, %s%s' % (projdesc, datumdesc, ellipsedesc)) - self.lprojection.SetLabel(label) - elif coordsys == 'xy': - label = ('XY coordinate system. Not projected') - self.lprojection.SetLabel(label) - elif coordsys == 'custom': - label = ('%s' % self.parent.custompage.customstring) - self.lprojection.SetLabel(label) - -class RegionDef(wx.Frame): - """ - Page for setting default region extents and resolution - """ - - def __init__(self,parent,id=wx.ID_ANY, title="Set default region values", location=None): - wx.Frame.__init__(self, parent, id, title, size=(650,300)) - - self.parent = parent - self.location = location - - # inputs - self.ttop = self.MakeTextCtrl("1", size=(150, -1)) - self.tbottom = self.MakeTextCtrl("0", size=(150, -1)) - self.tleft = self.MakeTextCtrl("0", size=(150, -1)) - self.tright = self.MakeTextCtrl("1", size=(150, -1)) - self.tres = self.MakeTextCtrl("1", size=(150, -1)) - - self.north = 1.0 - self.south = 0.0 - self.east = 1.0 - self.west = 0.0 - self.res = 1.0 - - # labels - self.lmessage = wx.StaticText(self,-1, "", size=(300,50)) - - # buttons - self.bset = self.MakeButton("Set coordinates", size=(150,-1)) - self.bcancel = self.MakeButton("Cancel", size=(150,-1)) - - #Set current working environment to PERMANENT mapset in selected location in order to set default region (WIND) - envval = {} - cmdlist = ['g.gisenv'] - p = gcmd.Command(cmdlist) - if p.returncode == 0: - output = p.module_stdout.read().strip("'").split(';\n') - for line in output: - line = line.strip() - if '=' in line: key,val = line.split('=') - envval[key] = val - self.currlocation = envval['LOCATION_NAME'].strip("';") - self.currmapset = envval['MAPSET'].strip("';") - if self.currlocation == self.location and self.currmapset == 'PERMANENT': - pass - else: - cmdlist = ['g.mapset', 'location=%s' % self.location, 'mapset=PERMANENT'] - gcmd.Command(cmdlist) - else: - wx.MessageBox('A valid location must be selected') - return - - #Get current region settings - region = {} - cmdlist = ['g.region', '-gp'] - p = gcmd.Command(cmdlist) - if p.returncode == 0: - output = p.module_stdout.read().split('\n') - for line in output: - line = line.strip() - if '=' in line: key,val = line.split('=') - region[key] = float(val) - else: - wx.MessageBox('Invalid region') - return - - self.north = region['n'] - self.south = region['s'] - self.east = region['e'] - self.west = region['w'] - self.res = region['ewres'] - - # Insert current region settings into text controls - self.ttop.SetValue(str(self.north)) - self.tbottom.SetValue(str(self.south)) - self.tleft.SetValue(str(self.west)) - self.tright.SetValue(str(self.east)) - self.tres.SetValue(str(self.res)) - - # layout - self.sizer = rcs.RowColSizer() - - self.sizer.Add(self.MakeLLabel("Region extents and resolution:"), 3, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 10, row=0,col=0, colspan=2) - - self.sizer.Add(self.MakeRLabel("North"), 0, - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 0, row=1,col=2) - self.sizer.Add(self.ttop, 0, - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=2,col=2) - - self.sizer.Add(self.MakeRLabel("West"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 0, row=3,col=0) - self.sizer.Add(self.tleft, 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=3,col=1) - - self.sizer.Add(self.tright, 0, - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=3,col=3) - self.sizer.Add(self.MakeRLabel("East"), 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 0, row=3,col=4) - - self.sizer.Add(self.tbottom, 0, - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=4,col=2) - self.sizer.Add(self.MakeRLabel("South"), 0, - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 0, row=5,col=2) - - self.sizer.Add(self.MakeRLabel("Resolution"), 0, - wx.ALIGN_RIGHT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=6,col=1) - self.sizer.Add(self.tres, 0, - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=6,col=2) - - self.sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0, row=7, col=0, colspan=6) - - self.sizer.Add(self.bset, 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=8, col=3 ) - - self.sizer.Add(self.bcancel, 0, - wx.ALIGN_LEFT | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, 5, row=8, col=1 ) - - - self.SetSizer(self.sizer) - self.SetAutoLayout(True) - self.Layout() - - self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset) - self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel) - self.Bind(wx.EVT_TEXT, self.OnNorth, self.ttop) - self.Bind(wx.EVT_TEXT, self.OnSouth, self.tbottom) - self.Bind(wx.EVT_TEXT, self.OnEast, self.tright) - self.Bind(wx.EVT_TEXT, self.OnWest, self.tleft) - self.Bind(wx.EVT_TEXT, self.OnRes, self.tres) - - def MakeRLabel(self, text=""): - """Make right-aligned label""" - try: - if text[-1] != " ": - text += " " - except: - pass - return wx.StaticText(self, -1, text, style=wx.ALIGN_RIGHT) - - def MakeLLabel(self, text=""): - """Make left-aligned label""" - try: - if text[-1] != " ": - text += " " - except: - pass - return wx.StaticText(self, -1, text, style=wx.ALIGN_LEFT) - - def MakeTextCtrl(self,text='', size=(100,-1)): - """Generic text control""" - return wx.TextCtrl(self,-1, text, size=size) - - def MakeButton(self,text, size=(75,25)): - """Generic button""" - return wx.Button(self, -1, text, - style=wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, - size=size) - - def OnNorth(self,event): - self.north = event.GetString() - - def OnSouth(self, event): - self.south = event.GetString() - - def OnEast(self,event): - self.east = event.GetString() - - def OnWest(self,event): - self.west = event.GetString() - - def OnRes(self,event): - self.res = event.GetString() - - def OnSetButton(self,event=None): - cmdlist = ['g.region', '-sgpa', 'n=%s' % self.north, 's=%s' % self.south, \ - 'e=%s' % self.east, 'w=%s' % self.west, 'res=%s' % self.res] - p = gcmd.Command(cmdlist) - if p.returncode == 0: - output = p.module_stdout.read() - wx.MessageBox('New default region:\n%s' % output) - else: - wx.MessageBox('Setting default region failed\n%s %s' % \ - (p.module_stderr.read(),p.module_stdout.read())) - self.Destroy() - - def OnCancel(self, event): - self.Destroy() - -class GWizard: - """ - Start wizard here and finish wizard here - """ - - def __init__(self, parent, grassdatabase): - wizbmp = wx.Image(os.path.join(os.getenv("GISBASE"),"etc","wx","images","wizard.png"), wx.BITMAP_TYPE_PNG) - wizbmp.Rescale(250,600) - wizbmp = wizbmp.ConvertToBitmap() - - global coordsys - self.parent = parent - # get georeferencing information from tables in $GISBASE/etc - - # make projections dictionary - f = open(os.path.join(os.getenv("GISBASE"), "etc","projections"),"r") - self.projections = {} - for line in f.readlines(): - line = line.expandtabs(1) - line = line.strip() - if not line: - continue - if line == '' or line[0] == "#": - continue - proj,projdesc = line.split(":", 1) - proj = proj.strip() - projdesc = projdesc.strip() - self.projections[proj] = projdesc - f.close() - - f = open(os.path.join(os.getenv("GISBASE"), "etc","datum.table"),"r") - self.datums = {} - paramslist = [] - for line in f.readlines(): - line = line.expandtabs(1) - line = line.strip() - if not line: - continue - if line == '' or line[0] == "#": - continue - datum,info = line.split(" ", 1) - info = info.strip() - datumdesc,params = info.split(" ",1) - datumdesc = datumdesc.strip('"') - paramlist = params.split() - ellipsoid = paramlist.pop(0) - self.datums[datum] = (datumdesc,ellipsoid,paramlist) - f.close() - - # make datum transforms dictionary - f = open(os.path.join(os.getenv("GISBASE"), "etc","datumtransform.table"),"r") - self.transforms = {} - j = 1 - for line in f.readlines(): - transcode = 'T'+str(j) - line = line.expandtabs(1) - line = line.strip() - if not line: - continue - if line == '' or line[0] == "#": - continue - datum,rest = line.split(" ", 1) - rest = rest.strip('" ') - params,rest = rest.split('"', 1) - params = params.strip() - rest = rest.strip('" ') - try: - region,info = rest.split('"', 1) - info = info.strip('" ') - info = region+': '+info - except: - info = rest - self.transforms[transcode] = (datum,info,params) - j+=1 - f.close() - - # make ellipsiods dictionary - f = open(os.path.join(os.getenv("GISBASE"), "etc","ellipse.table"),"r") - self.ellipsoids = {} - for line in f.readlines(): - line = line.expandtabs(1) - line = line.strip() - if not line: - continue - if line == '' or line[0] == "#": - continue - ellipse,rest = line.split(" ", 1) - rest = rest.strip('" ') - desc,params = rest.split('"', 1) - desc = desc.strip('" ') - paramslist = params.split() - self.ellipsoids[ellipse] = (desc,paramslist) - f.close() - - # define wizard pages - self.wizard = wiz.Wizard(parent, -1, "Define new Location", - bitmap=wizbmp) - self.startpage = DatabasePage(self.wizard, self, grassdatabase) - self.csystemspage = CoordinateSystemPage(self.wizard, self) - self.projpage = ProjectionsPage(self.wizard, self) - self.projtypepage = ProjTypePage(self.wizard,self) - self.epsgpage = EPSGPage(self.wizard, self) - self.filepage = GeoreferencedFilePage(self.wizard, self) - self.datumpage = DatumPage(self.wizard, self) - self.ellipsepage = EllipsePage(self.wizard, self) - self.custompage = CustomPage(self.wizard, self) - self.sumpage = SummaryPage(self.wizard, self) - - - # Set the initial order of the pages - # it should follow the epsg line - self.startpage.SetNext(self.csystemspage) - - self.csystemspage.SetPrev(self.startpage) - self.csystemspage.SetNext(self.sumpage) - - self.projpage.SetPrev(self.csystemspage) - self.projpage.SetNext(self.projtypepage) - - self.projtypepage.SetPrev(self.projpage) - self.projtypepage.SetNext(self.datumpage) - - self.datumpage.SetPrev(self.projtypepage) - self.datumpage.SetNext(self.sumpage) - - self.ellipsepage.SetPrev(self.projtypepage) - self.ellipsepage.SetNext(self.sumpage) - - self.epsgpage.SetPrev(self.csystemspage) - self.epsgpage.SetNext(self.sumpage) - - self.filepage.SetPrev(self.csystemspage) - self.filepage.SetNext(self.sumpage) - - self.custompage.SetPrev(self.csystemspage) - self.custompage.SetNext(self.sumpage) - - self.sumpage.SetPrev(self.csystemspage) - - self.wizard.FitToPage(self.datumpage) - - self.location = None #New location created - - success = False - - if self.wizard.RunWizard(self.startpage): - success = self.onWizFinished() - if success == True: - self.location = self.startpage.location - dlg = wx.MessageDialog(self.wizard, - "Do you want to set the default region extents and resolution now?", - "New location '%s' created"% self.location, - wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_YES: - dlg.Destroy() - defineRegion = RegionDef(None, location=self.location) - defineRegion.Show() - else: - dlg.Destroy() - - else: - wx.MessageBox("Unable to create new location.") - else: - wx.MessageBox("Location wizard canceled. New location not created.") - -# self.wizard.Destroy() - - def onWizFinished(self): - database = self.startpage.grassdatabase - location = self.startpage.location - global coordsys - success = False - -# wx.MessageBox("finished database: %s, location: %s, coordsys: %s" % (database, location, coordsys)) - if os.path.isdir(os.path.join(database,location)): - dlg = wx.MessageDialog(self, "Could not create new location: %s already exists" - % os.path.join(database,location),"Could not create location", - wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - if coordsys == "xy": - success = self.XYCreate() - elif coordsys == "latlong": - rows = int(round((float(north)-float(south))/float(resolution))) - cols = int(round((float(east)-float(west))/float(resolution))) - cells = int(rows*cols) - success = self.LatlongCreate() - elif coordsys == "proj": - success = self.Proj4Create() - elif coordsys == 'custom': - success = self.CustomCreate() - elif coordsys == "epsg": - success = self.EPSGCreate() - elif coordsys == "file": - success = self.FileCreate() - - return success - - def XYCreate(self): - """ - Create an XY location - """ - database = self.startpage.grassdatabase - location = self.startpage.location - - dlg = wx.MessageDialog(self.wizard, "New XY location '%s' will be created (not projected or georeferenced)" - % location, - "Create new XY location?", - wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_NO: - dlg.Destroy() - return False - else: - dlg.Destroy() - - #Make location folder and PERMANT mapset - os.mkdir(os.path.join(database,location)) - os.mkdir(os.path.join(database,location,'PERMANENT')) - - #Make DEFAULT_WIND and WIND files - regioninfo = ['proj: 0', - 'zone: 0', - 'north: 1', - 'south: 0', - 'east: 1', - 'west: 0', - 'cols: 1', - 'rows: 1', - 'e-w resol: 1', - 'n-s resol: 1', - 'top: 1', - 'bottom: 0', - 'cols3: 1', - 'rows3: 1', - 'depths: 1', - 'e-w resol3: 1', - 'n-s resol3: 1', - 't-b resol: 1'] - - try: - defwind = open(os.path.join(database,location,"PERMANENT","DEFAULT_WIND"),'w') - for param in regioninfo: - defwind.write(param+'\n') - defwind.close() - shutil.copy(os.path.join(database,location,"PERMANENT","DEFAULT_WIND"),\ - os.path.join(database,location,"PERMANENT","WIND")) - - #Make MYNAME file - myname = open(os.path.join(database,location,"PERMANENT","MYNAME"),'w') - myname.write('') - myname.close() - return True - except: - return False - - def Proj4Create(self): - """ - Create a new location for selected projection - """ - - location = self.startpage.location - proj = self.projpage.proj - projdesc = self.projpage.projdesc - - utmzone = self.projtypepage.utmzone - utmhemisphere = self.projtypepage.utmhemisphere - - datum = self.datumpage.datum - if self.datumpage.datumdesc: - datumdesc = self.datumpage.datumdesc+' - '+self.datumpage.ellipsoid - else: datumdesc = '' - datumparams = self.datumpage.datumparams - transparams = self.datumpage.transparams - - ellipse = self.ellipsepage.ellipse - ellipsedesc = self.ellipsepage.ellipsedesc - ellipseparams = self.ellipsepage.ellipseparams - - # Creating PROJ.4 string - if proj == 'll': - proj = 'longlat' - - if proj == 'utm' and utmhemisphere == 'south': - proj4string = '+proj=%s +zone=%s +south' % (proj, utmzone) - elif proj == 'utm': - proj4string = '+proj=%s +zone=%s' % (proj, utmzone) - else: - proj4string = '+proj=%s ' % (proj) - - proj4params = '' - # set ellipsoid parameters - for item in ellipseparams: - if item[:4] == 'f=1/': - item = '+rf='+item[4:] - else: - item = '+'+item - proj4params = '%s %s' % (proj4params, item) - # set datum and transform parameters if relevant - if datumparams: - for item in datumparams: - proj4params = '%s +%s' % (proj4params,item) - if transparams: - proj4params = '%s +no_defs +%s' % (proj4params,transparams) - else: - proj4params = '%s +no_defs' % proj4params - else: - proj4params = '%s +no_defs' % proj4params - - proj4string = '%s %s' % (proj4string, proj4params) - - msgtext = "New location '%s' will be created georeferenced to" % location - georeftext = '%s: %s%s' % (projdesc,datumdesc,ellipsedesc) - p4text = '(PROJ.4 string: %s)' % proj4string - - dlg = wx.MessageDialog(self.wizard, msgtext+' '+georeftext+' '+p4text, - "Create new location?", - wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_NO: - dlg.Destroy() - return False - else: - dlg.Destroy() - - # Creating location from PROJ.4 string passed to g.proj - try: - cmdlist = ['g.proj', '-c', 'proj4=%s' % proj4string, 'location=%s' % location] - p = gcmd.Command(cmdlist) - if p.module.returncode == 0: - return True - else: - return False - - except StandardError, e: - dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - def CustomCreate(self): - proj4string = self.custompage.customstring - location = self.startpage.location - - dlg = wx.MessageDialog(self.wizard, "New location '%s' will be created using PROJ.4 string: %s" - % (location,proj4string), - "Create new location?", - wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_NO: - dlg.Destroy() - return False - else: - dlg.Destroy() - - try: - cmdlist = ['g.proj','-c','proj4=%s' % proj4string,'location=%s' % location] - p = gcmd.Command(cmdlist) - if p.module.returncode == 0: - return True - else: - return False - - except StandardError, e: - dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - - def EPSGCreate(self): - """ - Create a new location from an EPSG code. - """ - epsgcode = self.epsgpage.epsgcode - epsgdesc = self.epsgpage.epsgdesc - location = self.startpage.location - cmdlist = [] - - if not epsgcode: - dlg = wx.MessageDialog(self.wizard, "Could not create new location: EPSG Code value missing", - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - dlg = wx.MessageDialog(self.wizard, "New location '%s' will be created georeferenced to EPSG code %s: %s" - % (location, epsgcode, epsgdesc), - "Create new location from EPSG code?", - wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_NO: - dlg.Destroy() - return False - else: - dlg.Destroy() - - # creating location - try: - cmdlist = ['g.proj','epsg=%s' % epsgcode,'datumtrans=-1'] - p = gcmd.Command(cmdlist) - dtoptions = p.module_stdout.read() - if dtoptions != None: - dtrans = '' - # open a dialog to select datum transform number - dlg = wx.TextEntryDialog(self.wizard, dtoptions, - caption='Select the number of a datum transformation to use', - defaultValue='1', - style=wx.TE_WORDWRAP|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX| - wx.RESIZE_BORDER|wx.VSCROLL| - wx.OK|wx.CANCEL) - - if dlg.ShowModal() == wx.ID_CANCEL: - dlg.Destroy() - return False - else: - dtrans = dlg.GetValue() - if dtrans != '': - dlg.Destroy() - else: - wx.MessageBox('You must select a datum transform') - return False - - cmdlist = ['g.proj','-c','epsg=%s' % epsgcode,'location=%s' % location,'datumtrans=%s' % dtrans] - else: - cmdlist = ['g.proj','-c','epsg=%s' % epsgcode,'location=%s' % location,'datumtrans=1'] - - p = gcmd.Command(cmdlist) - if p.module.returncode == 0: - return True - else: - return False - - except StandardError, e: - dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - def FileCreate(self): - """ - Create a new location from a georeferenced file - """ - georeffile = self.filepage.georeffile - location = self.startpage.location - - cmdlist = [] - - dlg = wx.MessageDialog(self.wizard, "New location '%s' will be created georeferenced to file '%s'" - % (location, georeffile), "Create new location from georeferenced file?", - wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) - if dlg.ShowModal() == wx.ID_NO: - dlg.Destroy() - return False - else: - dlg.Destroy() - - if not os.path.isfile(georeffile): - dlg = wx.MessageDialog(self.wizard, "Could not create new location: could not find file %s" % georeffile, - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - if not georeffile: - dlg = wx.MessageDialog(self.wizard, "Could not create new location: georeferenced file not set", - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - - # creating location - try: - cmdlist = ['g.proj','-c','georef=%s' % georeffile,'location=%s' % location] - p = gcmd.Command(cmdlist) - if p.module.returncode == 0: - return True - else: - return False - - except StandardError, e: - dlg = wx.MessageDialog(self.wizard, "Could not create new location: %s " % str(e), - "Could not create location", wx.OK|wx.ICON_INFORMATION) - dlg.ShowModal() - dlg.Destroy() - return False - -if __name__ == "__main__": - gWizard = GWizard(None, "") - GRASSStartUp = GWizard.StartUp(0) - GRASSStartUp.MainLoop() - #app.MainLoop() Deleted: trunk/grassaddons/gui/states.txt =================================================================== --- trunk/grassaddons/gui/states.txt 2007-10-19 22:28:09 UTC (rev 1148) +++ trunk/grassaddons/gui/states.txt 2007-10-20 09:51:46 UTC (rev 1149) @@ -1,185 +0,0 @@ -Afghanistan; 59.9,28.66 75.65,39.11 -Africa; -20.2,-37.6 53.4,35.75 -Albania; 19.36,39.42 21.39,42.71 -Algeria; -9.47,17.94 13.19,38.14 -Angola; 11.31,-18.68 24.97,-3.84 -Antarctic; -180,-90 180,-66 -Antarctica; -180,-90 180,-62.83 -Arctic; -180,66 180,90 -Argentina; -74.97,-56.71 -51.76,-20.25 -Armenia; 43.53,38.68 47.07,41.48 -Asia; 40,-10 180,83.5 -Australia; 111.22,-45.73 155.72,-8.88 -Austria; 9.27,45.99 17.93,49.38 -Azerbaijan; 44.58,38.04 50.96,42.2 -Bangladesh; 87.95,20.75 93.07,26.62 -Belgium; 2.54,49.31 6.69,51.69 -Belize; -89.18,15.78 -87.78,18.64 -Benin; 0.74,5.97 4.34,12.66 -Bhutan; 88.8,26.54 92.37,28.46 -Bolivia; -70.05,-23.63 -56.72,-9.13 -Bosnia and Herzegovina; 15.76,42.38 20.02,45.45 -Botswana; 19.57,-27.41 29.94,-17.32 -Brazil; -75.64,-35.81 -32.74,7.12 -Brunei; 114.22,3.96 115.42,5.09 -Bulgaria; 22.19,40.86 29.02,44.59 -Burkina Faso; -5.72,9.19 2.98,15.54 -Burma; 91.41,9.22 102.13,29.34 -Burundi; 28.98,-4.85 31.17,-2.35 -Byelarus; 22.91,50.82 33.38,56.65 -Cambodia; 102.28,10.07 107.98,14.86 -Cameroon; 8.22,1.06 16.85,13.65 -Canada; -145.27,37.3 -48.11,87.61 -Caribbean; -91.4,27.36 -55.4,6.48 -Central African Republic; 13.96,1.5 28.11,11.67 -Central America; -94.1,21.8 -75.8,6.61 -Chad; 12.88,6.67 24.97,24.19 -Chile; -77.16,-56.79 -64.9,-15.72 -China; 70.83,15.06 137.97,56.58 -Colombia; -79.69,-5 -66.15,13.28 -Congo; 10.93,-5.41 19.19,3.98 -Costa Rica; -85.83,7.9 -82.18,11.38 -Croatia; 13.47,42.09 19.92,46.84 -Cuba; -85.03,19.36 -73.44,23.68 -Cyprus; 32.23,34.44 34.78,35.78 -Czech Republic; 12.13,48.23 19.38,51.42 -Denmark; 8.02,54.68 12.89,58 -Djibouti; 41.89,10.78 43.77,12.81 -Dominican Republic; -71.87,17.54 -67.99,20.12 -East Pacific Ocean; -180,64.8 -72.7,-75.6 -Ecuador; -81.08,-5.35 -74.68,1.72 -Egypt; 24.29,21.29 37.61,32.14 -El Salvador; -90.05,13.07 -87.41,14.6 -Equatorial Guinea; 8.39,0.76 11.59,3.82 -Eritrea; 36.31,12 43.58,18.41 -Estonia; 23.3,57.29 28.59,59.75 -Ethiopia; 32.49,2.63 48.85,15.56 -Europe; -25.1,71.3 35,34.9 -Finland; 20.46,59.3 32.14,70.44 -France; -5.29,40.65 10.4,51.82 -French Guiana; -54.37,1.84 -51.23,5.89 -Gabon; 8.71,-4.23 15.01,2.6 -Gambia; -16.71,13.02 -13.66,13.96 -Germany; 5.68,46.86 15.68,55.41 -Ghana; -3.31,4.39 1.7,11.47 -Greece; 19.99,34.62 27.19,42.01 -Greenland; -75.34,56.78 -9.36,86.6 -Guatemala; -92.24,13.59 -87.87,18.06 -Guinea; -15.19,6.77 -6.87,13.02 -Guinea-Bissau; -16.51,10.97 -13.34,12.8 -Guyana; -61.41,0.81 -56.12,8.79 -Haiti; -74.38,17.88 -71.34,20.1 -Honduras; -89.47,12.75 -82.92,16.31 -Hungary; 16.12,45.44 23.57,48.95 -Iceland; -24.55,62.81 -12.79,67.01 -India; 66.79,6.58 99.01,36.96 -Indian Ocean; 22.3,-55.4 119.5,25.2 -Indonesia; 93.11,-12.65 143.45,7.88 -Iran; 43.31,24.08 64.42,40.73 -Iraq; 38.47,28.5 49.25,37.84 -Ireland; -10.52,51.23 -5.62,55.49 -Israel; 34.17,29.25 36.09,33.31 -Italy; 6.11,36.15 19.33,47.71 -Ivory Coast; -8.64,4.03 -2.01,10.96 -Jamaica; -78.22,17.72 -76,18.63 -Japan; 128.74,30.1 146.46,46.26 -Jordan; 34.97,28.87 39.75,33.44 -Kazakhstan; 44.73,38.62 89.65,57.49 -Kenya; 33,-5.3 42.44,5.07 -Democratic People's Republic of Korea; 124.02,43.29 37.55,130.95 -Republic of Korea; 125.95,38.76 33.06,129.88 -Kuwait; 46.62,28.34 48.74,30 -Kyrgyzstan; 69.01,38.7 81.03,43.77 -Laos; 99.77,13.47 108.1,22.98 -Latvia; 20.76,55.32 28.76,58.44 -Lebanon; 35.09,32.84 36.79,34.63 -Lesotho; 27.16,-30.89 29.76,-28.59 -Liberia; -11.47,4.16 -6.95,8.66 -Libya; 8.79,18.7 26.1,33.95 -Lithuania; 20.86,53.6 27.25,56.73 -Luxembourg; 5.9,49.42 6.77,50.21 -Macedonia; 20.62,40.62 23.27,42.48 -Madagascar; 42.83,-26.31 51.38,-11.58 -Malawi; 32.55,-17.51 36.46,-9.26 -Malaysia; 99.4,-0.2 120.19,7.86 -Mali; -12.77,9.25 5.27,25.83 -Mauritania; -17.47,14.21 -4.04,27.81 -Mexico; -118.48,13.05 -85.18,34.17 -Middle East; 25,10.7 59.7,36.1 -Moldova; 26.64,45.31 30.47,48.64 -Mongolia; 86.47,40 121.62,53.65 -Montenegro; 18.56,41.77 20.67,43.64 -Morocco; -13.52,26.96 -0.28,36.48 -Mozambique; 29.67,-27.82 41.89,-9.63 -Namibia; 11.32,-29.61 25.86,-16.31 -Nepal; 79.9,26 88.84,30.88 -Netherlands; 3.54,50.56 7.62,53.59 -New Hampshire; -72.68,42.57 -70.58,45.43 -New Jersey; -75.69,38.8 -73.78,41.47 -New Mexico; -109.35,31.04 -102.7,37.3 -New Zealand; 166.05,-47.31 179.41,-33.89 -Nicaragua; -87.7,10.55 -82.87,15.24 -Niger; -0.39,10.95 16.95,24.28 -Nigeria; 2.33,3.72 15.34,14.4 -North America; -168.5,18 -50.4,85.7 -North Atlantic Ocean; -82,0 12,80 -Northern Temperate; -180,23 180,60 -Norway; 3.88,56.69 32.56,81.95 -Oman; 51.53,16.19 60.52,26.73 -Pakistan; 60.18,22.94 78.66,37.86 -Panama; -83.06,6.9 -76.63,9.95 -Papua New Guinea; 140.37,-11.3 153.05,-2.2 -Paraguay; -62.83,-27.85 -53.6,-18.87 -Peru; -82.13,-19.35 -67.52,0.79 -Philippines; 116.68,4.85 127.23,19.22 -Poland; 13.77,48.57 24.85,55.24 -Portugal; -9.6,36.75 -5.65,42.36 -Qatar; 50.97,24.33 51.89,26.17 -Romania; 20.05,43.29 30.38,48.76 -Russia; 25,23.21 180,71 -Rwanda; 28.9,-3.01 31.2,-1.03 -Saudi Arabia; 33.9,14.01 57.3,33.22 -Senegal; -17.53,12.02 -10.89,17.14 -Serbia; 18.8,41.66 23.35,46.39 -Sierra Leone; -13.16,6.71 -10.02,10.09 -Slovakia; 16.84,47.61 23.06,49.93 -Slovenia; 13.39,45.28 16.87,47.06 -Somalia; 40.53,-2.55 52.14,12.66 -South Africa; 13.68,-35.9 33.98,-21.27 -South America; -84.9,-57.6 -32.4,13.7 -South Atlantic Ocean; -67,-55.4 23,0 -Southern Ocean; -180,-77 180,-32 -Southern Temperate; -180,-60 180,-23 -Spain; -9.69,35.4 3.98,44.38 -Sri Lanka; 79.69,5.76 82.26,9.89 -Sudan; 21.06,2.6 39.77,22.86 -Suriname; -58.01,1.53 -53.42,6.23 -Swaziland; 30.93,-27.52 32.45,-25.72 -Sweden; 10.56,54.63 24.84,69.68 -Switzerland; 5.92,45.66 10.84,48.02 -Syria; 35.36,31.84 43.11,37.69 -Taiwan; 119.99,21.78 122.14,25.31 -Tajikistan; 67.34,36.34 75.59,41.46 -Tanzania United Republic of; 0,-0.54 28.96,41.23 -Thailand; 96.83,4.8 106.42,21.22 -Togo; -0.09,5.85 2.21,11.33 -Trinidad; -61.88,10.01 -60.86,10.89 -Tropics; -180,-23 180,23 -Tunisia; 7.38,29.87 12.03,37.65 -Turkey; 25.29,34.91 45.94,43 -Turkmenistan; 52.05,34.56 67.66,43.46 -Uganda; 29.45,-1.82 35.52,4.32 -Ukraine; 21.4,43.61 41.24,53.31 -United Arab Emirates; 51.06,21.82 56.87,26.25 -United Kingdom; -8.41,49.49 2.39,59.07 -United States; -180,13.71 -61.48,76.63 -Uruguay; -58.46,-35.26 -52.77,-29.97 -Uzbekistan; 55.44,36.08 74.31,46.46 -Venezuela; -73.81,-0.11 -58.91,12.92 -Vietnam; 101.43,7.75 110.25,24.05 -Virginia; -84.1,36.12 -74.82,39.88 -Western Sahara; -17.23,20.87 -8.01,28 -Yemen; 42.45,12.12 53.74,19.51 -Zaire; 11.45,-14.4 32.4,6.28 -Zambia; 21.55,-18.7 34.45,-7.69 -Zimbabwe; 25.11,-22.93 33.65,15.22 From landa at grass.itc.it Sat Oct 20 12:58:27 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:47 2007 Subject: [grass-addons] r1150 - in trunk/grassaddons/gui: . gui_modules icons Message-ID: <200710201058.l9KAwR2v026871@grass.itc.it> Author: landa Date: 2007-10-20 12:58:23 +0200 (Sat, 20 Oct 2007) New Revision: 1150 Modified: trunk/grassaddons/gui/README trunk/grassaddons/gui/gui_modules/grassenv.py trunk/grassaddons/gui/icons/icon.py Log: GRASS_ICONPATH must be given as GRASS variable. Modified: trunk/grassaddons/gui/README =================================================================== --- trunk/grassaddons/gui/README 2007-10-20 09:51:46 UTC (rev 1149) +++ trunk/grassaddons/gui/README 2007-10-20 10:58:23 UTC (rev 1150) @@ -125,10 +125,10 @@ * default (based on TCL/TK GUI prototype) * Silk -To enable 'Silk' icon theme set environment variable: +To enable 'Silk' icon theme set GRASS variable: -$ export GRASS_ICONPATH=$GISBASE/etc/wx/icons/silk +$ g.gisenv set=GRASS_ICONPATH=$GISBASE/etc/wx/icons/silk To re-enable default icons (TCL/TK theme) -$ unset GRASS_ICONPATH +$ g.gisenv set=GRASS_ICONPATH= Modified: trunk/grassaddons/gui/gui_modules/grassenv.py =================================================================== --- trunk/grassaddons/gui/gui_modules/grassenv.py 2007-10-20 09:51:46 UTC (rev 1149) +++ trunk/grassaddons/gui/gui_modules/grassenv.py 2007-10-20 10:58:23 UTC (rev 1150) @@ -17,16 +17,29 @@ import os import sys -gmpath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") -sys.path.append(gmpath) -import gcmd +try: + import subprocess +except: + CompatPath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "compat") + sys.path.append(CompatPath) + import subprocess + +# gmpath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") +# sys.path.append(gmpath) +# import gcmd def GetGRASSVariable(var): """Return GRASS variable or '' if variable is not defined""" - gisEnv = gcmd.Command(['g.gisenv']) + # gisEnv = gcmd.Command(['g.gisenv']) - for item in gisEnv.ReadStdOutput(): + gisEnv = subprocess.Popen(['g.gisenv'], + stdin=None, + stdout=subprocess.PIPE, + stderr=None, + close_fds=True) + + for item in gisEnv.stdout.readlines(): if var in item: return item.split('=')[1].replace("'",'').replace(';','').strip() - return '' + return None Modified: trunk/grassaddons/gui/icons/icon.py =================================================================== --- trunk/grassaddons/gui/icons/icon.py 2007-10-20 09:51:46 UTC (rev 1149) +++ trunk/grassaddons/gui/icons/icon.py 2007-10-20 10:58:23 UTC (rev 1150) @@ -22,9 +22,16 @@ import wx +gmPath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") +sys.path.append(gmPath) +import grassenv + +iconpath = grassenv.GetGRASSVariable('GRASS_ICONPATH') +if not iconpath: + iconpath = os.getenv("GRASS_ICONPATH") + iconpath_default = os.path.join(os.getenv("GISBASE"), "etc", "gui", "icons") iconpath_vdigit = os.path.join(os.getenv("GISBASE"), "etc", "v.digit") -iconpath = os.getenv("GRASS_ICONPATH") icons_default = { # map display From landa at grass.itc.it Sun Oct 21 00:16:51 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:47 2007 Subject: [grass-addons] r1151 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710202216.l9KMGpcR032474@grass.itc.it> Author: landa Date: 2007-10-21 00:16:46 +0200 (Sun, 21 Oct 2007) New Revision: 1151 Modified: trunk/grassaddons/gui/gui_modules/debug.py trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/toolbars.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/wxgui.py Log: Styled command output introduced (not fully functional, need to be fixed!) Various minor fixes... Modified: trunk/grassaddons/gui/gui_modules/debug.py =================================================================== --- trunk/grassaddons/gui/gui_modules/debug.py 2007-10-20 10:58:23 UTC (rev 1150) +++ trunk/grassaddons/gui/gui_modules/debug.py 2007-10-20 22:16:46 UTC (rev 1151) @@ -59,7 +59,7 @@ def msg (self, level, message): self._update_level() if self.debuglevel > 0 and level > 0 and level <= self.debuglevel: - print "GUI D%d/%d: %s" % (level, level, message) + print >> sys.stderr, "GUI D%d/%d: %s" % (level, level, message) # Debug instance Debug = DebugMsg() Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-20 10:58:23 UTC (rev 1150) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-20 22:16:46 UTC (rev 1151) @@ -31,9 +31,11 @@ sys.path.append(CompatPath) import subprocess -# debugging ... +# debugging & log window GuiModulePath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") sys.path.append(GuiModulePath) + +import wxgui_utils from debug import Debug as Debug class EndOfCommand(Exception): @@ -53,6 +55,7 @@ verbose - verbose mode [0; 3] wait - wait for childer execution dlgMsg - type of error message (None, gui, txt) [only if wait=True] + log - log window or None Usage: cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=True, wait=True) @@ -66,7 +69,8 @@ """ def __init__ (self, cmd, stdin=None, - verbose=0, wait=True, dlgMsg='gui'): + verbose=0, wait=True, dlgMsg='gui', + stdout=None, stderr=None): # # input # @@ -81,7 +85,11 @@ self.cmd.append('--q') elif verbose == 3 and '--v' not in self.cmd: self.cmd.append('--v') - + else: + verbosity = os.getenv("GRASS_VERBOSE") + os.environ["GRASS_VERBOSE"] = str(verbose) + if verbosity: + os.environ["GRASS_VERBOSE"] = verbosity # # GRASS module # @@ -97,7 +105,6 @@ # message_format = os.getenv("GRASS_MESSAGE_FORMAT") os.environ["GRASS_MESSAGE_FORMAT"] = "gui" - # os.environ["GRASS_MESSAGE_FORMAT"] = "txt" # # run command ... @@ -110,11 +117,25 @@ else: # Popen class (default) Debug.msg(4, "Command.__init__(): [Popen] cmd='%s'" % ' '.join(cmd)) + if stdout is None: + out = subprocess.PIPE + elif stdout == sys.stdout: + out = None + else: + out = stdout + + if stderr is None: + err = subprocess.PIPE + elif stderr == sys.stderr: + err = None + else: + err = stderr + self.module = subprocess.Popen(self.cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) + stdout=out, + stderr=err, + close_fds=False) # set up streams self.module_stdin = self.module.stdin self.module_stderr = self.module.stderr @@ -124,20 +145,16 @@ self.module_stdin.write(stdin) self.module_stdin.close() - if message_format: - os.environ["GRASS_MESSAGE_FORMAT"] = message_format - else: - os.unsetenv("GRASS_MESSAGE_FORMAT") - - # list of messages (<- stderr) - # -> [(type, content)] type = (error, warning, message) - self.module_msg = self.__ProcessStdErr() # -> self.module_msg - if self.module: if wait: self.module.wait() + + if stderr is None: + # list of messages (<- stderr) + # -> [(type, content)] type = (error, warning, message) + self.module_msg = self.__ProcessStdErr() # -> self.module_msg + self.returncode = self.module.returncode - # failed? if self.dlgMsg and self.returncode != 0: if self.dlgMsg == 'gui': # GUI dialog @@ -162,6 +179,11 @@ Debug.msg (3, "Command(): cmd='%s', wait=%d, returncode=?" % \ (' '.join(self.cmd), wait)) + if message_format: + os.environ["GRASS_MESSAGE_FORMAT"] = message_format + else: + os.unsetenv("GRASS_MESSAGE_FORMAT") + def __ProcessStdErr(self): """ Read messages/warnings/errors from stderr @@ -198,6 +220,10 @@ Note: Remove '\n' from output (TODO: '\r\n' ??) """ lineList = [] + + if stream is None: + return lineList + while True: line = stream.readline() if not line: Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-20 10:58:23 UTC (rev 1150) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-20 22:16:46 UTC (rev 1151) @@ -595,8 +595,9 @@ self.combo.SetValue ('Select vector map') # re-active layer - # TODO: if status doesn't change in layer tree... - self.mapcontent.ChangeLayerActive(layerSelected, True) + item = self.parent.tree.FindItemByData('maplayer', layerSelected) + if item and self.parent.tree.IsItemChecked(item): + self.mapcontent.ChangeLayerActive(layerSelected, True) self.parent.digit.SetMapName(None) Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-20 10:58:23 UTC (rev 1150) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-20 22:16:46 UTC (rev 1151) @@ -6,6 +6,9 @@ * Layer * LayerTree * GMConsole + * GMStdout + * GMStrerr + * GMStc PURPOSE: Utility classes for GRASS wxPython GUI. Main functions include tree control for GIS map layer management, command console, and command parsing. @@ -22,11 +25,15 @@ """ -import os,sys +import os +import sys +import string +import tempfile + import wx import wx.lib.customtreectrl as CT import wx.combo -import string +import wx.stc gmpath = os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ) sys.path.append(gmpath) @@ -346,7 +353,6 @@ Note: lcmd is given as a list """ self.first = True - checked = False params = {} # no initial options parameters # deselect active item @@ -360,7 +366,6 @@ ctrl = wx.TextCtrl(self, id=wx.ID_ANY, value='', pos=wx.DefaultPosition, size=(250,25), style=wx.TE_MULTILINE|wx.TE_WORDWRAP) - checked = True ctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged) ctrl.Bind(wx.EVT_TEXT, self.OnCmdChanged) elif ltype == 'group': @@ -368,7 +373,6 @@ ctrl = None grouptext = 'Layer group:' + str(self.groupnode) self.groupnode += 1 - checked = True else: # all other items (raster, vector, ...) ctrl = wx.SpinCtrl(self, id=wx.ID_ANY, value="", pos=(30, 50), @@ -398,8 +402,11 @@ # layer is initially unchecked as inactive (beside 'command') # use predefined value if given - if lchecked: + if lchecked is not None: checked = lchecked + else: + checked = True + self.CheckItem(layer, checked=checked) # select new item @@ -903,7 +910,7 @@ self.GetPyData(layer)[0]['propwin'] = propwin # check layer as active - self.CheckItem(layer, checked=True) + # self.CheckItem(layer, checked=True) # change parameters for item in layers list in render.Map self.ChangeLayer(layer) @@ -976,8 +983,28 @@ def OnCloseWindow(self, event): pass - # self.Map.Clean() + # self.Map.Clean() + def FindItemByData(self, key, value): + """Find item based on key and value (see PyData[0])""" + item = self.GetFirstChild(self.root)[0] + return self.__FindSubItemByData(item, key, value) + + def __FindSubItemByData(self, item, key, value): + """Support method for FindItemByValue""" + while item and item.IsOk(): + itemValue = self.GetPyData(item)[0][key] + if value == itemValue: + return item + if self.GetPyData(item)[0]['type'] == 'group': + subItem = self.GetFirstChild(item)[0] + found = self.__FindSubItemByData(subItem, key, value) + if found: + return found + item = self.GetNextSibling(item) + + return None + class GMConsole(wx.Panel): """ Create and manage output console for commands entered on the @@ -998,10 +1025,15 @@ self.gcmdlst = [] # list of commands in bin and scripts # text control for command output - self.cmd_output = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", - style=wx.TE_MULTILINE| wx.TE_READONLY) - self.cmd_output.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, '')) + # self.cmd_output = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", + # style=wx.TE_MULTILINE| wx.TE_READONLY) + # self.cmd_output.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, '')) + self.cmd_output = GMStc(parent=self, id=wx.ID_ANY) + # redirect + # sys.stdout = GMStdout(self.cmd_output) + # sys.stderr = GMStderr(self.cmd_output) + # buttons self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR) self.console_save = wx.Button(parent=self, id=wx.ID_SAVE) @@ -1081,7 +1113,7 @@ if cmdlist[0] in gcmdlst: # send GRASS command without arguments to GUI command interface # except display commands (they are handled differently) - if cmdlist[0][0:2] == "d.": + if cmdlist[0][0:2] == "d.": # display GRASS commands try: layertype = {'d.rast' : 'raster', 'd.rgb' : 'rgb', @@ -1098,46 +1130,27 @@ 'd.rhumbline' : 'rhumb', 'd.labels' : 'labels'}[cmdlist[0]] except KeyError: - print _('Command type not yet implemented') + wx.MessageBox(message=_("Command '%s' not yet implemented") % cmdlist[0]) return False # add layer self.parent.curr_page.maptree.AddLayer(ltype=layertype, lcmd=cmdlist) - else: - if len(cmdlist) > 1: - menuform.GUI().ParseCommand(cmdlist, parentframe=self, show=False) - else: - menuform.GUI().ParseCommand(cmdlist, parentframe=self, show=True) - - else: - # Send any other command to the shell. Send output to - # console output window. - - if self.parent.notebook.GetSelection() != 1: - # select 'Command output' tab - self.parent.notebook.SetSelection(1) - - self.cmd_output.write("$ " + ' '.join(cmdlist) + "\n") - - if cmdlist[0] not in gcmdlst: - # if command is not a GRASS command, treat it like a shell command - generalCmd = subprocess.Popen(cmdlist, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) + else: # other GRASS commands + if self.parent.notebook.GetSelection() != 1: + # select 'Command output' tab + self.parent.notebook.SetSelection(1) - for outline in runCmd.stdout: - self.cmd_output.write(outline) - else: # activate compuational region (set with g.region) for all non-display commands. tmpreg = os.getenv("GRASS_REGION") os.unsetenv("GRASS_REGION") # process GRASS command with argument - grassCmd = gcmd.Command(cmdlist, verbose=3) - + self.cmd_output.AddText('$ %s' % ' '.join(cmdlist)) + grassCmd = gcmd.Command(cmdlist, verbose=3, + stdout=GMStdout(self.cmd_output), + stderr=GMStderr(self.cmd_output)) # deactivate computational region and return to display settings if tmpreg: @@ -1149,9 +1162,25 @@ # if oline.find("GRASS_INFO_PERCENT")>-1: # self.console_progressbar.SetValue(int(oline.split()[1])) - for line in grassCmd.ReadStdOutput(): - self.cmd_output.write(line + '\n') - + else: + # Send any other command to the shell. Send output to + # console output window. + + if self.parent.notebook.GetSelection() != 1: + # select 'Command output' tab + self.parent.notebook.SetSelection(1) + + print "$ " + ' '.join(cmdlist) + + # if command is not a GRASS command, treat it like a shell command + generalCmd = subprocess.Popen(cmdlist, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + + for outline in generalCmd.stdout: + print outline + return True def ClearHistory(self, event): @@ -1183,3 +1212,119 @@ output.close() dlg.Destroy() + +class GMStdout: + """GMConsole standard output + + Based on FrameOutErr.py + + Name: FrameOutErr.py + Purpose: Redirecting stdout / stderr + Author: Jean-Michel Fauth, Switzerland + Copyright: (c) 2005-2007 Jean-Michel Fauth + Licence: GPL + """ + def __init__(self, gmstc): + self.gmstc = gmstc + self.buffer = tempfile.TemporaryFile(mode="w") + + def write(self, s): + # if not self.gmstc.GetParent().IsShown(): + # self.mystc.GetParent().Show() + + s = s.replace('\n', os.linesep) + p1 = self.gmstc.GetCurrentPos() # get caret position + self.gmstc.AddText(s) + self.gmstc.EnsureCaretVisible() + p2 = self.gmstc.GetCurrentPos() + self.gmstc.StartStyling(p1, 0xff) + self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleOutput) + + def fileno(self): + return self.buffer.fileno() + + def __del__(self): + self.buffer.flush() + self.buffer.seek(0,0) + for line in self.buffer.readlines(): + self.write(line) + +class GMStderr: + """GMConsole standard error output + + Based on FrameOutErr.py + + Name: FrameOutErr.py + Purpose: Redirecting stdout / stderr + Author: Jean-Michel Fauth, Switzerland + Copyright: (c) 2005-2007 Jean-Michel Fauth + Licence: GPL + """ + def __init__(self, gmstc): + self.gmstc = gmstc + self.buffer = tempfile.TemporaryFile(mode="w") + + def write(self, s): + # if self.gmstc.GetParent().IsShown() == False: + # self.gmstc.GetParent().Show() + + s = s.replace('\n', os.linesep) + p1 = self.gmstc.GetCurrentPos() + self.gmstc.AddText(s) + self.gmstc.EnsureCaretVisible() + p2 = self.gmstc.GetCurrentPos() + self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) + + def fileno(self): + return self.buffer.fileno() + + def __del__(self): + self.buffer.flush() + self.buffer.seek(0,0) + for line in self.buffer.readlines(): + self.write(line) + +class GMStc(wx.stc.StyledTextCtrl): + """Styled GMConsole + + Based on FrameOutErr.py + + Name: FrameOutErr.py + Purpose: Redirecting stdout / stderr + Author: Jean-Michel Fauth, Switzerland + Copyright: (c) 2005-2007 Jean-Michel Fauth + Licence: GPL + """ + def __init__(self, parent, id): + wx.stc.StyledTextCtrl.__init__(self, parent, id) + self.parent = parent + + # styles + self.StyleDefault = 0 + self.StyleDefaultSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF" + self.StyleOutput = 1 + self.StyleOutputSpec = "face:Courier New,size:10,fore:#0000FF,back:#FFFFFF" + self.StyleError = 2 + self.StyleErrorSpec = "face:Courier New,size:10,fore:#7F0000,back:#FFFFFF" + + # default and clear => init + self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, self.StyleDefaultSpec) + self.StyleClearAll() + self.StyleSetSpec(self.StyleOutput, self.StyleOutputSpec) + self.StyleSetSpec(self.StyleError, self.StyleErrorSpec) + + # margin widths + self.SetMarginWidth(0, 0) + self.SetMarginWidth(1, 0) + self.SetMarginWidth(2, 0) + + # miscellaneous, a few parameters + self.SetMarginLeft(2) + self.SetViewWhiteSpace(True) + self.SetTabWidth(4) + self.SetUseTabs(False) + #~ self.SetEOLMode(wx.stc.STC_EOL_CRLF) + #~ self.SetViewEOL(True) + self.UsePopUp(True) + self.SetSelBackground(True, "#FFFF00") + self.SetUseHorizontalScrollBar(True) Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-20 10:58:23 UTC (rev 1150) +++ trunk/grassaddons/gui/wxgui.py 2007-10-20 22:16:46 UTC (rev 1151) @@ -450,7 +450,7 @@ filename = '' if dlg.ShowModal() == wx.ID_OK: - filename = dlg.GetFilename() + filename = dlg.GetPath() if filename == '': return @@ -537,7 +537,7 @@ filename = '' if dlg.ShowModal() == wx.ID_OK: - filename = dlg.GetFilename() + filename = dlg.GetPath() if filename == '': return False From neteler at grass.itc.it Sun Oct 21 10:39:00 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Thu Oct 25 01:43:47 2007 Subject: [grass-addons] r1152 - in trunk/grassaddons: . i.points.auto i.points.auto/orig Message-ID: <200710210839.l9L8d0LK031452@grass.itc.it> Author: neteler Date: 2007-10-21 10:38:25 +0200 (Sun, 21 Oct 2007) New Revision: 1152 Added: trunk/grassaddons/i.points.auto/ trunk/grassaddons/i.points.auto/Makefile trunk/grassaddons/i.points.auto/TODO trunk/grassaddons/i.points.auto/analyze.c trunk/grassaddons/i.points.auto/ask.c trunk/grassaddons/i.points.auto/ask_mag.c trunk/grassaddons/i.points.auto/call.c trunk/grassaddons/i.points.auto/cell.c trunk/grassaddons/i.points.auto/cellhd.c trunk/grassaddons/i.points.auto/colors.c trunk/grassaddons/i.points.auto/conv.c trunk/grassaddons/i.points.auto/curses.c trunk/grassaddons/i.points.auto/debug.c trunk/grassaddons/i.points.auto/defs.h trunk/grassaddons/i.points.auto/description.html trunk/grassaddons/i.points.auto/digit.c trunk/grassaddons/i.points.auto/dot.c trunk/grassaddons/i.points.auto/drawcell.c trunk/grassaddons/i.points.auto/driver.c trunk/grassaddons/i.points.auto/equ.c trunk/grassaddons/i.points.auto/find.c trunk/grassaddons/i.points.auto/find_points.c trunk/grassaddons/i.points.auto/find_points_semi.c trunk/grassaddons/i.points.auto/georef.c trunk/grassaddons/i.points.auto/globals.h trunk/grassaddons/i.points.auto/graphics.c trunk/grassaddons/i.points.auto/group.c trunk/grassaddons/i.points.auto/input.c trunk/grassaddons/i.points.auto/line.c trunk/grassaddons/i.points.auto/local_proto.h trunk/grassaddons/i.points.auto/main.c trunk/grassaddons/i.points.auto/mark.c trunk/grassaddons/i.points.auto/mouse.c trunk/grassaddons/i.points.auto/orig/ trunk/grassaddons/i.points.auto/orig/find_points_semi.c.org trunk/grassaddons/i.points.auto/orig/globals.h.org trunk/grassaddons/i.points.auto/overlap_area.c trunk/grassaddons/i.points.auto/points.c trunk/grassaddons/i.points.auto/target.c trunk/grassaddons/i.points.auto/title.c trunk/grassaddons/i.points.auto/view.c trunk/grassaddons/i.points.auto/where.c trunk/grassaddons/i.points.auto/zoom.c trunk/grassaddons/i.points.auto/zoom_box.c trunk/grassaddons/i.points.auto/zoom_pnt.c Log: new module for semi-automated image registration based on FFT correlation Added: trunk/grassaddons/i.points.auto/Makefile =================================================================== --- trunk/grassaddons/i.points.auto/Makefile (rev 0) +++ trunk/grassaddons/i.points.auto/Makefile 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,10 @@ +MODULE_TOPDIR = ../.. + +PGM = i.points.auto + +LIBES = $(IMAGERYLIB) $(GMATHLIB) $(D_LIB) $(DISPLAYLIB) $(RASTERLIB) $(GISLIB) $(VASKLIB) $(CURSES) $(FFTWLIB) +DEPENDENCIES= $(IMAGERYDEP) $(GMATHDEP) $(D_DEP) $(DISPLAYDEP) $(RASTERDEP) $(GISDEP) $(VASKDEP) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd Property changes on: trunk/grassaddons/i.points.auto/Makefile ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/TODO =================================================================== --- trunk/grassaddons/i.points.auto/TODO (rev 0) +++ trunk/grassaddons/i.points.auto/TODO 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,5 @@ +Compile with + make MODULE_TOPDIR=$HOME/grass63/ + +This code is basically an improved i.points (from 2004). +Further changes in i.points haven's been ported here yet. Added: trunk/grassaddons/i.points.auto/analyze.c =================================================================== --- trunk/grassaddons/i.points.auto/analyze.c (rev 0) +++ trunk/grassaddons/i.points.auto/analyze.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,935 @@ +#include +#include +#include +#include +#include +#include "globals.h" +#include "local_proto.h" +#define NLINES 18 +struct box +{ + int top, bottom, left,right; +}; + +static int uparrow ( struct box *,int); +static int downarrow ( struct box *,int) ; +static int pick(int,int); +static int done(void); +static int cancel_which(void); +static int inbox (struct box *,int,int); +static int dotext (char *,int,int,int,int,int,int); +static int compute_transformation(void); +static int to_file(void); +static int askfile(void); +static int to_printer(void); +static int do_report ( FILE *); +static int printcentered(FILE *,char *,int); +static int show_point(int,int); +static int offsetx, offsety; +static int n_old; +static int which; +static struct box more, less, report,box_lines, box_points; +static int height, size, edge, nlines; +static int curp, first_point; +static double rms,l_rms; +static double *xres, *yres, *gnd, *tres, *ures, *lgnd; +static int pager; +static int xmax, ymax, gmax; +static int tmax, umax, lgmax; +static char buf[300]; +int new_control_line (Lines *ln,double t1,double u1,double t2,double u2,int status); +Lines lines; /* contiene t ed u delle rette inserite */ +int use_points=1; +int top, bottom, left, right, width, middle, nums; +int count =0, first_line=0; +#define FMT0(buf,n) \ + sprintf (buf, "%3d ", n) +#define FMT1(buf,xres,yres,gnd) \ + sprintf (buf, "%5.1f %5.1f %6.1f ", xres,yres,gnd) +#define LHEAD1 " error " +#define LHEAD2 " # col row target" +#define LLINEHEAD2 " # dt du target" + +#define FMT2(buf,e1,n1,e2,n2) \ + sprintf (buf, "%9.1f %9.1f %9.1f %9.1f ", e1,n1,e2,n2) +#define RHEAD1 " image target" +#define RHEAD2 " east north east north" +#define RLINEHEAD2 " t1 u1 t2 u2 " + +#define BACKGROUND WHITE + +int +analyze (void) +{ + + double t_temp1,u_temp1, t_temp2, u_temp2; + + static int use = 1; + + static Objects objects[]= + { + MENU(" DONE ", done, &use), + MENU(" PRINT ", to_printer, &use), + MENU(" FILE ", to_file, &use), + INFO(" Double click on point to be included/excluded ", &use), + OTHER(pick,&use), + {0} + }; + + int color; + int tsize; + int cury; + int len; + int line; + int i; +/* to give user a response of some sort */ + if (group.points.count ==0) + return 0; + + + Menu_msg ("Preparing analysis ..."); + +/* + * build a popup window at center of the screen. + * 35% the height and wide enough to hold the report + * + */ + + /* height of 1 line, based on NLINES taking up 35% vertical space */ + height = (.35 * (SCREEN_BOTTOM - SCREEN_TOP))/NLINES + 1; + use_points=1; +/* size of text, 80% of line height */ + tsize = .8 * height; + size = tsize-2; /* fudge for computing pixels width of text */ + +/* indent for the text */ + edge = .1 * height + 1; + +/* determine the length, in chars, of printed line */ + FMT0 (buf,0); + nums = strlen(buf) * size; + FMT1 (buf, 0.0, 0.0, 0.0); + len = strlen(buf); + middle = len * size; + FMT2 (buf, 0.0, 0.0, 0.0, 0.0); + len += strlen(buf) ; + +/* width is for max chars plus sidecar for more/less */ + R_standard_color (WHITE); + width = len * size + nums + 2*height; + if ((SCREEN_RIGHT - SCREEN_LEFT) < width) + width = SCREEN_RIGHT - SCREEN_LEFT; + + +/* define the window */ + + //bottom = VIEW_MENU->top-1; + //top = bottom - height*NLINES; + + bottom = height*NLINES; + top = 0; + + + left = SCREEN_LEFT; + right = left + width; + middle += left + nums; + nums += left; + +/* save what is under this area, so it can be restored */ + R_panel_save (tempfile1, top, bottom, left, right); + + +/* fill it with white */ + R_standard_color (WHITE); + R_box_abs (left, top, right, bottom); + + right -= 2*height; /* reduce it to exclude sidecar */ + +/* print messages in message area */ + R_text_size (tsize, tsize); + + +/* setup the more/less boxes in the sidecar */ + R_standard_color (BLUE); + less.top = top; + less.bottom = top + 2*height; + less.left = right; + less.right = right + 2*height; + Outline_box (less.top, less.bottom, less.left, less.right); + + more.top = bottom - 2*height; + more.bottom = bottom; + more.left = right; + more.right = right + 2*height; + Outline_box (more.top, more.bottom, more.left, more.right); + +/* + * top two lines are for column labels + * last two line is for overall rms error. + */ + nlines = NLINES - 4; + first_point = 0; + +/* allocate predicted values */ + xres = (double *) G_calloc (group.points.count, sizeof (double)); + yres = (double *) G_calloc (group.points.count, sizeof (double)); + gnd = (double *) G_calloc (group.points.count, sizeof (double)); + + + i=0; + while(group.points.status[i]!=1 && i < group.points.count) + i++; + if(i >=group.points.count && group.points.status[i]!=1) + i=0; +offsetx = group.points.e2[i] - group.points.e1[i]; +offsety = group.points.n2[i] - group.points.n1[i]; + + +lines.count=0; + for (i=0; i < group.points.count; i++) + { + if (group.points.status[i] == 2 || group.points.status[i] == -2) + { + points_to_line (group.points.e1[i], group.points.n1[i],group.points.e1[i+1], group.points.n1[i+1],&t_temp1,&u_temp1); + points_to_line (group.points.e2[i]- offsetx, group.points.n2[i]-offsety,group.points.e2[i+1]-offsetx, group.points.n2[i+1]-offsety,&t_temp2,&u_temp2); + + sprintf (buf, "t2[0] e u2[0].... %f %f \n",10000*t_temp2,10000*u_temp2 ); + Curses_write_window (INFO_WINDOW, 3+ i, 2, buf); + + + new_control_line ( &lines,10000*t_temp1,10000*u_temp1,10000*t_temp2,10000*u_temp2,group.points.status[i]); + } + } + + tres = (double *) G_calloc (lines.count, sizeof (double)); + ures = (double *) G_calloc (lines.count, sizeof (double)); + lgnd = (double *) G_calloc (lines.count, sizeof (double)); + + /* compute transformation for the first time */ + compute_transformation(); + + + /* put head on the report */ + + box_points.top=top; + box_points.bottom=top+height-1; + box_points.left= left; + box_points.right=(right-left)/2; + dotext (" ANALYZE -> POINTS",top, top+height, left, (right-left)/2, 0, RED); + Outline_box (box_points.top, box_points.bottom, box_points.left, box_points.right); + + box_lines.top=top; + box_lines.bottom=top+height-1; + box_lines.left= ((right- left)/2)+1; + box_lines.right=right; + dotext (" ANALYZE -> LINES",top, top+height, ((right-left)/2)+1, right, 0, BLACK); + Outline_box (box_lines.top, box_lines.bottom, box_lines.left, box_lines.right); + + cury=top; + cury = top+height; + dotext (LHEAD1, cury, cury+height, left, middle, 0, BLACK); + dotext (RHEAD1, cury, cury+height, middle, right-1, 0, BLACK); + cury += height; + dotext (LHEAD2, cury, cury+height, left, middle, 0, BLACK); + dotext (RHEAD2, cury, cury+height, middle, right-1, 0, BLACK); + + cury += height; + R_move_abs (left, cury-1); + R_cont_abs (right, cury-1); + +/* isolate the sidecar */ + R_standard_color (BLACK); + R_move_abs (right, top); + R_cont_abs (right, bottom); + +/* define report box */ + report.top = cury; + report.left = left; + report.right = right; + count = 0; + first_line = 0; + +/* lets do it */ + pager = 1; + while(1) + { + R_text_size (tsize, tsize); + line = 0; + curp = first_point; + cury = top + 3*height; + count=0; + while(1) + { + if (line >= nlines || curp >= group.points.count) + break; + if(group.equation_stat > 0 && group.points.status[curp]==1) + { + if(use_points) + { + color = BLUE; + FMT1(buf, xres[curp], yres[curp], gnd[curp]); + if (curp == xmax || curp == ymax || curp == gmax) + color = RED; + dotext (buf, cury, cury+height, nums, middle, 0, color); + line++; + cury += height; + } + } + else if(group.points.status[curp] ==2) + { + /* if(group.points.status[curp+1]!=3) + break;*/ + if(!use_points) + { + color = BLUE; + if (count+first_line == tmax || count+first_line == umax || count+first_line == lgmax) + color = RED; + sprintf (buf, "%5.1f %5.1f %5.1f ", tres[count+ first_line],ures[count+first_line],lgnd[count+first_line]); + dotext (buf, cury, cury+height, nums, middle, 0, color); + line++; + cury += height; + } + + curp++; + } + else if (group.points.status[curp] > 0) + { + FMT0 (buf, curp+1-count); + dotext (buf, cury, cury+height, left, nums, 0, BLACK); + FMT2(buf, + group.points.e1[curp], + group.points.n1[curp], + group.points.e2[curp], + group.points.n2[curp]); + dotext (buf, cury, cury+height, middle, right-1, 0, BLACK); + dotext ("?", cury, cury+height, nums, middle, 1, BLACK); + line++; + cury += height; + } + + else if (group.points.status[curp] == -2 ) + { + if(group.points.status[curp+1]!=-3) + break; + if (!use_points) + { + dotext ("not used", cury, cury+height, nums, middle, 1, BLUE); + line++; + cury += height; + } + curp++; + } + else if (use_points) + { + dotext ("not used", cury, cury+height, nums, middle, 1, BLACK); + line++; + cury += height; + } + if (pager) + { + if(use_points &&( group.points.status[curp]==1 || group.points.status[curp]==0)) + { + + FMT0 (buf, curp+1-2*(first_line+count)); + dotext (buf, cury-height, cury, left, nums, 0, BLACK); + FMT2(buf, + group.points.e1[curp], + group.points.n1[curp], + group.points.e2[curp], + group.points.n2[curp]); + dotext (buf, cury-height, cury, middle, right-1, 0, BLACK); + } + if(!use_points &&( group.points.status[curp]>1 || group.points.status[curp]<-1)) + { + FMT0 (buf, first_line + count); + dotext (buf, cury-height, cury, left, nums, 0, BLACK); + sprintf (buf, "%9.1f %9.1f %9.1f %9.1f ", + lines.t1[first_line+count], + lines.u1[first_line+count], + lines.t2[first_line+count], + lines.u2[first_line+count]); + dotext (buf, cury-height, cury, middle, right-1, 0, BLACK); + + } + } + if( group.points.status[curp]>1 || group.points.status[curp]<-1) + count++; + curp++; + } + report.bottom = cury; + if(use_points) + { + downarrow (&more, ((group.points.count-curp)-2*(lines.count-(count+first_line)))>0 ? BLACK : BACKGROUND); + uparrow (&less, first_point > 0 ? BLACK : BACKGROUND); + } + if(!use_points) + { + downarrow (&more, (lines.count-(count+first_line))>0 ? BLACK : BACKGROUND); + uparrow (&less, first_point > 0 ? BLACK : BACKGROUND); + } + + R_standard_color (BACKGROUND); + R_box_abs (left, cury, right-1, bottom); + if(use_points) { + if (group.equation_stat < 0) + { + color = RED; + strcpy (buf, "Poorly placed control points"); + } + else if (group.equation_stat == 0) + { + color = RED; + strcpy (buf, "No active control points"); + } + else + { + color = BLACK; + sprintf (buf, "Overall rms error: %.2f", rms); + } + } + else + { + if (lines.line_stat < 0) + { + color = RED; + strcpy (buf, "Poorly placed control points"); + } + else if (lines.line_stat == 0) + { + color = RED; + strcpy (buf, "No active control points"); + } + else + { + color = BLACK; + sprintf (buf, "Overall rms error: %.2f", l_rms); + } + } + dotext (buf, bottom-height, bottom, left, right-1, 0, color); + R_standard_color (BLACK); + R_move_abs (left, bottom-height); + R_cont_abs (right-1, bottom-height); + + pager = 0; + which = -1; + if(Input_pointer(objects) < 0) + break; + + + + } + + /* all done. restore what was under the window */ + right += 2*height; /* move it back over the sidecar */ + R_standard_color (BACKGROUND); + R_box_abs (left, top, right, bottom); + R_panel_restore (tempfile1); + R_panel_delete (tempfile1); + R_flush(); + + free (xres); free (yres); free (gnd); + I_put_control_points (group.name, &group.points); + display_points(1); + return 0; /* return but don't QUIT */ +} + + +static int uparrow (struct box *box, int color) +{ + R_standard_color (BLACK); + Uparrow (box->top+edge, box->bottom-edge, box->left+edge, box->right-edge); + + return 0; +} + +static int downarrow(struct box *box, int color) +{ + R_standard_color (BLACK); + Downarrow (box->top+edge, box->bottom-edge, box->left+edge, box->right-edge); + + return 0; +} + +static int pick(int x,int y) +{ + int n; + int cur; + int i; + + cur = which; + cancel_which(); + if (inbox(&more,x,y)) + { + if (use_points && ((group.points.count-curp)-2*(lines.count-(count+first_line)))<=0) + return 0; + if(!use_points && (lines.count-(count+first_line))<=0) + return 0; + first_point = curp; + first_line +=count; + pager = 1; + return 1; + } + if (inbox(&box_points,x,y)) + { + R_text_size (.8*height, .8*height); + use_points=1; + dotext (" ANALYZE -> POINTS",top, top+height, left, (right-left)/2, 0, RED); + dotext (" ANALYZE -> LINES",top, top+height,((right-left)/2)+1, right, 0, BLACK); + Outline_box (box_points.top, box_points.bottom, box_points.left, box_points.right); + Outline_box (box_lines.top, box_lines.bottom, box_lines.left, box_lines.right); + dotext (LHEAD2, top+2*height, top+3*height, left, middle, 0, BLACK); + dotext (RHEAD2, top+2*height, top+3*height, middle, right-1, 0, BLACK); + first_point = 0; + first_line = 0; + pager = 1; + return 1; + } + if (inbox(&box_lines,x,y)) + { + R_text_size (.8*height, .8*height); + use_points=0; + dotext (" ANALYZE -> LINES",top, top+height, ((right-left)/2)+1, right, 0, RED); + dotext (" ANALYZE -> POINTS",top, top+height, left, (right-left)/2, 0, BLACK); + Outline_box (box_points.top, box_points.bottom, box_points.left, box_points.right); + Outline_box (box_lines.top, box_lines.bottom, box_lines.left, box_lines.right); + dotext (LLINEHEAD2, top+2*height, top+3*height, left, middle, 0, BLACK); + dotext (RLINEHEAD2, top+2*height, top+3*height, middle, right-1, 0, BLACK); + first_point = 0; + first_line = 0; + pager = 1; + return 1; + } + if (inbox(&less,x,y)) + { + if (first_point == 0) + return 0; + first_point = 0; + first_line = 0; + pager = 1; + return 1; + } + if (!inbox (&report,x,y)) + { + return 0; + } + + n_old = n = (y - report.top)/height; + i=0; + if(use_points){ + for (i; i<=n; i++) + if (group.points.status[first_point + i]==2||group.points.status[first_point + i]==-2) n+=2; + } + else { while (n>=0) { + if (group.points.status[first_point + i]==2||group.points.status[first_point + i]==-2) { + n--; + i++; + } + i++; + } + n=i-2; + } + if (n == cur) /* second click! */ + { + if (group.points.status[first_point +n]==2||group.points.status[first_point +n]==-2) { + group.points.status[first_point+n] = -group.points.status[first_point+n]; + group.points.status[first_point+(n+1)] = -group.points.status[first_point+(n+1)]; + lines.status[first_line + n_old] = - lines.status[first_line + n_old]; + } + + else + group.points.status[first_point+n] = !group.points.status[first_point+n]; + compute_transformation(); + show_point (first_point+n, 1); + + + return 1; + } + which = n; + show_point (first_point+n, 0); + R_standard_color (RED); + Outline_box (report.top + n*height, report.top +(n+1)*height, + report.left, report.right-1); + return 0; /* ignore first click */ + +} + +static int done (void) +{ + cancel_which(); + return -1; +} + +static int cancel_which (void) +{ + if (which >= 0) + { + R_standard_color (BACKGROUND); + Outline_box (report.top + which*height, report.top +(which+1)*height, + report.left, report.right-1); + show_point (first_point+which, 1); + } + which = -1; + + return 0; +} + +static int inbox (struct box *box,int x,int y) +{ + return (x>box->left && x right && y>box->top && ybottom); +} + +static int dotext (char *text, + int top,int bottom,int left,int right,int centered,int color) +{ + R_standard_color (BACKGROUND); + R_box_abs (left, top, right, bottom); + R_standard_color (color); + R_move_abs (left+1+edge, bottom-1-edge); + if (centered) + R_move_rel ((right-left-strlen(text)*size)/2,0); + R_set_window (top, bottom, left, right); /* for text clipping */ + R_text (text); + R_set_window (SCREEN_TOP, SCREEN_BOTTOM, SCREEN_LEFT, SCREEN_RIGHT); + + return 0; +} + +static int compute_transformation (void) +{ + int n, count; + double d,d1,d2,sum; + double e1, e2, n1, n2; + double t1, t2, u1, u2; + double xval, yval, gval; + double tval, uval, lgval; + + xmax = ymax = gmax = 0; + xval = yval = gval = 0.0; + + Compute_equation(); /*trova gli A,B,C che legano punti dell'image a punti del ltarget */ + lines.line_stat = compute_georef_equations_lp(&lines); + + if (group.equation_stat <= 0 && lines.line_stat<=0) return 1; + +/* compute the row,col error plus ground error + * keep track of largest and second largest error + */ + sum = 0.0; + rms = 0.0; + count = 0; + for (n = 0; n < group.points.count && group.equation_stat>0; n++) + { + if (group.points.status[n] !=1) continue; + count++; + georef (group.points.e2[n], group.points.n2[n], &e1, &n1, group.E21, group.N21); + georef (group.points.e1[n], group.points.n1[n], &e2, &n2, group.E12, group.N12); + + if((d = xres[n] = e1-group.points.e1[n]) < 0) + d = -d; + if (d > xval) + { + xmax = n; + xval = d; + } + + if ((d = yres[n] = n1-group.points.n1[n]) < 0) + d = -d; + if (d > yval) + { + ymax = n; + yval = d; + } + +/* compute ground error (ie along diagonal) */ + d1 = e2 - group.points.e2[n]; + d2 = n2 - group.points.n2[n]; + d = d1*d1 + d2*d2; + sum += d; /* add it to rms sum, before taking sqrt */ + d = sqrt(d); + gnd[n] = d; + if (d > gval) /* is this one the max? */ + { + gmax = n; + gval = d; + } + + } +/* compute overall rms error */ + if (count) + rms = sqrt (sum/count); + + count =0; + tmax = umax = lgmax = 0; + tval = uval = lgval = 0.0; + sum = 0.0; + l_rms = 0.0; + for (n = 0; n < lines.count && lines.line_stat>0 ; n++) + { + if (lines.status[n] !=2) continue; + count++; + georef (lines.t2[n], lines.u2[n], &t1, &u1, lines.E21, lines.N21); + georef (lines.t1[n], lines.u1[n], &t2, &u2, lines.E12, lines.N12); + if((d = tres[n] = t1- lines.t1[n]) < 0) + d = -d; + if (d > tval) + { + tmax = n; + tval = d; + } + + if ((d = ures[n] = u1- lines.u1[n]) < 0) + d = -d; + if (d > uval) + { + umax = n; + uval = d; + } + +/* compute ground error (ie along diagonal) */ + d1 = t2 - lines.t2[n]; + d2 = u2 - lines.u2[n]; + d = d1*d1 + d2*d2; + sum += d; /* add it to rms sum, before taking sqrt */ + d = sqrt(d); + lgnd[n] = d; + if (d > lgval) /* is this one the max? */ + { + lgmax = n; + lgval = d; + } + + } + if (count) + l_rms = sqrt (sum/count); + + + + return 0; +} + +static int to_file (void) +{ + FILE *fd; + char msg[1024]; + + cancel_which(); + if (Input_other (askfile, "Keyboard") < 0) + { + return 0; + } + + fd = fopen (buf, "w"); + if (fd == NULL) + { + sprintf (msg, "** Unable to create file %s\n", buf); + Beep(); + Curses_write_window (PROMPT_WINDOW, 2, 1, msg); + } + else + { + do_report (fd); + fclose (fd); + sprintf (msg, "Report saved in file %s\n", buf); + Curses_write_window (PROMPT_WINDOW, 2, 1, msg); + } + return 0; +} + +static int askfile (void) +{ + char file[100]; + + while (1) + { + Curses_prompt_gets ("Enter file to hold report: ", file); + G_strip (file); + if (*file == 0) return -1; + if (G_index (file, '/')) + strcpy (buf, file); + else + sprintf (buf, "%s/%s", G_home(), file); + if (access (buf, 0) != 0) + return 1; + sprintf (buf, "** %s already exists. choose another file", file); + Beep(); + Curses_write_window (PROMPT_WINDOW, 2, 1, buf); + } + + return 0; +} + +static int to_printer (void) +{ + FILE *fd; + cancel_which(); + Menu_msg ("sending report to printer ..."); + + fd = popen ("lpr", "w"); + do_report (fd); + pclose (fd); + return 0; +} + +static int do_report ( FILE *fd) +{ + char buf[100]; + int n; + int width; + + fprintf (fd, "LOCATION: %-20s GROUP: %-20s MAPSET: %s\n\n", + G_location(), group.name, G_mapset()); + fprintf (fd, "%15sAnalysis of control point registration\n\n", ""); + fprintf (fd, "%s %s\n", LHEAD1, RHEAD1); + fprintf (fd, "%s %s\n", LHEAD2, RHEAD2); + + FMT1 (buf,0.0,0.0,0.0); + width = strlen (buf); + + for (n = 0; n < group.points.count; n++) + { + FMT0(buf,n+1); + fprintf (fd, "%s", buf); + if(group.equation_stat > 0 && group.points.status[n] > 0) + { + FMT1(buf, xres[n], yres[n], gnd[n]); + fprintf (fd, "%s", buf); + } + else if (group.points.status[n] > 0) + printcentered (fd, "?", width); + else + printcentered (fd, "not used", width); + FMT2(buf, + group.points.e1[n], + group.points.n1[n], + group.points.e2[n], + group.points.n2[n]); + fprintf (fd, " %s\n", buf); + } + fprintf (fd, "\n"); + if (group.equation_stat < 0) + fprintf (fd, "Poorly place control points\n"); + else if (group.equation_stat == 0) + fprintf (fd, "No active control points\n"); + else + fprintf (fd, "Overall rms error: %.2f\n", rms); + + return 0; +} + +static int printcentered (FILE *fd, char *buf,int width) +{ + int len; + int n; + int i; + + len = strlen (buf); + n = (width -len)/2; + + for (i = 0; i < n; i++) + fprintf (fd, " "); + fprintf (fd, "%s", buf); + i += len; + while (i++ < width) + fprintf (fd, " "); + + return 0; +} + +static int show_point(int n,int true_color) +{ + int x_temp[2], y_temp[2]; + int row,col; + + if (!true_color) + R_standard_color (ORANGE); + else if(group.points.status[n]>0) + R_standard_color (GREEN); + else + R_standard_color (RED); + + + /* Display red_points in VIEW_MAP1_ZOOM */ + + if (group.points.status[n]==0 || group.points.status[n] == 1 ) + display_one_point (VIEW_MAP1_ZOOM, group.points.e1[n], group.points.n1[n]); + else + { + display_one_point (VIEW_MAP1_ZOOM, group.points.e1[n], group.points.n1[n]); + display_one_point (VIEW_MAP1_ZOOM, group.points.e1[n+1], group.points.n1[n+1]); + row = northing_to_row (&VIEW_MAP1_ZOOM->cell.head, group.points.n1[n]) + .5; + col = easting_to_col (&VIEW_MAP1_ZOOM->cell.head, group.points.e1[n]) + .5; + y_temp[0] = row_to_view (VIEW_MAP1_ZOOM, row); + x_temp[0] = col_to_view (VIEW_MAP1_ZOOM, col); + + row = northing_to_row (&VIEW_MAP1_ZOOM->cell.head, group.points.n1[n+1]) + .5; + col = easting_to_col (&VIEW_MAP1_ZOOM->cell.head,group.points.e1[n+1]) + .5; + y_temp[1] = row_to_view (VIEW_MAP1_ZOOM, row); + x_temp[1] = col_to_view (VIEW_MAP1_ZOOM, col); + + R_polyline_abs (x_temp,y_temp,2); + R_flush(); + + } + + + /* Display red_points in VIEW_MAP2_ZOOM */ + if (group.points.status[n]==0 || group.points.status[n] == 1 ) + display_one_point (VIEW_MAP2_ZOOM, group.points.e2[n], group.points.n2[n]); + else + { + display_one_point (VIEW_MAP2_ZOOM, group.points.e2[n], group.points.n2[n]); + display_one_point (VIEW_MAP2_ZOOM, group.points.e2[n+1], group.points.n2[n+1]); + row = northing_to_row (&VIEW_MAP2_ZOOM->cell.head, group.points.n2[n]) + .5; + col = easting_to_col (&VIEW_MAP2_ZOOM->cell.head, group.points.e2[n]) + .5; + y_temp[0] = row_to_view (VIEW_MAP2_ZOOM, row); + x_temp[0] = col_to_view (VIEW_MAP2_ZOOM, col); + + row = northing_to_row (&VIEW_MAP2_ZOOM->cell.head, group.points.n2[n+1]) + .5; + col = easting_to_col (&VIEW_MAP2_ZOOM->cell.head,group.points.e2[n+1]) + .5; + y_temp[1] = row_to_view (VIEW_MAP2_ZOOM, row); + x_temp[1] = col_to_view (VIEW_MAP2_ZOOM, col); + + R_polyline_abs (x_temp,y_temp,2); + R_flush(); + + } + + + + return 0; +} + + +int points_to_line (double e1, double n1, double e2, double n2, double *t, double *u) +{ + double a,b,c; + a=-(n2 - n1); + b= (e2 - e1); + c= (n2*e1 - n1*e2); + *t= a/c; + *u=b/c; + } + +int new_control_line ( Lines *ln, + double t1,double u1,double t2,double u2,int status) +{ + int i; + unsigned int size; + + i = (ln->count)++ ; + size = ln->count * sizeof(double) ; + ln->t1 = (double *) G_realloc (ln->t1, size); + ln->t2 = (double *) G_realloc (ln->t2, size); + ln->u1 = (double *) G_realloc (ln->u1, size); + ln->u2 = (double *) G_realloc (ln->u2, size); + size = ln->count * sizeof(int) ; + ln->status = (int *) G_realloc (ln->status, size); + + ln->t1[i] = t1; + ln->t2[i] = t2; + ln->u1[i] = u1; + ln->u2[i] = u2; + ln->status[i] = status; + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/analyze.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/ask.c =================================================================== --- trunk/grassaddons/i.points.auto/ask.c (rev 0) +++ trunk/grassaddons/i.points.auto/ask.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,676 @@ +#include +#include +#include +#include +#include "globals.h" +#include "local_proto.h" +#define NLINES 18 + +struct box +{ + int top, bottom, left,right; +}; + +static int pick(int,int,int); +static int downarrow(struct box *,int); +static int uparrow(struct box *,int); +static int dobox(struct box *,char *,int,int,int,int,int); +static int dotext(char *,int ,int ,int ,int ,int ); +static int inbox(struct box *,int ,int ); +static int cancel_which(); + +static int text_size; +static int which; +static struct box cancel, more, less; +static int height, size, edge, count; +static int page,npages; +static struct +{ + char name[GNAME_MAX], mapset[GMAPSET_MAX]; + struct box box; +} list[NLINES*2]; + +int +ask_gis_files (char *type, char *file, char *xname, char *xmapset, int position) +{ + static int use = 1; + int pick(); + static Objects objects[]= + { + OTHER(pick,&use), + {0} + }; + + char msg[100]; + FILE *fd; + int width; + int len1, len2, len; + long offset; + long *page_offset; + int col, nlist; + int line; + int stat; + char buf[100]; + int top, bottom, left, right, center; + int topx, bottomx, leftx, rightx, widthx; + char name[GNAME_MAX], mapset[GMAPSET_MAX], cur_mapset[GMAPSET_MAX]; + int new_mapset; + char debugmsg[200]; + + Menu_msg(""); + debug("ask_gis_files todo\n"); + + fd = fopen (file, "r"); + if (fd == NULL) + G_fatal_error ("ask_gis_files: can't read tempfile"); + if (fread (&len1, sizeof(len1), 1, fd) != 1 + || fread (&len2, sizeof(len2), 1, fd) != 1 + || len1 <= 0 || len2 <= 0) + { + fclose (fd); + return 0; + } + + sprintf (msg, "Double click on %s file to be plotted", type); + +/* + * build a popup window at center of the screen. + * 35% the height and wide enough to hold 2 columms of file names + * + * the window is for choosing file names and will be laid out in 2 columns + * + * ------------------------------------------ + * | CANCEL | (MORE) | (LESS) | + * ------------------------------------------ + * | mapset | + * ------------------------------------------ + * | name1 | name2 | + * ------------------------------------------ + * | name3 | name4 | + * ------------------------------------------ + * | name5 | name6 | + * | . | + * | . | + * | . | + * ------------------------------------------ + */ + +/* height of 1 line, based on NLINES taking up 35% vertical space */ + height = (.35 * (SCREEN_BOTTOM - SCREEN_TOP))/NLINES + 1; + +/* size of text, 80% of line height */ + text_size = .8 * height; + size = text_size - 1; /* fudge for computing pixels width of text */ + +/* indent for the text */ + edge = .1 * height + 1; + +/* this is a fudge to determine the length of the largest text */ + len1 = 2 * len1 ; /* name in 2 columns */ + len2 += strlen ("mapset "); + len = (len1 > len2 ? len1 : len2); + +/* width is for max chars plus sidecar for more/less */ + width = len * size + height; + widthx = strlen(msg) * size; + if (widthx < width) + widthx = width; + +/* define the window */ + top = (SCREEN_TOP + SCREEN_BOTTOM - height*NLINES)/2; + bottom = top + height*NLINES; + + center = (SCREEN_LEFT + SCREEN_RIGHT)/2; + if (position > 0) + { + right = (center + SCREEN_RIGHT + width)/2; + if (right >= SCREEN_RIGHT) + right = SCREEN_RIGHT-1; + left = right - width; + } + else if (position < 0) + { + left = (center + SCREEN_LEFT - width)/2; + if (left <= SCREEN_LEFT) + left = SCREEN_LEFT+1; + right = left + width; + } + else + { + left = center + width/2; + right = left + width; + } + + topx = top - 3 *height; + bottomx = topx + 2*height; + leftx = (left+right-widthx)/2; + if (leftx < SCREEN_LEFT) + leftx = SCREEN_LEFT; + rightx = leftx + widthx; + +/* save what is under these areas, so they can be restored */ + R_panel_save (tempfile1, top, bottom, left, right); + R_panel_save (tempfile2, topx, bottomx, leftx, rightx); + +/* fill it top with GREY, pick area with white */ + R_standard_color (WHITE); + R_box_abs (left, top, right, bottom); + R_standard_color (BLACK); /* GREY */ + R_box_abs (leftx, topx, rightx, bottomx); + + R_standard_color (BLUE); /* BLACK*/ + Outline_box (top, bottom, left, right); + right -=height; /* reduce it to exclude sidecar */ + Outline_box (top, bottom, left, right); + +/* print messages above the files */ + R_standard_color (ORANGE);/*WHITE*/ /* ADDED */ + dotext (msg, topx, topx+height, leftx, rightx, 1); + dotext ("Double click here to cancel", topx+height, bottomx, leftx, rightx, 1); + cancel.top = topx; + cancel.bottom = bottomx; + cancel.left = leftx; + cancel.right = rightx; + +/* start the mouse in the cancel box */ + Set_mouse_xy ((leftx + rightx)/2, (topx + bottomx)/2); + + dobox (&less, "", BLUE, top, right, right+height,0); + dobox (&more, "", BLUE, bottom-height, right, right+height,0); + +/* as we read the file of names, keep track of pages so we can + * page backward + */ + page = 0; + page_offset = (long *) G_calloc (npages=1, sizeof(long)); + *page_offset = ftell(fd); + + nlist = sizeof (list)/ sizeof(list[0]); + for (stat = -1; stat < 0;) + { + line = 0; + count = 0; + *cur_mapset = 0; + col = 0; + while(1) + { + offset = ftell (fd); + if (fgets (buf, sizeof buf, fd) == NULL + || sscanf (buf, "%s %s", name, mapset) != 2) + break; + sprintf(debugmsg, "fgets name: %s\n", name); + debug(debugmsg); + if(new_mapset = (strcmp (cur_mapset,mapset) != 0)) + { + if(line) line++; + if (col) line++; + col = 0; + } + if (count >= nlist || line+new_mapset >= NLINES) + { + if (page+1 == npages) + { + npages++; + page_offset = (long *) G_realloc (page_offset, npages * sizeof (long)); + page_offset[npages-1] = offset; + } + break; + } + if (new_mapset) + { + struct box dummy; + char label[GMAPSET_MAX+7]; + + strcpy (cur_mapset, mapset); + sprintf (label, "Mapset %s", mapset); + dobox (&dummy, label, GREY, top+line*height, left, right, 0); + line++; + } + if (col) + { + dobox (&list[count].box, name, WHITE, top+line*height, left+width/2, right, 0); + line++; + col = 0; + } + else + { + dobox (&list[count].box, name, WHITE, top+line*height, left, left+width/2, 0); + col = 1; + } + + strcpy (list[count].name, name); + strcpy (list[count].mapset, mapset); + count++; + } + + downarrow (&more, page+1 < npages ? BLACK : WHITE); + uparrow (&less, page > 0 ? BLACK : WHITE); + which = -1; + switch(Input_pointer(objects)) + { + case -1: /* more or less */ + break; + case -2: /* cancel */ + stat = 0; + continue; + default: /* file picked */ + strcpy (xname, list[which].name); + strcpy (xmapset, list[which].mapset); + stat = 1; + continue; + } + fseek (fd, page_offset[page], 0); + R_standard_color (WHITE); + R_box_abs (left+1, top+1, right-1, bottom-1); + } + +/* all done. restore what was under the window */ + right += height; /* move it back over the sidecar */ + R_standard_color (WHITE); + R_box_abs (left, top, right, bottom); + R_panel_restore (tempfile1); + R_panel_restore (tempfile2); + R_panel_delete (tempfile1); + R_panel_delete (tempfile2); + R_flush(); + + G_free (page_offset); + return stat; +} + + + + + + + + + + +int +ask_original_map(char *type, char *file, char *xname, char *xmapset, int position) +{ + static int use = 1; + int pick(); + static Objects objects[]= + { + OTHER(pick,&use), + {0} + }; + + char msg[100]; + FILE *fd; + int width; + int len1, len2, len; + long offset; + long *page_offset; + int col, nlist; + int line; + int stat; + char buf[100]; + int top, bottom, left, right, center; + int topx, bottomx, leftx, rightx, widthx; + char name[GNAME_MAX], mapset[GMAPSET_MAX], cur_mapset[GMAPSET_MAX]; + int new_mapset; + + Menu_msg(""); + + fd = fopen (file, "r"); + if (fd == NULL) + G_fatal_error ("ask_gis_files: can't read tempfile"); + if (fread (&len1, sizeof(len1), 1, fd) != 1 + || fread (&len2, sizeof(len2), 1, fd) != 1 + || len1 <= 0 || len2 <= 0) + { + fclose (fd); + return 0; + } + + sprintf (msg, "Double click on the final %s map ", type); + +/* + * build a popup window at center of the screen. + * 35% the height and wide enough to hold 2 columms of file names + * + * the window is for choosing file names and will be laid out in 2 columns + * + * ------------------------------------------ + * | CANCEL | (MORE) | (LESS) | + * ------------------------------------------ + * | mapset | + * ------------------------------------------ + * | name1 | name2 | + * ------------------------------------------ + * | name3 | name4 | + * ------------------------------------------ + * | name5 | name6 | + * | . | + * | . | + * | . | + * ------------------------------------------ + */ + + + +/* height of 1 line, based on NLINES taking up 35% vertical space */ + height = (.35 * (SCREEN_BOTTOM - SCREEN_TOP))/NLINES + 1; + +/* size of text, 80% of line height */ + text_size = .8 * height; + size = text_size - 1; /* fudge for computing pixels width of text */ + +/* indent for the text */ + edge = .1 * height + 1; + +/* this is a fudge to determine the length of the largest text */ + len1 = 2 * len1 ; /* name in 2 columns */ + len2 += strlen ("mapset "); + len = (len1 > len2 ? len1 : len2); + +/* width is for max chars plus sidecar for more/less */ + width = len * size + height; + widthx = strlen(msg) * size; + if (widthx < width) + widthx = width; + +/* define the window */ + top = (SCREEN_TOP + SCREEN_BOTTOM - height*NLINES)/2; + bottom = top + height*NLINES; + + center = (SCREEN_LEFT + SCREEN_RIGHT)/2; + if (position > 0) + { + right = (center + SCREEN_RIGHT + width)/2; + if (right >= SCREEN_RIGHT) + right = SCREEN_RIGHT-1; + left = right - width; + } + else if (position < 0) + { + left = (center + SCREEN_LEFT - width)/2; + if (left <= SCREEN_LEFT) + left = SCREEN_LEFT+1; + right = left + width; + } + else + { + left = center + width/2; + right = left + width; + } + + topx = top - 3 *height; + bottomx = topx + 2*height; + leftx = (left+right-widthx)/2; + if (leftx < SCREEN_LEFT) + leftx = SCREEN_LEFT; + rightx = leftx + widthx; + + + + +/* save what is under these areas, so they can be restored */ + R_panel_save (tempfile1, top, bottom, left, right); + R_panel_save (tempfile2, topx, bottomx, leftx, rightx); + +/* fill it top with GREY, pick area with white */ + R_standard_color (WHITE); + R_box_abs (left, top, right, bottom); + R_standard_color (BLACK); + R_box_abs (leftx, topx, rightx, bottomx); + + R_standard_color (BLUE); /*BLACK */ + Outline_box (top, bottom, left, right); + right -=height; /* reduce it to exclude sidecar */ + Outline_box (top, bottom, left, right); + +/* print messages above the files */ + R_standard_color (ORANGE); /*BLACK */ + dotext (msg, topx, topx+height, leftx, rightx, 1); + dotext ("Double click here to cancel", topx+height, bottomx, leftx, rightx, 1); + cancel.top = topx; + cancel.bottom = bottomx; + cancel.left = leftx; + cancel.right = rightx; + +/* start the mouse in the cancel box */ + Set_mouse_xy ((leftx + rightx)/2, (topx + bottomx)/2); + + dobox (&less, "", BLUE, top, right, right+height,0); + dobox (&more, "", BLUE, bottom-height, right, right+height,0); + +/* as we read the file of names, keep track of pages so we can + * page backward + */ + page = 0; + page_offset = (long *) G_calloc (npages=1, sizeof(long)); + *page_offset = ftell(fd); + + + + nlist = sizeof (list)/ sizeof(list[0]); + for (stat = -1; stat < 0;) + { + line = 0; + count = 0; + *cur_mapset = 0; + col = 0; + while(1) + { + + offset = ftell (fd); + if (fgets (buf, sizeof buf, fd) == NULL + || sscanf (buf, "%s %s", name, mapset) != 2) + break; + if(new_mapset = (strcmp (cur_mapset,mapset) != 0)) + { + if(line) line++; + if (col) line++; + col = 0; + } + if (count >= nlist || line+new_mapset >= NLINES) + { + if (page+1 == npages) + { + npages++; + page_offset = (long *) G_realloc (page_offset, npages * sizeof (long)); + page_offset[npages-1] = offset; + } + break; + } + if (new_mapset) + { + struct box dummy; + char label[GMAPSET_MAX+7]; + + strcpy (cur_mapset, mapset); + sprintf (label, "Mapset %s", mapset); + dobox (&dummy, label, GREY, top+line*height, left, right, 0); + line++; + } + if (col) + { + dobox (&list[count].box, name, WHITE, top+line*height, left+width/2, right, 0); + line++; + col = 0; + } + else + { + dobox (&list[count].box, name, WHITE, top+line*height, left, left+width/2, 0); + col = 1; + } + strcpy (list[count].name, name); + strcpy (list[count].mapset, mapset); + count++; + } + downarrow (&more, page+1 < npages ? BLACK : WHITE); + uparrow (&less, page > 0 ? BLACK : WHITE); + which = -1; + + + + + + switch(Input_pointer(objects)) + { + case -1: /* more or less */ + break; + case -2: /* cancel */ + stat = 0; + continue; + default: /* file picked */ + strcpy (xname, list[which].name); + strcpy (xmapset, list[which].mapset); + stat = 1; + continue; + } + fseek (fd, page_offset[page], 0); + R_standard_color (WHITE); + R_box_abs (left+1, top+1, right-1, bottom-1); + } + + + +/* all done. restore what was under the window */ + right += height; /* move it back over the sidecar */ + R_standard_color (WHITE); + R_box_abs (left, top, right, bottom); + R_panel_restore (tempfile1); + R_panel_restore (tempfile2); + R_panel_delete (tempfile1); + R_panel_delete (tempfile2); + R_flush(); + + + G_free (page_offset); + return stat; +} + + + + + + + +static int dobox(struct box *box, char *text,int color,int top,int left,int right,int centered) +{ + int bottom; + + bottom = top+height; +/* fill inside of box with color */ + R_standard_color (color); + R_box_abs (left+1, top+1, right-1, bottom-1); + +/* draw box outline and text in black */ + R_standard_color (BLUE); /*BLACK*/ + Outline_box (top, bottom, left, right); + R_standard_color (BLACK); /* ADDED. It determines the colour of text in the table */ + dotext (text, top, bottom, left, right, centered); + + box->top = top; + box->bottom = bottom; + box->left = left; + box->right = right; + + return 0; +} + +static int uparrow(struct box *box,int color) +{ + R_standard_color (color); + Uparrow (box->top+edge, box->bottom-edge, box->left+edge, box->right-edge); + + return 0; +} + +static int downarrow ( struct box *box,int color) +{ + R_standard_color (color); + Downarrow (box->top+edge, box->bottom-edge, box->left+edge, box->right-edge); + + return 0; +} + +static int pick(int x,int y,int button) +{ + int n; + + if (inbox(&more,x,y)) + { + cancel_which(); + if (page+1 >= npages) + return 0; + page++; + return -1; + } + if (inbox(&less,x,y)) + { + cancel_which(); + if (page == 0) + return 0; + page--; + return -1; + } + if (inbox(&cancel,x,y)) + { + if (which == -2) + return -2; + cancel_which(); + which = -2; + R_standard_color (RED); + Outline_box (cancel.top, cancel.bottom, cancel.left, cancel.right); + return 0; + } +/* search name list. handle double click */ + for (n = 0; n < count; n++) + if (inbox(&list[n].box,x,y)) + { + if (n == which) /* second click! */ + return 1; + cancel_which(); + which = n; + R_standard_color (RED); + Outline_box (list[n].box.top, list[n].box.bottom, + list[n].box.left, list[n].box.right); + return 0; /* ignore first click */ + } + + cancel_which(); + return 0; +} + +static int +cancel_which (void) +{ + if (which == -2) + { + R_standard_color (BLACK); + Outline_box (cancel.top, cancel.bottom, cancel.left, cancel.right); + } + else if (which >= 0) + { + R_standard_color (BLACK); + Outline_box (list[which].box.top, list[which].box.bottom, + list[which].box.left, list[which].box.right); + } + which = -1; + + return 0; +} + +static int inbox(struct box *box,int x,int y) +{ + return (x>box->left && x right && y>box->top && ybottom); +} + +static int dotext(char *text,int top,int bottom,int left,int right,int centered) +{ + R_text_size (text_size, text_size); + R_move_abs (left+1+edge, bottom-1-edge); + if (centered) + R_move_rel ((right-left-strlen(text)*size)/2,0); + R_set_window (top, bottom, left, right); /* for text clipping */ + R_text (text); + R_set_window (SCREEN_TOP, SCREEN_BOTTOM, SCREEN_LEFT, SCREEN_RIGHT); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/ask.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/ask_mag.c =================================================================== --- trunk/grassaddons/i.points.auto/ask_mag.c (rev 0) +++ trunk/grassaddons/i.points.auto/ask_mag.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,168 @@ +#include +#include "globals.h" +#include "local_proto.h" + +struct box +{ + int top, bottom, left, right; +}; + +static struct box plus, minus, value; +static struct box cancel, accept; +static int mag; +static int inbox(struct box *,int,int); +static int dotext(char *,int,int,int,int,int); +static int incr(int,int); + +int +ask_magnification (int *magnification) +{ + static int use = 1; + int incr(); + int x,y; + int height; + int stat; + int width; + int top, bottom, left, right; + + static Objects objects[]= + { + OTHER(incr, &use), + {0} + }; + + Menu_msg (""); + + mag = *magnification ; + if (mag < 1) + mag = 1; + + height = VIEW_MENU->nrows; + R_text_size (height-4, height-4); + + + Get_mouse_xy (&x, &y); + top = y - height/2; + if (top < SCREEN_TOP) + top = SCREEN_TOP; + bottom = top + 4 * height; + if (bottom >= VIEW_MENU->top) + { + top -= bottom - (VIEW_MENU->top -1); + bottom = VIEW_MENU->top-1; + } + width = Text_width ("MAGNIFICATION") + 4; + left = x - width/2; + if (left < SCREEN_LEFT) + left = SCREEN_LEFT; + right = left + width; + if (right > SCREEN_RIGHT) + { + left -= right - SCREEN_RIGHT; + right = SCREEN_RIGHT; + } + + R_panel_save (tempfile1, top, bottom, left, right); + R_standard_color (BLUE); /*WHITE*/ + R_box_abs (left, top, right, bottom); + R_standard_color (RED); /*BLACK*/ + Outline_box (top, bottom, left, right); + + plus.top = top + height; + plus.bottom = plus.top + height; + plus.left = left; + plus.right = plus.left + Text_width ("++") + 4; + Outline_box (plus.top, plus.bottom, plus.left, plus.right); + + minus.top = top + height; + minus.bottom = minus.top + height; + minus.right = right; + minus.left = minus.right - Text_width ("--") - 4; + Outline_box (minus.top, minus.bottom, minus.left, minus.right); + + value.top = top + height; + value.bottom = value.top + height; + value.left = plus.right; + value.right = minus.left; + Outline_box (value.top, value.bottom, value.left, value.right); + + accept.top = value.bottom; + accept.bottom = accept.top + height; + accept.left = left; + accept.right = right; + Outline_box (accept.top, accept.bottom, accept.left, accept.right); + + cancel.top = accept.bottom; + cancel.bottom = cancel.top + height; + cancel.left = left; + cancel.right = right; + Outline_box (cancel.top, cancel.bottom, cancel.left, cancel.right); + + dotext ("MAGNIFICATION", top, top+height, left, right, WHITE); + dotext ("+", plus.top, plus.bottom, plus.left, plus.right, GREY); + dotext ("-", minus.top, minus.bottom, minus.left, minus.right, GREY); + dotext ("ACCEPT", accept.top, accept.bottom, accept.left, accept.right, GREY); + dotext ("CANCEL", cancel.top, cancel.bottom, cancel.left, cancel.right, GREY); + draw_mag(); + + stat = Input_pointer (objects); + +/* to respond to user */ + R_standard_color (BLUE); /*WHITE*/ + R_box_abs (left, top, right, bottom); + R_flush(); + + R_panel_restore (tempfile1); + R_panel_delete (tempfile1); + + *magnification = mag; + return stat > 0; +} + +int +draw_mag (void) +{ + char buf[10]; + + sprintf (buf, "%d", mag); + dotext (buf, value.top, value.bottom, value.left, value.right, WHITE); + + return 0; +} + +static int incr(int x,int y) +{ + if (inbox (&accept,x,y)) + return 1; + if (inbox (&cancel,x,y)) + return -1; + if (inbox (&plus,x,y)) + { + mag++; + draw_mag(); + } + else if (inbox (&minus,x,y) && mag > 1) + { + mag--; + draw_mag(); + } + return 0; +} + +static int dotext(char *text,int top,int bottom,int left,int right,int background) +{ + R_standard_color (BLUE); /*background*/ + R_box_abs (left+1, top+1, right-1, bottom-1); + R_standard_color (WHITE); /*BLACK*/ + /* center the text */ + left = (left + right - Text_width (text))/2; + Text (text, top, bottom, left, right, 2); + R_flush(); + + return 0; +} + +static int inbox(struct box *box,int x,int y) +{ + return (x>box->left && x right && y>box->top && ybottom); +} Property changes on: trunk/grassaddons/i.points.auto/ask_mag.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/call.c =================================================================== --- trunk/grassaddons/i.points.auto/call.c (rev 0) +++ trunk/grassaddons/i.points.auto/call.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include "globals.h" +#include "local_proto.h" + +/* + * call a subroutine, but as a child process + * allowing interrupts for the child + */ +#include + +int call (int (*function)(),char *msg) +{ + int pid; + int w, status; + char i_msg[80]; + +/* + * build interrupt msg + */ + sprintf (i_msg, "Hit %s %s\n", G_unctrl(interrupt_char), msg); +/* + * make sure all graphics have gotten to the monitor + */ + R_stabilize(); + +/* fork to create child */ + pid = fork(); + if (pid < 0) + { + End_curses(); + perror ("Can't fork"); + exit (1); + } + +/* parent just waits for child */ + Curses_allow_interrupts(1); + if (pid) + { + Curses_write_window (PROMPT_WINDOW, 1, 1, i_msg); + while ( (w = wait (&status)) != pid && w != -1) + ; + Curses_allow_interrupts(0); + Curses_write_window (PROMPT_WINDOW, 1, 1, "\n"); + } + +/* child turns on interrupts and calls the function */ + else + { + signal (SIGINT, SIG_DFL); + (*function)(); + exit(0); + } + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/call.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/cell.c =================================================================== --- trunk/grassaddons/i.points.auto/cell.c (rev 0) +++ trunk/grassaddons/i.points.auto/cell.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,100 @@ +#include +#include "globals.h" +#include "local_proto.h" + +static int use = 1; +static int choose_cellfile(char *,char *); +static int plot(int,int); +static int cancel(void); + +int +plotcell (int x, int y) +{ + int cancel(); + int plot(); + static Objects objects[] = + { + MENU("CANCEL", cancel, &use), + INFO("Indicate which side should be plotted", &use), + OTHER(plot, &use), + {0} + }; +/* + * if the target cell file list is ready, ask the user which side + * should be plotted, otherwise can only plot group files + */ + if (access (cell_list,0) == 0) + Input_pointer (objects); + else + plot (VIEW_MAP1->left+1,0); + return 0; +} + +static int +cancel (void) +{ + return 1; +} + + +static int plot(int x,int y) +{ + char name[100], mapset[100]; + struct Cell_head cellhd; + + if (x > VIEW_MAP1->left && x < VIEW_MAP1->right) + { + if (!choose_groupfile(name,mapset)) + return 1; + if(G_get_cellhd(name, mapset, &cellhd) < 0) + return 1; + + Erase_view (VIEW_MAP1_ZOOM); + VIEW_MAP1_ZOOM->cell.configured = 0; + + G_adjust_window_to_box (&cellhd, &VIEW_MAP1->cell.head, VIEW_MAP1->nrows, VIEW_MAP1->ncols); + Configure_view (VIEW_MAP1, name, mapset, cellhd.ns_res, cellhd.ew_res); + drawcell(VIEW_MAP1); + } + else if (x > VIEW_MAP2->left && x < VIEW_MAP2->right) + { + if (!ask_gis_files("raster",group_list,name, mapset,1)) + return 1; + select_target_env(); + + if(G_get_cellhd(name, mapset, &cellhd) < 0) + { + select_current_env(); + return 1; + } + + Erase_view (VIEW_MAP2_ZOOM); + VIEW_MAP2_ZOOM->cell.configured = 0; + + G_adjust_window_to_box (&cellhd, &VIEW_MAP2->cell.head, VIEW_MAP2->nrows, VIEW_MAP2->ncols); + Configure_view (VIEW_MAP2, name, mapset, cellhd.ns_res, cellhd.ew_res); + select_target_env(); + drawcell(VIEW_MAP2); + select_current_env(); + if (from_screen < 0) + { + from_flag = 1; + from_screen = 0; + if (from_keyboard < 0) + { + from_keyboard = 0; + from_screen = 1; + } + } + } + else + return 0; /* ignore mouse click */ + + display_points(1); + return 1; +} + +static int choose_cellfile(char *name,char *mapset) +{ + return ask_gis_files ("raster", cell_list, name, mapset, 1); +} Property changes on: trunk/grassaddons/i.points.auto/cell.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/cellhd.c =================================================================== --- trunk/grassaddons/i.points.auto/cellhd.c (rev 0) +++ trunk/grassaddons/i.points.auto/cellhd.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,25 @@ +#include "globals.h" +#include "local_proto.h" + +int +Outline_cellhd (View *view, struct Cell_head *cellhd) +{ + int row,col; + int top, bottom, left, right; + + row = northing_to_row (&view->cell.head, cellhd->north) + .5; + top = row_to_view (view, row); + + col = easting_to_col (&view->cell.head, cellhd->west) + .5; + left = col_to_view (view, col); + + row = northing_to_row (&view->cell.head, cellhd->south) + .5; + bottom = row_to_view (view, row); + + col = easting_to_col (&view->cell.head, cellhd->east) + .5; + right = col_to_view (view, col); + + Outline_box (top, bottom, left, right); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/cellhd.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/colors.c =================================================================== --- trunk/grassaddons/i.points.auto/colors.c (rev 0) +++ trunk/grassaddons/i.points.auto/colors.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,7 @@ +#include +#include +int +set_colors (struct Colors *colors) +{ + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/colors.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/conv.c =================================================================== --- trunk/grassaddons/i.points.auto/conv.c (rev 0) +++ trunk/grassaddons/i.points.auto/conv.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,59 @@ +#include "globals.h" + +/* conversion routines to convert from view x,y to cell col,row + * as well as cell col,row to cell east,north + */ +int +view_to_col (View *view, int x) +{ + return x - view->cell.left; +} + +int +view_to_row (View *view, int y) +{ + return y - view->cell.top; +} + +int +col_to_view (View *view, int col) +{ + return view->cell.left + col; +} + +int +row_to_view (View *view, int row) +{ + return view->cell.top + row; +} + +/* in these next 2 routines, location determines if we are + * converting from center of the cell (location == .5) + * top or left edge (location == 0.0) + * bottom or right edge (location == 1.0) + */ + +double +row_to_northing (struct Cell_head *cellhd, int row, double location) +{ + return cellhd->north - (row + location) * cellhd->ns_res; +} + +double +col_to_easting (struct Cell_head *cellhd, int col, double location) +{ + return cellhd->west + (col + location) * cellhd->ew_res; +} + +double +northing_to_row (struct Cell_head *cellhd, double north) +{ + return (cellhd->north - north) / cellhd->ns_res; +} + +double +easting_to_col (struct Cell_head *cellhd, double east) +{ + return (east - cellhd->west) / cellhd->ew_res; +} + Property changes on: trunk/grassaddons/i.points.auto/conv.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/curses.c =================================================================== --- trunk/grassaddons/i.points.auto/curses.c (rev 0) +++ trunk/grassaddons/i.points.auto/curses.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,282 @@ +#include +#include +#include "globals.h" +#include "local_proto.h" + +static int inited = 0; + +static WINDOW *save; +WINDOW *newwin(); + +static Window *make_window (int top, int bottom, int left, int right) +{ + Window *window; + + if (top < 0 || bottom >= LINES || left < 0 || right >= COLS + || bottom-top <= 1 || right-left <= 1) + { + End_curses(); + fprintf (stderr, "make_window(%d,%d,%d,%d): illegal screen values\n", + top, bottom, left, right); + sleep(3); + exit(1); + } + window = (Window *) G_malloc (sizeof(Window)); + window->top = top; + window->bottom = bottom; + window->left = left; + window->right = right; + Curses_clear_window (window); + return window; +} + +int Begin_curses (void) +{ +/* should only be called once at program outset */ + + initscr () ; /* initialize curses standard screens */ + raw() ; /* set tty modes via curses calls */ + noecho() ; + nonl() ; + + inited = 1; + +/* make a window to save stdscr */ + save = newwin(LINES,COLS,0,0); + +/* make_window (nrows, ncols, start_row, start_col) */ + INFO_WINDOW = make_window (0, LINES-4, COLS/2, COLS-1); + MENU_WINDOW = make_window (0, LINES-4, 0, COLS/2); + PROMPT_WINDOW = make_window (LINES-4, LINES-1, 0, COLS-1); + refresh(); + + + return 0; +} + +int End_curses (void) +{ +/* should only be called upon program exit */ + + clear() ; /* clear the screen */ + refresh() ; + endwin() ; /* let curses reset the tty now */ + + return 0; +} + +int Suspend_curses (void) +{ + overwrite (stdscr, save); + clear(); + refresh(); + endwin(); + + return 0; +} + +int Resume_curses (void) +{ + clear(); + refresh(); + overwrite (save, stdscr); + refresh(); + + return 0; +} + +int Curses_allow_interrupts (int ok) +{ + refresh(); + if (ok) + noraw(); + else + raw(); + + return 0; +} + +int Curses_clear_window (Window *window) +{ + int y,x; + +if (!inited) return 1; + for (y = window->top+1; y < window->bottom; y++) + { + move (y, x=window->left+1); + while (x++ < window->right) + addch (' '); + } + Curses_outline_window (window); + refresh(); + + return 0; +} + +int Curses_outline_window (Window *window) +{ + int x, y; + + move (window->top, x=window->left+1); + while (x++ < window->right) + addch ('-'); + move (window->bottom, x=window->left+1); + while (x++ < window->right) + addch ('-'); + for (y=window->top+1; y < window->bottom; y++) + { + move (y, window->left); + addch ('|'); + move (y, window->right); + addch ('|'); + } + move (window->top, window->left); + addch ('+'); + move (window->top, window->right); + addch ('+'); + move (window->bottom, window->left); + addch ('+'); + if (window->bottom < LINES-1 || window->right < COLS-1) + { + move (window->bottom, window->right); + addch ('+'); + } + + return 0; +} + +int Curses_write_window (Window *window, int line, int col, char *message) +{ + int y,x,i; + +if (!inited) +{ + fprintf (stderr, "%s\n", message); + return 1; +} + if (line <= 0 || line >= window->bottom-window->top) + return 1; + if (col <= 0 || col >= window->right-window->left) + return 1; + move(y=window->top+line, x=window->left+col); + while (*message != 0 && *message != '\n' && x < window->right) + { + addch (*message); + message++; + x++; + } + if (*message == '\n') + for (i = x; i < window->right; i++) + addch (' '); + move (y, x); + refresh(); + + return 0; +} + + +int +Curses_replot_screen (void) +{ + int x,y; + getyx (stdscr, y, x); + wrefresh(curscr) ; + move (y, x); + refresh(); + + return 0; +} + +int Curses_prompt_gets (char *prompt, char *answer) +{ + char c ; + int n; + int y,x; + + *answer = 0; + n = 0; + + Curses_write_window (PROMPT_WINDOW, 1, 1, "\n"); + Curses_write_window (PROMPT_WINDOW, 1, 1, prompt); + + for(;;) + { + refresh (); + c = Curses_getch(0) ; + if (c == '\n' || c == '\r') + break; + + getyx (stdscr, y, x); + if (c > 037 && c < 0177) + { + if (x < PROMPT_WINDOW->right) + { + *answer++ = c ; + *answer = 0 ; + addch(c) ; + n++; + } + continue; + } + if (c == '\b') + { + if (n > 0) + { + answer--; + *answer = 0; + move (y, x-1); + addch (' '); + move (y, x-1); + n--; + } + continue; + } + Beep(); + } + + return 0; +} + +int +Beep (void) +{ + putchar ('\7'); + fflush (stdout); + + return 0; +} + +int +Curses_getch (int with_echo) +{ + char achar; + int c; + int kill; + +if (!inited) return 0; + kill = 0; + while(1) + { + c = getch() & 0177; + if (c == interrupt_char) + { + if (kill++ >= 3) + { + End_curses(); + exit(0); + } + continue; + } + kill = 0; + if (c != 18) + break; + Curses_replot_screen(); + } + if (with_echo) + { + achar = c; + addch(achar); + refresh(); + } + return c; +} Property changes on: trunk/grassaddons/i.points.auto/curses.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/debug.c =================================================================== --- trunk/grassaddons/i.points.auto/debug.c (rev 0) +++ trunk/grassaddons/i.points.auto/debug.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,13 @@ +#include +#include "globals.h" +#include "local_proto.h" + +int +debug (char *msg) +{ + R_stabilize(); + Curses_write_window (PROMPT_WINDOW, 1, 1, msg); + /* Curses_getch(0);*/ + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/debug.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/defs.h =================================================================== --- trunk/grassaddons/i.points.auto/defs.h (rev 0) +++ trunk/grassaddons/i.points.auto/defs.h 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,72 @@ +#include +#include + +/* this is a curses structure */ +typedef struct +{ + int top, left, bottom, right; +} Window; + +/* this is a graphics structure */ +typedef struct +{ + int top, bottom ,left, right; + int nrows, ncols; + struct + { + int configured; + struct Cell_head head; + struct Colors colors; + char name[100]; + char mapset[100]; + int top, bottom ,left, right; + double ew_res, ns_res; /* original map resolution */ + } cell; +} View; + + +typedef struct +{ + char name[100]; + struct Ref ref; + struct Control_Points points; + double E12[3], N12[3], E21[3], N21[3]; + int equation_stat; +} Group; + +typedef struct +{ + int type; /* object type */ + int (*handler)(); /* routine to handle the event */ + char *label; /* label to display if MENU or OPTION */ + int binding; /* OPTION bindings */ + int *status; /* MENU,OPTION status */ + int top,bottom,left,right; +} Objects; + +#define MENU_OBJECT 1 +#define OPTION_OBJECT 2 +#define INFO_OBJECT 3 +#define OTHER_OBJECT 4 + + +#define MENU(label,handler,status) \ + {MENU_OBJECT,handler,label,0,status,0,0,0,0} +#define OPTION(label,binding,status) \ + {OPTION_OBJECT,NULL,label,binding,status,0,0,0,0} +#define INFO(label,status) \ + {INFO_OBJECT,NULL,label,0,status,0,0,0,0} +#define OTHER(handler,status) \ + {OTHER_OBJECT,handler,NULL,0,status,0,0,0,0} + +typedef struct +{ + double *t1; + double *u1; + double *t2; + double *u2; + int *status; + double E12[3], N12[3], E21[3], N21[3]; + int count; + int line_stat; +} Lines; Property changes on: trunk/grassaddons/i.points.auto/defs.h ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/description.html =================================================================== --- trunk/grassaddons/i.points.auto/description.html (rev 0) +++ trunk/grassaddons/i.points.auto/description.html 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,55 @@ +

DESCRIPTION

+ +This module allows a search of GCP's on two raster-maps with differents levels +of automation. + +The manual search is the default search, so it's possible to +determine the GCP's manually with the mouse. + +Semiautomated-search +You have to determine with the mouse some corrispondent areas +(with a discrete precision) in the two maps and the module searches the GCP's in these areas. + +Automated-search +At the start of module you have to load the maps that the algorithm uses to the search, +so it's recommended to use the maps filtered with the filters DIVERSITY or STDDEV +(of GRASS) with a window of 3x3 or 5x5 pixels. However, the algorithm sometimes work +well with the original maps too. + +You click the button Automated-Search and then you have to load the maps that you want to +visualize at the end of the search (with the GCP's), usually they are the original maps. + +If the maps have strong geometric distortion and strong geometric differencies, maybe +the results of the search (with the default options) are not good, so you can click the +button LESS-GCP's and then repeat the operation. + +The Overlap-Points (O.P.) era two corresponding points (one for every maps) that is +used from the algorithm to determine the overlapping-area in the two maps. +The Master-map is considered the map on the left, and the Slave-map is the map on the right. + +Center, top, bottom, left, right are the position of the Master Overlap-Point (on the +left map) that will be searched on the Slave map (right map). Center is the point at the +center of the map. Top, bottom, left, right are the position of the O.P. respect to +the center of the map. If you choose one of these possibilities, then you have to +choose the shift from the center, measured in percentage of the dimensions of the map; there +are two possibilities: 5% and 10%. +This type of search is the most automated (fully-automated ). + +If you choose -MARK SLAVE O.P.-, then the module visualizes a blue point at the center +of the master map, and you have to mark the corrispondent point on the slave map. +You can use this function if the maps are overlapped for more of 50% and if the +algorithm doesn't have success in the fully-automated search. + +If the maps have a overlapping area less of 50%, you can use the function -MARK M and S O.P.-. +You have to mark a point in the master map and the corresponding point on the slave map. + +At the end of search it's possible to exclude automatically the points not really +corresponding. This function use the rms with a threshold. The default-value for +the threshold is 2.5, but (before to active the Auto-Exclusion) you can change it, +chossing one of different proposed values; you can choose an arbitrary value with +click on -OTHER-, so you go on the shell and digit the value from keyboard and confirm +with ENTER. + +

AUTHOR

+ +

Last changed: $Date: 2006/06/22 07:46:46 $

Added: trunk/grassaddons/i.points.auto/digit.c =================================================================== --- trunk/grassaddons/i.points.auto/digit.c (rev 0) +++ trunk/grassaddons/i.points.auto/digit.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,129 @@ +#include +#include +#include "globals.h" +#include "local_proto.h" + +static int setup(void); +static int oops(void); +static int yes(void); +static int no(void); + +int +setup_digitizer (void) +{ + static int use = 1; + int setup(), no(), yes(); + static Objects objects[]= + { + INFO("Do you wish to use the digitizer? ", &use), + MENU("YES", yes, &use), + MENU("NO", no, &use), + {0} + }; + char command[1024]; + + use_digitizer = 0; +/* + * test to see if we have a digitizer (geo.quest) + * make sure this program has execute permission first. + * then run the program and check its exit status + * 0 means can use digitizer, other means can't + */ + sprintf (command, "%s/etc/geo.quest", G_gisbase()); + if (access (command, 1) != 0) + return 0; + if (system(command)) + return 0; + + +/* + * ask the user if he/she wishes to use it + */ + Start_mouse_in_menu(); + Input_pointer (objects); + if (use_digitizer) + Input_other (setup, "Keyboard"); + + return 0; +} + +static int +setup (void) +{ + char command[1024]; +/* + * setup the digitizer. system() call must exit with 0 to indicate + * everything went fine + */ + sprintf (command, "%s/etc/geo.reg %s %d", + G_gisbase(), digit_points, getpid()); + Suspend_curses(); + if (system (command)) + { + use_digitizer = 0; + sleep(3); + } + Resume_curses(); + + return 0; +} + +int +digitizer_point (double *east, double *north) +{ + char command[1024]; + FILE *fd; + int stat; + +/* make sure digitzer is to be used */ + if (!use_digitizer) + return 0; + + sprintf (command, "%s/etc/geo.point %s %s", + G_gisbase(), digit_points, digit_results); + + Suspend_curses(); + if(system (command)) + { + sleep(3); + Resume_curses(); + oops(); + return 0; + } + Resume_curses(); + fd = fopen (digit_results, "r"); + if (fd == NULL) + { + oops(); + return 0; + } + stat = (fscanf (fd, "%lf %lf", east, north) == 2); + fclose (fd); + + if (stat == 0) + oops(); + return stat; +} + +static int +oops (void) +{ + Curses_clear_window (MENU_WINDOW); + Curses_write_window (MENU_WINDOW, 3,2,"Can't get data from digitizer"); + + return 0; +} + +static int +no (void) +{ + use_digitizer = 0; + return 1; +} + +static int +yes (void) +{ + use_digitizer = 1; + return 1; +} Property changes on: trunk/grassaddons/i.points.auto/digit.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/dot.c =================================================================== --- trunk/grassaddons/i.points.auto/dot.c (rev 0) +++ trunk/grassaddons/i.points.auto/dot.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,55 @@ +#include +#include "globals.h" + +int +dot (int x, int y) +{ + int vx[5], vy[5]; + + vx[0] = x; vy[0] = y - dotsize; + vx[1] = x - dotsize; vy[1] = y; + vx[2] = x; vy[2] = y + dotsize; + vx[3] = x + dotsize; vy[3] = y; + vx[4] = x; vy[4] = y - dotsize; + + R_polygon_abs (vx, vy, 5); +/* + int i; + + for (i = 0; i < dotsize; i++) + { + R_move_abs (x-i, y+i-dotsize); + R_cont_rel (i+i,0); + R_move_abs (x-i, y+dotsize-i); + R_cont_rel (i+i,0); + } + R_move_abs (x-dotsize, y); + R_cont_rel (dotsize+dotsize, 0); +*/ + + return 0; +} + +int +save_under_dot (int x, int y) +{ + R_panel_save (tempfile1, y-dotsize, y+dotsize, x-dotsize, x+dotsize); + + return 0; +} + +int +restore_under_dot (void) +{ + R_panel_restore (tempfile1); + + return 0; +} + +int +release_under_dot (void) +{ + R_panel_delete (tempfile1); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/dot.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/drawcell.c =================================================================== --- trunk/grassaddons/i.points.auto/drawcell.c (rev 0) +++ trunk/grassaddons/i.points.auto/drawcell.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,77 @@ +#include +#include +#include "globals.h" +#include +#include +#include "local_proto.h" + +int drawcell(View *view) +{ + int fd; + int left, top; + int ncols, nrows; + int row; + DCELL *dcell; + struct Colors *colors; + int read_colors; + char msg[GNAME_MAX]; + + + if (!view->cell.configured) return 0; + if (view == VIEW_MAP1 || view == VIEW_MAP1_ZOOM) + { + colors = &VIEW_MAP1->cell.colors; + read_colors = view == VIEW_MAP1; + } + else + { + colors = &VIEW_MAP2->cell.colors; + read_colors = view == VIEW_MAP2; + } + if (read_colors) + { + G_free_colors (colors); + if(G_read_colors (view->cell.name, view->cell.mapset, colors) < 0) + return 0; + } + + display_title (view); + + set_colors (colors); + + G_set_window (&view->cell.head); + nrows = G_window_rows(); + ncols = G_window_cols(); + + left = view->cell.left; + top = view->cell.top; + + R_standard_color (BLUE); + Outline_box (top, top+nrows-1, left, left+ncols-1); + + if (getenv("NO_DRAW")) + return 1; + + fd = G_open_cell_old (view->cell.name, view->cell.mapset); + if (fd < 0) + return 0; + dcell = G_allocate_d_raster_buf(); + + sprintf (msg, "Plotting %s ...", view->cell.name); + Menu_msg(msg); + + D_cell_draw_setup(top, top + nrows, left, left + ncols); + for (row = 0; row < nrows; row++) + { + if(G_get_d_raster_row_nomask(fd, dcell, row) < 0) + break; + D_draw_d_raster (row, dcell, colors); + } + D_cell_draw_end(); + G_close_cell (fd); + G_free (dcell); + if(colors != &VIEW_MAP1->cell.colors) + set_colors(&VIEW_MAP1->cell.colors); + + return row==nrows; +} Property changes on: trunk/grassaddons/i.points.auto/drawcell.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/driver.c =================================================================== --- trunk/grassaddons/i.points.auto/driver.c (rev 0) +++ trunk/grassaddons/i.points.auto/driver.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,63 @@ +#include "globals.h" +#include "local_proto.h" + +static int use = 1; +static int stop(void); +static int dont_stop(void); +static int really_quit(void); + +int driver (void) +{ + static Objects objects[] = + { + MENU(" QUIT ",really_quit,&use), + MENU(" ZOOM ",zoom,&use), + MENU(" PLOT RASTER ",plotcell,&use), + MENU(" LINE ",line,&use), + MENU(" ANALYZE ",analyze,&use), + MENU(" SEMIAUTOMATED SEARCH ",Extract_matrix_semi,&use), + MENU(" AUTOMATED SEARCH ",automated_search,&use), + OTHER(mark, &use), + {0} + }; + + Input_pointer (objects); + Menu_msg (""); + + return 0; +} + + + + + + +static int +really_quit (void) +{ + static Objects objects[] = + { + INFO("really quit? ",&use), + MENU(" NO ",dont_stop,&use), + MENU(" YES ",stop,&use), + {0} + }; + if (Input_pointer (objects) < 0) + return -1; + return 0; /* don't quit */ +} + + +static int +dont_stop (void) +{ + return 1; +} + +static int +stop (void) +{ + return -1; +} + + Property changes on: trunk/grassaddons/i.points.auto/driver.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/equ.c =================================================================== --- trunk/grassaddons/i.points.auto/equ.c (rev 0) +++ trunk/grassaddons/i.points.auto/equ.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,11 @@ +#include "globals.h" +#include "local_proto.h" + +int +Compute_equation (void) +{ + group.equation_stat = compute_georef_equations(&group.points, + group.E12, group.N12, group.E21, group.N21); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/equ.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/find.c =================================================================== --- trunk/grassaddons/i.points.auto/find.c (rev 0) +++ trunk/grassaddons/i.points.auto/find.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,21 @@ +#include +#include "globals.h" +#include "local_proto.h" + +/* + * run etc/i.find command find all cell, vect files + * in the target location. + */ +int find_target_files (void) +{ + char command[1024]; + + select_target_env(); + sprintf (command, "%s/etc/i.find %s %s cell %s dig %s", + G_gisbase(), G_location(), G_mapset(), cell_list, vect_list); + select_current_env(); + + system(command); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/find.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/find_points.c =================================================================== --- trunk/grassaddons/i.points.auto/find_points.c (rev 0) +++ trunk/grassaddons/i.points.auto/find_points.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,2212 @@ +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_FFTW_H +#include +#endif +#ifdef HAVE_DFFTW_H +#include +#endif + +#include +#include +#include +#include "globals.h" +#include "local_proto.h" + +#ifdef NULL_VALUE +#undef NULL_VALUE +#endif +#define NULL_VALUE -1 + + +double *fft_first[2]; +double *fft_second[2]; +double *fft_prod_con[2]; + +int n=1; /*If (n==1) then the algorithm is searching the Overlapping-Area, if (n==2), it is searching the GCP's*/ +int pos_point; +int dist; +int ncols1, ncols2, nrows1, nrows2; +int nrows1_img, ncols1_img, nrows2_img, ncols2_img; +int r1, c1; /* Central (or around the central) point of the first img */ +int r2, c2; /* Corresponding point in the second img */ +int r2c, c2c; /* Central point of the first img */ + +char *group_name; +char *group_MAPSET; +char *group_LOCATION_NAME; +char *group_GISDBASE; +int q; +FILE *fp; +FILE *fp_old; +/*int i;*/ +char file_name[500]; + +char name1[100]; +char name2[100]; +char mapset[100]; + +int dist_r, dist_c; + +int z; + + +int n_points=0; /* When "LESS_GCP's" is activated, then (n_points==0) */ +int man_op=0; /* Variable for the option "Manual_OP". It's 1 if the option is activated */ +double e_man2, n_man2; /* Coordinates for the manual_OP */ +int man_m_s_op=0; +double e_man1, n_man1; + +View *m1, *m2; + + + + +int min(int a, int b) +{ + + if(a <= b) + { + return a; + } + else + { + return b; + } +} + +static int main_menu(); +static int cancel(); +static int shift1(); +static int shift2(); + +static int less_GCPs(); +static int manual_op(); +static int manual_op1(); +static int mark_op(int x,int y,int button); +static int mark_point_op (View *view,int x, int y); + +static int central(); +static int top(); +static int bottom(); +static int left(); +static int right(); + +static int manual_m_s_op(); +static int manual_m_s_op1(); +static int mark_m_s_op(int x,int y,int button); +static int mark_point_m_s_op (View *view,int x, int y); + +/* variables for function "TRY_AGAIN" */ +char name1_initial[100]; +char name2_initial[100]; +char mapset_initial[100]; +static int try_again(); +static int store_points(); + + + + +/* Variables and functions for the Auto-Exclusion */ +static int curp, first_point; +static double *xres, *yres, *gnd, *tres, *ures, *lgnd; +static int offsetx, offsety; +static int xmax, ymax, gmax; +static int tmax, umax, lgmax; +static double rms,l_rms; +static double th=2.5; /*Default threshold of the rms for the Auto-Exclusion.*/ +char file_name1[500]; +static int auto_exclusion(); +static int change_rms_th(); +static int compute_transformation(void); +static int th_1(); +static int th_2(); +static int th_3(); +static int th_4(); +static int th_5(); +static int other_th(); +static int pre_analyze(); + + + + + + + + + +int automated_search() +{ + + static int use = 1; + + ask_original_map ("raster", group_list, name1,mapset, -1); + ask_original_map ("raster", group_list, name2,mapset, 1); + + + + static Objects objects1[]= + { + MENU(" MAIN MENU ",cancel,&use), + INFO(" O.P. -> ",&use), + MENU(" Central ",central,&use), + MENU(" Top ",top,&use), + MENU(" Bottom ",bottom,&use), + MENU(" Left ",left,&use), + MENU(" Right ",right,&use), + INFO(" ",&use), + MENU(" LESS GCPs ",less_GCPs,&use), + MENU(" Mark Slave-O.P. ",manual_op,&use), + MENU(" Mark M&S-O.P. ",manual_m_s_op,&use), + {0} + }; + + + Input_pointer (objects1); + + m=0; + + return 0; + +} + + + + + + +void Extract_matrix() +{ + struct GModule *module; + struct Control_Points *cp1; + char buf[256]; + char *s; + int rows, cols; + + char *first_map_R_mapset; + char *first_map_R_name; + int first_map_R_fd; + char *second_map_R_mapset; + char *second_map_R_name; + int second_map_R_fd; + + int K; + + int correlation_window_dim; + int search_window_dim; + int search_window_dim1; + int search_window_dim2; + + + int squared_search_window_dim; + int search_jump; + + int left1, top1, left2, top2; + int repeat; + + int n_1, e_1, n_2, e_2, s_1, s_2, w_1, w_2; + int r1_1, r1_2, r2_1, r2_2; + int c1_1, c1_2, c2_1, c2_2; + + int i; + + int h1_r; + int h1_c; + int h2_r; + int h2_c; + + + DCELL *rowbuf1_R; + DCELL *tf1_R; + DCELL *rowbuf2_R; + DCELL *tf2_R; + double **search_window; + double **mat1,**mat2; + int r,c; + int search_border; + int p1; + int dim_win_c, dim_win_r; + char first_sites[500]; + char second_sites[500]; + char file_name_old[500]; + FILE *first_fp; + FILE *second_fp; + + int xp1, yp1, xs1, ys1; + int xp2, yp2, xs2, ys2; + int nimg; + + static int use = 1; + + + + + if(n==1) + { + m1=VIEW_MAP1; + m2=VIEW_MAP2; + } + + else + { + + if( (r2 >= r1) && (c2 >= c1 ) ) + { + xp1 = (c1 - (min(c1,c2)))+1; + xp2 = (c2 - (c1-xp1)); + xs2 = (c2 + min((ncols1-c1),(ncols2-c2)))-1; + xs1 = (c1 + (xs2 - c2)); + yp1 = (r1 - (min(r1,r2)))+1; + yp2 = (r2 - (r1 - yp1)); + ys2 = (r2 + min((nrows1-r1),(nrows2-r2)))-1; + ys1 = (r1 + (ys2 - r2)); + } + else if( (r2 <= r1) && (c2 <= c1) ) + { + xp2 = (c2 - (min(c2,c1)))+1; + xp1 = (c1 - (c2 - xp2)); + xs1 = (c1 + min((ncols1-c1),(ncols2-c2)))-1; + xs2 = (c2 + (xs1 - c1)); + yp2 = (r2 - min(r2,r1))+1; + yp1 = (r1 - (r2 - yp2)); + ys1 = (r1 + min((nrows1-r1),(nrows2-r2)))-1; + ys2 = (r2 + (ys1 - r1)); + } + else if( (r2 >= r1) && (c2 <= c1) ) + { + xp2 = (c2 - min(c2,c1))+1; + xp1 = (c1 - (c2 - xp2)); + xs1 = (c1 + min((ncols1-c1),(ncols2-c2)))-1; + xs2 = (c2 + (xs1 - c1)); + yp1 = (r1 - min(r1,r2))+1; + yp2 = (r2 - (r1 - yp1)); + ys2 = (r2 + min((nrows1-r1),(nrows2-r2)))-1; + ys1 = (r1 + (ys2 - r2)); + } + else if( (r2 <= r1) && (c2 >= c1) ) + { + xp1 = (c1 - min(c1,c2))+1; + xp2 = (c2 - (c1 - xp1)); + xs2 = (c2 + min((ncols2-c2),(ncols1-c1)))-1; + xs1 = (c1 + (xs2 - c2)); + yp2 = (r2 - min(r1,r2))+1; + yp1 = (r1 - (r2 - yp2)); + ys1 = (r1 + min((nrows1-r1),(nrows2-r2)))-1; + ys2 = (r2 + (ys1 - r1)); + } + + + /* overlap_area(): function that extracts a window from the angle-points + * top_left (xp1, yp1) and down_right (xs1, ys1) + */ + nimg = 1; + overlap_area(xp1, yp1, xs1, ys1, nimg, ncols1, nrows1); + + + nimg = 2; + overlap_area(xp2, yp2, xs2, ys2, nimg, ncols2, nrows2); + + + m1=VIEW_MAP1_ZOOM; + m2=VIEW_MAP2_ZOOM; + + } + + + + first_map_R_name=m1->cell.name; + second_map_R_name=m2->cell.name; + + + + + + /* rows & cols of the view in m1 */ + n_1=m1->cell.head.north; + e_1=m1->cell.head.east; + s_1=m1->cell.head.south; + w_1=m1->cell.head.west; + left1 = m1->cell.left; + top1 = m1->cell.top; + + r1_1=s_1/m1->cell.ns_res; + r1_2=n_1/m1->cell.ns_res; + c1_1=w_1/m1->cell.ew_res; + c1_2=e_1/m1->cell.ew_res; + + nrows1=r1_2-r1_1; + ncols1=c1_2-c1_1; + + + /* rows & cols of the view in m2 */ + n_2=m2->cell.head.north; + e_2=m2->cell.head.east; + s_2=m2->cell.head.south; + w_2=m2->cell.head.west; + left2 = m2->cell.left; + top2 = m2->cell.top; + + r2_1=s_2/m2->cell.ns_res; + r2_2=n_2/m2->cell.ns_res; + c2_1=w_2/m2->cell.ew_res; + c2_2=e_2/m2->cell.ew_res; + + nrows2=r2_2-r2_1; + ncols2=c2_2-c2_1; + + + if(n==1) + { + nrows1_img = nrows1; + ncols1_img = ncols1; + nrows2_img = nrows2; + ncols2_img = ncols2; + } + + + /* Initialize the GIS calls */ + module = G_define_module(); + module->description = "Fine registration of two stereo images"; + + /* Load environmental vars*/ + group_LOCATION_NAME=buf; + group_LOCATION_NAME=G_getenv("LOCATION_NAME"); + group_GISDBASE=buf; + group_GISDBASE=G_getenv("GISDBASE"); + group_MAPSET=buf; + group_MAPSET=G_getenv("MAPSET"); + + + if(n==1) + { + + strcpy (name1_initial,first_map_R_name); + strcpy (name2_initial,second_map_R_name); + strcpy (mapset_initial,group_MAPSET); + + } + + + /* Correlation parameters */ + if(n==1) + { + + if(ncols1 <= nrows1) + { + search_window_dim1 = ncols1; + } + else + { + search_window_dim1 = nrows1; + } + + if(ncols2 <= nrows2) + { + search_window_dim2 = ncols2; + } + else + { + search_window_dim2 = nrows2; + } + + + + if(search_window_dim1 <= search_window_dim2) + { + search_window_dim = search_window_dim1; + } + else + { + search_window_dim = search_window_dim2; + } + } + + + else if(n==2) + { + correlation_window_dim=((ncols1/10+nrows1/10)/4); + + + + if(n_points==1) + { + + K=((ncols1/4+nrows1/4)/3); + search_window_dim = (correlation_window_dim + K); + n_points = 0; + + } + else + { + + K=((ncols1/4+nrows1/4)/8); + search_window_dim = G_math_max_pow2(correlation_window_dim + K); + + } + + + + search_jump=search_window_dim / 2; + } + + + + + group_name=group.name; + squared_search_window_dim=search_window_dim*search_window_dim; + + + if(n==1) + { + Menu_msg ("Loading first image..."); + } + + else + { + Menu_msg ("Loading first overlapping_image..."); + } + + /* Open first real map*/ + + if((first_map_R_mapset = G_find_cell2(first_map_R_name, "")) == NULL) + { + sprintf(buf,"Raster map [%s] not available",first_map_R_name); + G_fatal_error(buf); + } + + + if((first_map_R_fd = G_open_cell_old(first_map_R_name, + first_map_R_mapset)) < 0) + { + sprintf(buf,"Error opening raster map [%s]", first_map_R_name); + G_fatal_error(buf); + } + + /* Set region to first map definition region < m1 > */ + G_get_cellhd (first_map_R_name, first_map_R_mapset, &cellhd1); + G_set_window(&cellhd1); + h1_r=cellhd1.rows; + h1_c=cellhd1.cols; + + + + /* Memory allocation for the first overlapping_map */ + + mat1 = (DCELL **) G_calloc(nrows1,sizeof(DCELL *)); + for(r=0;rcell.ns_res; + cellhd1.south=r1_1*m1->cell.ns_res; + cellhd1.east=c1_2*m1->cell.ew_res; + cellhd1.west=c1_1*m1->cell.ew_res; + + /* Set cellhd2 to overlapping_map_2 */ + cellhd2.rows=nrows2; + cellhd2.cols=ncols2; + cellhd2.north=r2_2*m2->cell.ns_res; + cellhd2.south=r1_1*m2->cell.ns_res; + cellhd2.east=c2_2*m2->cell.ew_res; + cellhd2.west=c2_1*m2->cell.ew_res; + + /* Set windows to cellhd1 */ + G_set_window(&cellhd1); + + + + /******************************************/ + /* function --> Search_correlation_points */ + /******************************************/ + Search_correlation_points(mat1, mat2, + search_window_dim, + squared_search_window_dim, + search_jump,group_name, nrows1, ncols1, + search_window, r1_2, c1_1, r2_2, c2_1, + h1_r, h2_r, h1_c, h2_c, nrows2, ncols2, n ); + + + + + sprintf(file_name,"%s/%s/%s/group/%s/TARGET",group_GISDBASE, + group_LOCATION_NAME, group_MAPSET,group_name); + fp = fopen(file_name,"w"); + fprintf(fp,"%s\n%s\n",group_LOCATION_NAME,group_MAPSET); + fclose(fp); + + + if(n==2) + { + + G_get_cellhd (name1, mapset, &cellhd1); + G_adjust_window_to_box (&cellhd1, &VIEW_MAP1->cell.head, VIEW_MAP1->nrows, VIEW_MAP1->ncols); + Configure_view (VIEW_MAP1, name1, mapset, cellhd1.ns_res, cellhd1.ew_res); + drawcell(VIEW_MAP1); + display_points(1); + R_flush(); + Curses_clear_window (PROMPT_WINDOW); + + + G_get_cellhd (name2, mapset, &cellhd2); + G_adjust_window_to_box (&cellhd2, &VIEW_MAP2->cell.head, VIEW_MAP2->nrows, VIEW_MAP2->ncols); + Configure_view (VIEW_MAP2, name2, mapset, cellhd2.ns_res, cellhd2.ew_res); + drawcell(VIEW_MAP2); + display_points(1); + R_flush(); + Curses_clear_window (PROMPT_WINDOW); + + nimg = 1; + overlap_area(xp1, yp1, xs1, ys1, nimg, ncols1_img, nrows1_img); + + nimg = 2; + overlap_area(xp2, yp2, xs2, ys2, nimg, ncols2_img, nrows2_img); + + + } + + + + select_current_env (); + + + display_points_in_view_diff_color (VIEW_MAP1, 1, + sPoints.e1, sPoints.n1, + sPoints.status, sPoints.count); + + + display_points_in_view_diff_color (VIEW_MAP2, 1, + sPoints.e2, sPoints.n2, + sPoints.status, sPoints.count); + + + + + display_points_in_view_diff_color (VIEW_MAP1_ZOOM, 1, + sPoints.e1, sPoints.n1, + sPoints.status, sPoints.count); + + + + display_points_in_view_diff_color (VIEW_MAP2_ZOOM, 1, + sPoints.e2, sPoints.n2, + sPoints.status, sPoints.count); + + R_flush(); + + + + if(n==2) + { + + static Objects objects[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" STORE POINTS IN FILE ",store_points,&use), + MENU(" TRY AGAIN ",try_again,&use), + INFO(" ",&use), + MENU(" rms-th ",change_rms_th,&use), + MENU(" Auto-Exclusion GCPs ",auto_exclusion,&use), + {0} + }; + + Input_pointer (objects); + + + return 0; + } + + + + + + /* Free memory */ + + free( rowbuf1_R); + free( rowbuf2_R); + + + for(r=0;r cross-correlation at differnet lag + between the two orig. (complex) windows */ + fft(1,fft_prod_con,squared_search_window_dim,search_window_dim, + search_window_dim); + + + + + /* Search the lag coresponding to the maximum correlation */ + cc = 0.0; + + for(i=0;i cc) + { + cc = fft_prod_con[0][i]; + tmp_r=i/search_window_dim; + tmp_c=i%search_window_dim; + + } + } + + + + + /* Get coordinates of "ending" point */ + if((tmp_r <= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c1 - tmp_c,&cellhd2) + dist_c; + north2 = G_row_to_northing((double) r1 - tmp_r,&cellhd2) + dist_r; + + } + if((tmp_r <= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c1 - (tmp_c-search_window_dim-1),&cellhd2) + dist_c; + north2 = G_row_to_northing((double) r1 - tmp_r,&cellhd2) + dist_r; + + } + if((tmp_r >= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c1 - tmp_c,&cellhd2) + dist_c; + north2 = G_row_to_northing((double) r1 - (tmp_r-search_window_dim-1),&cellhd2) + dist_r; + + } + if((tmp_r >= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c1 - (tmp_c-search_window_dim-1),&cellhd2) + dist_c; + north2 = G_row_to_northing((double) r1 - (tmp_r-search_window_dim-1),&cellhd2) + dist_r; + + } + + + + r2 = G_northing_to_row(north2,&cellhd2); + c2 = G_easting_to_col(east2,&cellhd2); + + sPoints.e1[sPoints.count-1] = east1; + sPoints.n1[sPoints.count-1] = north1; + sPoints.e2[sPoints.count-1] = east2; + sPoints.n2[sPoints.count-1] = north2; + } + + + + + else if(man_op==1) + { + + east1 = G_col_to_easting((double) c1, &cellhd1); + north1 = G_row_to_northing((double) r1, &cellhd1); + + + sPoints.e1[sPoints.count-1] = east1; + sPoints.n1[sPoints.count-1] = north1; + + + + R_standard_color (BLUE); + display_one_point(VIEW_MAP1,east1,north1); + + + manual_op1(); + + + east2 = e_man2; + north2 = n_man2; + + + r2 = G_northing_to_row(north2,&cellhd2); + c2 = G_easting_to_col(east2,&cellhd2); + + + sPoints.e2[sPoints.count-1] = east2; + sPoints.n2[sPoints.count-1] = north2; + + display_points_in_view_diff_color (VIEW_MAP2, 1, + sPoints.e2, sPoints.n2, + sPoints.status, sPoints.count); + + + + R_flush(); + + + } + + + + + /* Fill the POINTS file*/ + sPoints.status[sPoints.count-1] = 1; + sPoints.count += 1; + sPoints.e1=(double *)G_realloc(sPoints.e1,sPoints.count*sizeof(double)); + sPoints.n1=(double *)G_realloc(sPoints.n1,sPoints.count*sizeof(double)); + sPoints.e2=(double *)G_realloc(sPoints.e2,sPoints.count*sizeof(double)); + sPoints.n2=(double *)G_realloc(sPoints.n2,sPoints.count*sizeof(double)); + sPoints.status=(int *)G_realloc(sPoints.status,sPoints.count*sizeof(int)); + + + } + + + else if( (n==1) && (man_m_s_op==1) ) + { + manual_m_s_op1(); + + east1 = e_man1; + north1 = n_man1; + + r1 = G_northing_to_row(north1,&cellhd1); + c1 = G_easting_to_col(east1,&cellhd1); + + + sPoints.e1[sPoints.count-1] = east1; + sPoints.n1[sPoints.count-1] = north1; + + + R_standard_color (BLUE); + display_one_point(VIEW_MAP1,east1,north1); + + + + manual_op1(); + + + east2 = e_man2; + north2 = n_man2; + + + r2 = G_northing_to_row(north2,&cellhd2); + c2 = G_easting_to_col(east2,&cellhd2); + + + sPoints.e2[sPoints.count-1] = east2; + sPoints.n2[sPoints.count-1] = north2; + + + display_points_in_view_diff_color (VIEW_MAP2, 1, + sPoints.e2, sPoints.n2, + sPoints.status, sPoints.count); + + + + R_flush(); + + + /* Fill the POINTS file*/ + sPoints.status[sPoints.count-1] = 1; + sPoints.count += 1; + sPoints.e1=(double *)G_realloc(sPoints.e1,sPoints.count*sizeof(double)); + sPoints.n1=(double *)G_realloc(sPoints.n1,sPoints.count*sizeof(double)); + sPoints.e2=(double *)G_realloc(sPoints.e2,sPoints.count*sizeof(double)); + sPoints.n2=(double *)G_realloc(sPoints.n2,sPoints.count*sizeof(double)); + sPoints.status=(int *)G_realloc(sPoints.status,sPoints.count*sizeof(int)); + + + + } + + + + + else + { + + + /*Begin computation*/ + search_border = search_window_dim / 2; + + for(r = search_border; r < dim_win_r - search_border; r += search_jump) + { + for(c = search_border; c < dim_win_c - search_border; c += search_jump) + { + + /* Reinizialize fft vectors */ + + for(i=0;i=nrows2)||(c-search_border+2*search_border>=ncols2)) + { + if (sPoints.count<=1) + { + Menu_msg("DEFINE A NEW REGION."); + sleep(3); + pause; + } + return 0; + } + + Extract_portion_of_double_matrix(r,c,search_border,search_border, + mat2_R,search_window); + mean = 0.0; + for(i=0;i cross-correlation at differnet lag + between the two orig. (complex) windows */ + fft(1,fft_prod_con,squared_search_window_dim,search_window_dim, + search_window_dim); + + + + + + /* Search the lag coresponding to the maximum correlation */ + cc = 0.0; + + for(i=0;i cc) + { + cc = fft_prod_con[0][i]; + tmp_r=i/search_window_dim; + tmp_c=i%search_window_dim; + + } + } + + /* Get coordinates of "ending" point */ + if((tmp_r <= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - tmp_c,&cellhd2); + north2 = G_row_to_northing((double) r - tmp_r,&cellhd2); + + } + if((tmp_r <= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - (tmp_c-search_window_dim-1),&cellhd2); + north2 = G_row_to_northing((double) r - tmp_r,&cellhd2); + + } + if((tmp_r >= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - tmp_c,&cellhd2); + north2 = G_row_to_northing((double) r - (tmp_r-search_window_dim-1),&cellhd2); + + } + if((tmp_r >= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - (tmp_c-search_window_dim-1),&cellhd2); + north2 = G_row_to_northing((double) r - (tmp_r-search_window_dim-1),&cellhd2); + + } + + + + /* Fill the POINTS file*/ + sPoints.e1[sPoints.count-1] = east1; + sPoints.n1[sPoints.count-1] = north1; + sPoints.e2[sPoints.count-1] = east2; + sPoints.n2[sPoints.count-1] = north2; + + sPoints.status[sPoints.count-1] = 1; + sPoints.count += 1; + sPoints.e1=(double *)G_realloc(sPoints.e1,sPoints.count*sizeof(double)); + sPoints.n1=(double *)G_realloc(sPoints.n1,sPoints.count*sizeof(double)); + sPoints.e2=(double *)G_realloc(sPoints.e2,sPoints.count*sizeof(double)); + sPoints.n2=(double *)G_realloc(sPoints.n2,sPoints.count*sizeof(double)); + sPoints.status=(int *)G_realloc(sPoints.status,sPoints.count*sizeof(int)); + } + G_percent (r,dim_win_r, 1); + } + + + + } + +} + +void Extract_portion_of_double_matrix(int r,int c,int br,int bc,DCELL **mat,DCELL **wind) + /* + extract a squared portion of a matrix mat + given a the indeces of the center [r,c] + and the semilength of the borders [br,bc] + Output to array wind + */ +{ + int i,j; + for(i=0;(i <2*br);i++) + for(j = 0;(j <2*bc);j++) + { + wind[i][j] = mat[r - br + i][c - bc +j]; + } +} + + + + + + + +static int less_GCPs() +{ + + n_points = 1; + + return 0; +} + + + + + +static int manual_op() +{ + man_op = 1; + + n=1; + + Extract_matrix(); + + return 0; +} + + + + +static int manual_op1() +{ + + static int use = 1; + + + static Objects objects[] = + { + INFO(" Mark on the second img the Overlap-Point ",&use), + OTHER(mark_op, &use), + {0} + }; + + Input_pointer (objects); + Menu_msg (""); + + + + return 0; + + +} + + + + + +static int mark_op(int x,int y,int button) +{ + + static int use = 1; + + if (button != 1) + return where (x,y); + + if (VIEW_MAP2->cell.configured && In_view (VIEW_MAP2, x, y)) + mark_point_op(VIEW_MAP2, x, y); + + else + return 0; + + return -1 ; /* return but don't quit */ +} + + + + +static int mark_point_op (View *view,int x, int y) +{ + + /* convert x,y to east,north at center of cell */ + c2= view_to_col (view, x); + e_man2 = col_to_easting (&view->cell.head, c2, 0.5); + r2= view_to_row (view, y); + n_man2 = row_to_northing (&view->cell.head, r2, 0.5); + + + + return 0 ; + + +} + + + +static int manual_m_s_op() +{ + man_m_s_op = 1; + + n=1; + + Extract_matrix(); + + + return 0; +} + + +static int manual_m_s_op1() +{ + + static int use = 1; + + + static Objects objects[] = + { + INFO(" Mark on the first img the Overlap-Point ",&use), + OTHER(mark_m_s_op, &use), + {0} + }; + + Input_pointer (objects); + Menu_msg (""); + + + return 0; +} + + +static int mark_m_s_op(int x,int y,int button) +{ + + static int use = 1; + + if (button != 1) + return where (x,y); + + if (VIEW_MAP1->cell.configured && In_view (VIEW_MAP1, x, y)) + mark_point_m_s_op(VIEW_MAP1, x, y); + + else + return 0; + + return -1 ; /* return but don't quit */ +} + + + + +static int mark_point_m_s_op (View *view,int x, int y) +{ + + /* convert x,y to east,north at center of cell */ + c1= view_to_col (view, x); + e_man1 = col_to_easting (&view->cell.head, c1, 0.5); + r1= view_to_row (view, y); + n_man1 = row_to_northing (&view->cell.head, r1, 0.5); + + + + return 0 ; + + +} + + + + +static int central() +{ + n=1; + pos_point = 0; + man_op=0; + + Extract_matrix(); + + return 0; + +} + + +static int shift1() +{ + double nn_1,ee_1,ss_1,ww_1,rr1_1,rr1_2,cc1_1,cc1_2,nnrows1,nncols1; + int shift1; + + nn_1=VIEW_MAP1->cell.head.north; + ee_1=VIEW_MAP1->cell.head.east; + ss_1=VIEW_MAP1->cell.head.south; + ww_1=VIEW_MAP1->cell.head.west; + + rr1_1=ss_1/VIEW_MAP1->cell.ns_res; + rr1_2=nn_1/VIEW_MAP1->cell.ns_res; + cc1_1=ww_1/VIEW_MAP1->cell.ew_res; + cc1_2=ee_1/VIEW_MAP1->cell.ew_res; + + nnrows1=rr1_2-rr1_1; + nncols1=cc1_2-cc1_1; + + + + shift1 = (((nnrows1 + nncols1)/2)/100)*5; + + switch (pos_point) + { + + case 1: dist = shift1; + dist_r = -shift1; + dist_c = 0; + break; + case 2: dist = shift1; + dist_r = shift1; + dist_c = 0; + break; + case 3: dist = shift1; + dist_c = shift1; + dist_r = 0; + break; + case 4: dist = shift1; + dist_c = -shift1; + dist_r = 0; + break; + } + + + + Extract_matrix(); + + return 0; +} + + + + +static int shift2() +{ + + double nn_1,ee_1,ss_1,ww_1,rr1_1,rr1_2,cc1_1,cc1_2,nnrows1,nncols1; + int shift2; + + nn_1=VIEW_MAP1->cell.head.north; + ee_1=VIEW_MAP1->cell.head.east; + ss_1=VIEW_MAP1->cell.head.south; + ww_1=VIEW_MAP1->cell.head.west; + + rr1_1=ss_1/VIEW_MAP1->cell.ns_res; + rr1_2=nn_1/VIEW_MAP1->cell.ns_res; + cc1_1=ww_1/VIEW_MAP1->cell.ew_res; + cc1_2=ee_1/VIEW_MAP1->cell.ew_res; + + nnrows1=rr1_2-rr1_1; + nncols1=cc1_2-cc1_1; + + + + shift2 = (((nnrows1 + nncols1)/2)/100)*10; + + + + switch (pos_point) + { + + case 1: dist = shift2; + dist_r = -shift2; + dist_c = 0; + break; + case 2: dist = shift2; + dist_r = shift2; + dist_c = 0; + break; + case 3: dist = shift2; + dist_c = shift2; + dist_r = 0; + break; + case 4: dist = shift2; + dist_c = -shift2; + dist_r = 0; + break; + } + + + + Extract_matrix(); + + return 0; +} + + + + + +static int top() +{ + static int use = 1; + + n=1; + pos_point = 1; + man_op=0; + + static Objects objects2[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" <-- ",cancel,&use), + INFO(" Shift O.P. (% of map) -> ",&use), + MENU(" 5% ",shift1,&use), + MENU(" 10% ",shift2,&use), + {0} + }; + + Input_pointer (objects2); + + + return 0; + +} + + + + + +static int bottom() +{ + static int use = 1; + + n=1; + pos_point = 2; + man_op=0; + + static Objects objects3[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" <-- ",cancel,&use), + INFO(" Shift O.P. (% of map) -> ",&use), + MENU(" 5% ",shift1,&use), + MENU(" 10% ",shift2,&use), + {0} + }; + + Input_pointer (objects3); + + + return 0; + +} + + + +static int left() +{ + static int use = 1; + + n=1; + pos_point = 3; + man_op=0; + + static Objects objects4[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" <-- ",cancel,&use), + INFO(" Shift O.P. (% of map) -> ",&use), + MENU(" 5% ",shift1,&use), + MENU(" 10% ",shift2,&use), + {0} + }; + + Input_pointer (objects4); + + + return 0; + +} + + + +static int right() +{ + static int use = 1; + + n=1; + pos_point = 4; + man_op=0; + + static Objects objects5[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" <-- ",cancel,&use), + INFO(" Shift O.P. (% of map) -> ",&use), + MENU(" 5% ",shift1,&use), + MENU(" 10% ",shift2,&use), + {0} + }; + + Input_pointer (objects5); + + + return 0; + +} + + + + + + +static int try_again() +{ + + static int use = 1; + + G_get_cellhd (name1_initial, mapset_initial, &cellhd1); + G_adjust_window_to_box (&cellhd1, &VIEW_MAP1->cell.head, VIEW_MAP1->nrows, VIEW_MAP1->ncols); + Configure_view (VIEW_MAP1, name1_initial, mapset_initial, cellhd1.ns_res, cellhd1.ew_res); + drawcell(VIEW_MAP1); + display_points(1); + R_flush(); + Curses_clear_window (PROMPT_WINDOW); + + Erase_view (VIEW_MAP1_ZOOM); + + + G_get_cellhd (name2_initial, mapset_initial, &cellhd2); + G_adjust_window_to_box (&cellhd2, &VIEW_MAP2->cell.head, VIEW_MAP2->nrows, VIEW_MAP2->ncols); + Configure_view (VIEW_MAP2, name2_initial, mapset_initial, cellhd2.ns_res, cellhd2.ew_res); + drawcell(VIEW_MAP2); + display_points(1); + R_flush(); + Curses_clear_window (PROMPT_WINDOW); + + Erase_view (VIEW_MAP2_ZOOM); + + + static Objects objects3[]= + { + + + MENU(" MAIN MENU ",cancel,&use), + INFO(" O.P. -> ",&use), + MENU(" Central ",central,&use), + MENU(" Top ",top,&use), + MENU(" Bottom ",bottom,&use), + MENU(" Left ",left,&use), + MENU(" Right ",right,&use), + INFO(" ",&use), + MENU(" LESS GCPs ",less_GCPs,&use), + MENU(" Mark Slave-O.P. ",manual_op,&use), + MENU(" Mark M&S-O.P. ",manual_m_s_op,&use), + {0} + }; + + + Input_pointer (objects3); + + return 0; +} + + + + + + + + + +static int store_points() +{ + + int i; + + + sPoints.count -= 1; + if(sPoints.count > 0) + { + + sprintf(file_name,"%s/%s/%s/group/%s/POINTS",group_GISDBASE, + group_LOCATION_NAME,group_MAPSET,group_name); + + fp = fopen(file_name,"w"); + fprintf (fp,"# %7s %15s %15s %15s %9s status\n","", + "provaimage","","target",""); + fprintf (fp,"# %15s %15s %15s %15s (1=ok)\n", + "east","north","east","north"); + fprintf (fp,"#\n"); + + for (i = 1; i < sPoints.count; i++) /* i=1 because the sPoints[0] is the O.P. */ + if ( sPoints.status[i] != -1) + fprintf (fp, " %15f %15f %15f %15f %4d\n", + sPoints.e1[i], sPoints.n1[i], sPoints.e2[i], sPoints.n2[i], sPoints.status[i]); + + + fclose (fp); + } + + + + /* Load new control points */ + + for (i = 1; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + I_new_control_point (&group.points,sPoints.e1[i], sPoints.n1[i], + sPoints.e2[i], sPoints.n2[i], sPoints.status[i] ); + + + + m=1; /* To directly return to the main menu */ + + + return 0; + +} + + + + + +static int main_menu() +{ + m=1; + + return 0; +} + + +static int +cancel (void) +{ + return -1; +} + + + + + + +static int change_rms_th() +{ + static int use = 1; + + static Objects objects[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" <-- ",cancel,&use), + INFO(" ",&use), + MENU(" 1 ",th_1,&use), + MENU(" 2 ",th_2,&use), + MENU(" 3 ",th_3,&use), + MENU(" 4 ",th_4,&use), + MENU(" 5 ",th_5,&use), + MENU(" OTHER ",other_th,&use), + /* + OPTION(" 1 ", 2, &after_OPTION_out), + OPTION(" 2 ", 2, &temp_th_2), + OPTION(" 3 ", 2, &temp_th_3), + OPTION(" 4 ", 2, &temp_th_4), + OPTION(" 5 ", 2, &temp_th_5),*/ + {0} + }; + + + + Input_pointer (objects); + + + return 0; +} + + + +static int after_th() +{ + static int use = 1; + + + static Objects objects3[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" STORE POINTS IN FILE ",store_points,&use), + MENU(" TRY AGAIN ",try_again,&use), + INFO(" ",&use), + MENU(" rms-th ",change_rms_th,&use), + MENU(" Auto-Exclusion GCPs ",auto_exclusion,&use), + {0} + }; + + + Input_pointer (objects3); + + + + return 0; +} + + + + + + +static int th_1() +{ + th=1; + + after_th(); + + return 0; +} + + +static int th_2() +{ + th=2; + + after_th(); + + return 0; +} + + +static int th_3() +{ + th=3; + + after_th(); + + return 0; +} + + +static int th_4() +{ + th=4; + + after_th(); + + return 0; +} + +static int th_5() +{ + th=5; + + after_th(); + + return 0; +} + + + +static int other_th() +{ + char buf[100]; + double tmp_th; + + G_clear_screen(); + + while(1) + { + Curses_prompt_gets ("Insert the rms-threshold desired: ", buf); + sscanf (buf, "%lf", &tmp_th); + if(tmp_th!=0) break; + + } + + th = tmp_th; + + after_th(); + + return 0; +} + + + + + +int auto_exclusion(void) +{ + int k; + int i; + static int use = 1; + + sPoints.count = sPoints.count -1; + + /* Load new control points */ + + for (i = 1; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + I_new_control_point (&group.points,sPoints.e1[i], sPoints.n1[i], + sPoints.e2[i], sPoints.n2[i], sPoints.status[i] ); + + + + + first_point = 0; + + /* allocate predicted values */ + xres = (double *) G_calloc (group.points.count, sizeof (double)); + yres = (double *) G_calloc (group.points.count, sizeof (double)); + gnd = (double *) G_calloc (group.points.count, sizeof (double)); + + + compute_transformation(); + + + while(rms>=th) + { + for(k=0; k < group.points.count; k++) + { + + if(group.equation_stat > 0 && group.points.status[k]==1) + { + + if (k == xmax || k == ymax || k == gmax) + { + group.points.status[k] = 0; + } + } + compute_transformation(); + + } + } + display_points(1); + + + + static Objects objects[]= + { + MENU(" MAIN MENU ",main_menu,&use), + MENU(" ANALYZE & STORE ",pre_analyze,&use), + {0} + }; + + Input_pointer (objects); + + + free (xres); free (yres); free (gnd); + + return 0; +} + + + +static int pre_analyze() +{ + + analyze(); + + m=1; + + return 0; +} + + + + + + +static int compute_transformation (void) +{ + int n, count; + double d,d1,d2,sum; + double e1, e2, n1, n2; + double t1, t2, u1, u2; + double xval, yval, gval; + double tval, uval, lgval; + + xmax = ymax = gmax = 0; + xval = yval = gval = 0.0; + + Compute_equation(); + + /* compute the row,col error plus ground error + * keep track of largest and second largest error + */ + sum = 0.0; + rms = 0.0; + count = 0; + for (n = 0; n < group.points.count && group.equation_stat>0; n++) + { + if (group.points.status[n] !=1) continue; + count++; + georef (group.points.e2[n], group.points.n2[n], &e1, &n1, group.E21, group.N21); + georef (group.points.e1[n], group.points.n1[n], &e2, &n2, group.E12, group.N12); + + if((d = xres[n] = e1-group.points.e1[n]) < 0) + d = -d; + if (d > xval) + { + xmax = n; + xval = d; + } + + if ((d = yres[n] = n1-group.points.n1[n]) < 0) + d = -d; + if (d > yval) + { + ymax = n; + yval = d; + } + + /* compute ground error (ie along diagonal) */ + d1 = e2 - group.points.e2[n]; + d2 = n2 - group.points.n2[n]; + d = d1*d1 + d2*d2; + sum += d; /* add it to rms sum, before taking sqrt */ + d = sqrt(d); + gnd[n] = d; + if (d > gval) /* is this one the max? */ + { + gmax = n; + gval = d; + } + + } + /* compute overall rms error */ + if (count) + rms = sqrt (sum/count); + + + return 0; +} + + + + + + Property changes on: trunk/grassaddons/i.points.auto/find_points.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/find_points_semi.c =================================================================== --- trunk/grassaddons/i.points.auto/find_points_semi.c (rev 0) +++ trunk/grassaddons/i.points.auto/find_points_semi.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,778 @@ +#include +#include +#include +#include + +#include +#ifdef HAVE_FFTW_H +#include +#endif +#ifdef HAVE_DFFTW_H +#include +#endif + +#include +#include +#include +#include "globals.h" +#include "local_proto.h" + +#ifdef NULL_VALUE +#undef NULL_VALUE +#endif +#define NULL_VALUE -1 + + +#ifdef DEBUG +#undef DEBUG +#endif + +double *fft_first_s[2]; +double *fft_second_s[2]; +double *fft_prod_con_s[2]; + +View *ms1, *ms2; + +void Extract_matrix_semi() +{ + struct GModule *module; + struct Control_Points *cp1; + char buf[256]; + char *s; + int rows, cols; + char *first_map_R_mapset; + char *first_map_R_name; + int first_map_R_fd; + char *second_map_R_mapset; + char *second_map_R_name; + int second_map_R_fd; + + int K; + + int correlation_window_dim; + int search_window_dim; + + int squared_search_window_dim; + int search_jump; + + int ncols1, ncols2, nrows1, nrows2; + int left1, top1, left2, top2; + int repeat; + + int n_1, e_1, n_2, e_2, s_1, s_2, w_1, w_2; + int r1_1, r1_2, r2_1, r2_2; + int c1_1, c1_2, c2_1, c2_2; + + int i; + + int h1_r; + int h1_c; + int h2_r; + int h2_c; + + + char *group_name; + char *group_MAPSET; + char *group_LOCATION_NAME; + char *group_GISDBASE; + DCELL *rowbuf1_R; + DCELL *tf1_R; + DCELL *rowbuf2_R; + DCELL *tf2_R; + double **search_window; + double **mat1,**mat2; + int r,c; + int search_border; + int q; + int p1; + int dim_win_c, dim_win_r; + char first_sites[500]; + char second_sites[500]; + char file_name[500]; + char file_name_old[500]; + FILE *first_fp; + FILE *second_fp; + FILE *fp; + FILE *fp_old; + + + + /* Read VIEW_MAP1_ZOOM & VIEW_MAP2_ZOOM informations */ + + + ms1=VIEW_MAP1_ZOOM; + ms2=VIEW_MAP2_ZOOM; + + first_map_R_name=ms1->cell.name; + second_map_R_name=ms2->cell.name; + + /* rows & cols of VIEW_MAP1_ZOOM */ + n_1=ms1->cell.head.north; + e_1=ms1->cell.head.east; + s_1=ms1->cell.head.south; + w_1=ms1->cell.head.west; + left1 = ms1->cell.left; + top1 = ms1->cell.top; + + r1_1=s_1/ms1->cell.ns_res; + r1_2=n_1/ms1->cell.ns_res; + c1_1=w_1/ms1->cell.ew_res; + c1_2=e_1/ms1->cell.ew_res; + + nrows1=r1_2-r1_1; + ncols1=c1_2-c1_1; + + + /* rows & cols of VIEW_MAP2_ZOOM */ + n_2=ms2->cell.head.north; + e_2=ms2->cell.head.east; + s_2=ms2->cell.head.south; + w_2=ms2->cell.head.west; + left2 = ms2->cell.left; + top2 = ms2->cell.top; + + r2_1=s_2/ms2->cell.ns_res; + r2_2=n_2/ms2->cell.ns_res; + c2_1=w_2/ms2->cell.ew_res; + c2_2=e_2/ms2->cell.ew_res; + + nrows2=r2_2-r2_1; + ncols2=c2_2-c2_1; + + + + /* Initialize the GIS calls */ + module = G_define_module(); + module->description = "Fine registration of two stereo images"; + + /* Load environmental vars*/ + group_LOCATION_NAME=buf; + group_LOCATION_NAME=G_getenv("LOCATION_NAME"); + group_GISDBASE=buf; + group_GISDBASE=G_getenv("GISDBASE"); + group_MAPSET=buf; + group_MAPSET=G_getenv("MAPSET"); + + + /* Correlation parameters */ + correlation_window_dim=((ncols1/10+nrows1/10)/2); + K=((ncols1/4+nrows1/4)/2); + + search_window_dim = G_math_max_pow2(correlation_window_dim + K); + group_name=group.name; + squared_search_window_dim=search_window_dim*search_window_dim; + search_jump=search_window_dim / 2; + + + + Menu_msg ("Loading first zoom_image..."); + + /* Open first real map*/ + if((first_map_R_mapset = G_find_cell2(first_map_R_name, "")) == NULL) + { + sprintf(buf,"Raster map [%s] not available",first_map_R_name); + G_fatal_error(buf); + } + + + if((first_map_R_fd = G_open_cell_old(first_map_R_name, + first_map_R_mapset)) < 0) + { + sprintf(buf,"Error opening raster map [%s]", first_map_R_name); + G_fatal_error(buf); + } + + /* Set region to first map definition region < ms1 > */ + G_get_cellhd (first_map_R_name, first_map_R_mapset, &cellhd1); + G_set_window(&cellhd1); + h1_r=cellhd1.rows; + h1_c=cellhd1.cols; + + + + /* Memory allocation for zoom_map_1 */ + + mat1 = (DCELL **) G_calloc(nrows1,sizeof(DCELL *)); + for(r=0;rcell.ns_res; + cellhd1.south=r1_1*ms1->cell.ns_res; + cellhd1.east=c1_2*ms1->cell.ew_res; + cellhd1.west=c1_1*ms1->cell.ew_res; + + /* Set cellhd2 to zoom_map_2 */ + cellhd2.rows=nrows2; + cellhd2.cols=ncols2; + cellhd2.north=r2_2*ms2->cell.ns_res; + cellhd2.south=r1_1*ms2->cell.ns_res; + cellhd2.east=c2_2*ms2->cell.ew_res; + cellhd2.west=c2_1*ms2->cell.ew_res; + + /* Set windows to cellhd1 */ + G_set_window(&cellhd1); + + + + /******************************************/ + /* function --> Search_correlation_points */ + /******************************************/ + Search_correlation_points_semi(mat1, mat2, + search_window_dim, + squared_search_window_dim, + search_jump,group_name, nrows1, ncols1, + search_window, r1_2, c1_1, r2_2, c2_1, + h1_r, h2_r, h1_c, h2_c, nrows2, ncols2 ); + + + + + /* Build group/POINTS file */ + sPoints.count -= 1; + if(sPoints.count > 0) + { + sprintf(file_name,"%s/%s/%s/group/%s/POINTS",group_GISDBASE, + group_LOCATION_NAME,group_MAPSET,group_name); + fp_old = fopen(file_name,"r"); + if( fp_old==NULL) + { + q=0; + } + else + { + q=1; + fclose(fp_old); + } + + if (q==0) + { + fp = fopen(file_name,"a"); + fprintf (fp,"# %7s %15s %15s %15s %9s status\n","", + "image","","target",""); + fprintf (fp,"# %15s %15s %15s %15s (1=ok)\n", + "east","north","east","north"); + fprintf (fp,"#\n"); + + for (i = 0; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + fprintf (fp, " %15f %15f %15f %15f %4d\n", + sPoints.e1[i], sPoints.n1[i], sPoints.e2[i], sPoints.n2[i], sPoints.status[i]); + + } + if(q==1) + { + fp = fopen(file_name,"a"); + for (i = 0; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + fprintf (fp, " %15f %15f %15f %15f %4d\n", sPoints.e1[i], sPoints.n1[i], sPoints.e2[i], sPoints.n2[i], sPoints.status[i]); + } + fclose (fp); + } + + /* Load new control points */ + + for (i = 0; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + I_new_control_point (&group.points,sPoints.e1[i], sPoints.n1[i], + sPoints.e2[i], sPoints.n2[i], sPoints.status[i] ); + + /* Build group/REF file */ + /* + sprintf(file_name,"%s/%s/%s/group/%s/REF",group_GISDBASE, + group_LOCATION_NAME, group_MAPSET,group_name); + fp = fopen(file_name,"w"); + fprintf(fp,"%s %s\n",first_map_R_name,first_map_R_mapset); + + fclose(fp); + */ + + /* Build group/TARGET file */ + sprintf(file_name,"%s/%s/%s/group/%s/TARGET",group_GISDBASE, + group_LOCATION_NAME, group_MAPSET,group_name); + fp = fopen(file_name,"w"); + fprintf(fp,"%s\n%s\n",group_LOCATION_NAME,group_MAPSET); + fclose(fp); + + /* Display new points */ + select_current_env (); + display_points_in_view (VIEW_MAP1, 1, + group.points.e1, group.points.n1, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP1_ZOOM, 1, + group.points.e1, group.points.n1, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP2, 1, + group.points.e2, group.points.n2, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP2_ZOOM, 1, + group.points.e2, group.points.n2, + group.points.status, group.points.count); + R_flush(); + + /* Free memory */ + + free( rowbuf1_R); + free( rowbuf2_R); + + + for(r=0;r=nrows2)||(c-search_border+2*search_border>=ncols2)) + { + if (sPoints.count<=1) + { + Menu_msg("DEFINE A NEW REGION."); + sleep(3); + pause; + } + return 0; + } + + Extract_portion_of_double_matrix_semi(r,c,search_border,search_border, + mat2_R,search_window); + mean = 0.0; + for(i=0;i cross-correlation at differnet lag + between the two orig. (complex) windows */ + fft(1,fft_prod_con_s,squared_search_window_dim,search_window_dim, + search_window_dim); + +#ifdef DEBUG + for(i=0;i cc) + { + cc = fft_prod_con_s[0][i]; + tmp_r=i/search_window_dim; + tmp_c=i%search_window_dim; + + } + } + + /* Get coordinates of "ending" point */ + if((tmp_r <= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - tmp_c,&cellhd2); + north2 = G_row_to_northing((double) r - tmp_r,&cellhd2); + + } + if((tmp_r <= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - (tmp_c-search_window_dim-1),&cellhd2); + north2 = G_row_to_northing((double) r - tmp_r,&cellhd2); + + } + if((tmp_r >= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - tmp_c,&cellhd2); + north2 = G_row_to_northing((double) r - (tmp_r-search_window_dim-1),&cellhd2); + + } + if((tmp_r >= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - (tmp_c-search_window_dim-1),&cellhd2); + north2 = G_row_to_northing((double) r - (tmp_r-search_window_dim-1),&cellhd2); + + } + + + /* Fill the POINTS file*/ + sPoints.e1[sPoints.count-1] = east1; + sPoints.n1[sPoints.count-1] = north1; + sPoints.e2[sPoints.count-1] = east2; + sPoints.n2[sPoints.count-1] = north2; + + sPoints.status[sPoints.count-1] = 1; + sPoints.count += 1; + sPoints.e1=(double *)G_realloc(sPoints.e1,sPoints.count*sizeof(double)); + sPoints.n1=(double *)G_realloc(sPoints.n1,sPoints.count*sizeof(double)); + sPoints.e2=(double *)G_realloc(sPoints.e2,sPoints.count*sizeof(double)); + sPoints.n2=(double *)G_realloc(sPoints.n2,sPoints.count*sizeof(double)); + sPoints.status=(int *)G_realloc(sPoints.status,sPoints.count*sizeof(int)); + } + G_percent (r,dim_win_r, 1); + } + } + + +void Extract_portion_of_double_matrix_semi(int r,int c,int br,int bc,DCELL **mat,DCELL **wind) + /* + extract a squared portion of a matrix mat + given a the indeces of the center [r,c] + and the semilength of the borders [br,bc] + Output to array wind + */ +{ + int i,j; + for(i=0;(i <2*br);i++) + for(j = 0;(j <2*bc);j++) + { + wind[i][j] = mat[r - br + i][c - bc +j]; + } +} + + + + + + + + + + + + + + + + + + + + + + Property changes on: trunk/grassaddons/i.points.auto/find_points_semi.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/georef.c =================================================================== --- trunk/grassaddons/i.points.auto/georef.c (rev 0) +++ trunk/grassaddons/i.points.auto/georef.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,326 @@ +#include +#include "globals.h" + +static int floating_exception; +static void catch(int); +static double determinant(double,double, + double,double,double,double,double,double,double); + +void (*sigfpe)(); + +/* find coefficients A,B,C for e2 = A + B*e1 + C*n1 + * also compute the reverse equations + * + * return 0 if no points + * -1 if not solvable + * 1 if ok + * + * method is least squares. + * the least squares problem reduces to solving the following + * system of equations for A,B,C + * + * s0*A + s1*B + s2*C = x0 + * s1*A + s3*B + s4*C = x1 + * s2*A + s4*B + s5*C = x2 + * + * use Cramer's rule + * + * | x0 s1 s2 | | s0 x0 s2 | | s0 s1 x0 | + * | x1 s3 s4 | | s1 x1 s4 | | s1 s3 x1 | + * | x2 s4 s5 | | s2 x2 s5 | | s2 s4 x2 | + * A = ------------ B = ------------ C = ------------ + * | s0 s1 s2 | | s0 s1 s2 | | s0 s1 s2 | + * | s1 s3 s4 | | s1 s3 s4 | | s1 s3 s4 | + * | s2 s4 s5 | | s2 s4 s5 | | s2 s4 s5 | + * + */ + +int compute_georef_equations( + struct Control_Points *cp, + double E12[3], double N12[3], double E21[3], double N21[3]) +{ + double s0,s1,s2,s3,s4,s5; + double x0,x1,x2; + double det; + int i; + + + s0 = s1 = s2 = s3 = s4 = s5 = 0.0; + for (i = 0; i < cp->count; i++) + { + if (cp->status[i] != 1) + continue; + s0 += 1.0; + s1 += cp->e1[i]; + s2 += cp->n1[i]; + s3 += cp->e1[i] * cp->e1[i]; + s4 += cp->e1[i] * cp->n1[i]; + s5 += cp->n1[i] * cp->n1[i]; + } + if (s0 < 0.5) return 0; + + floating_exception = 0; + sigfpe = signal (SIGFPE, catch); + +/* eastings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < cp->count; i++) + { + if (cp->status[i] != 1) + continue; + x0 += cp->e2[i]; + x1 += cp->e1[i] * cp->e2[i]; + x2 += cp->n1[i] * cp->e2[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + E12[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + E12[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + E12[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + +/* northings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < cp->count; i++) + { + if (cp->status[i] != 1) + continue; + x0 += cp->n2[i]; + x1 += cp->e1[i] * cp->n2[i]; + x2 += cp->n1[i] * cp->n2[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + N12[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + N12[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + N12[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + +/* the inverse equations */ + + s0 = s1 = s2 = s3 = s4 = s5 = 0.0; + for (i = 0; i < cp->count; i++) + { + if (cp->status[i] != 1) + continue; + s0 += 1.0; + s1 += cp->e2[i]; + s2 += cp->n2[i]; + s3 += cp->e2[i] * cp->e2[i]; + s4 += cp->e2[i] * cp->n2[i]; + s5 += cp->n2[i] * cp->n2[i]; + } + +/* eastings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < cp->count; i++) + { + if (cp->status[i] != 1) + continue; + x0 += cp->e1[i]; + x1 += cp->e2[i] * cp->e1[i]; + x2 += cp->n2[i] * cp->e1[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + E21[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + E21[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + E21[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + +/* northings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < cp->count; i++) + { + if (cp->status[i] != 1) + continue; + x0 += cp->n1[i]; + x1 += cp->e2[i] * cp->n1[i]; + x2 += cp->n2[i] * cp->n1[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + N21[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + N21[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + N21[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + + signal (SIGFPE, sigfpe); + return floating_exception ? -1 : 1; +} + + +int compute_georef_equations_lp (Lines *ln) +{ + double s0,s1,s2,s3,s4,s5; + double x0,x1,x2; + double det; + int i; + + + s0 = s1 = s2 = s3 = s4 = s5 = 0.0; + for (i = 0; i < ln->count; i++) + { + if (ln->status[i] != 2) + continue; + s0 += 1.0; + s1 += ln->t1[i]; + s2 += ln->u1[i]; + s3 += ln->t1[i] * ln->t1[i]; + s4 += ln->t1[i] * ln->u1[i]; + s5 += ln->u1[i] * ln->u1[i]; + } + if (s0 < 0.5) return 0; + + floating_exception = 0; + sigfpe = signal (SIGFPE, catch); + +/* eastings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < ln->count; i++) + { + if (ln->status[i] != 2) + continue; + x0 += ln->t2[i]; + x1 += ln->t1[i] * ln->t2[i]; + x2 += ln->u1[i] * ln->t2[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + ln->E12[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + ln->E12[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + ln->E12[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + +/* northings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < ln->count; i++) + { + if (ln->status[i] != 2) + continue; + x0 += ln->u2[i]; + x1 += ln->t1[i] * ln->u2[i]; + x2 += ln->u1[i] * ln->u2[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + ln->N12[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + ln->N12[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + ln->N12[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + +/* the inverse equations */ + + s0 = s1 = s2 = s3 = s4 = s5 = 0.0; + for (i = 0; i < ln->count; i++) + { + if (ln->status[i] != 2) + continue; + s0 += 1.0; + s1 += ln->t2[i]; + s2 += ln->u2[i]; + s3 += ln->t2[i] * ln->t2[i]; + s4 += ln->t2[i] * ln->u2[i]; + s5 += ln->u2[i] * ln->u2[i]; + } + +/* eastings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < ln->count; i++) + { + if (ln->status[i] != 2) + continue; + x0 += ln->t1[i]; + x1 += ln->t2[i] * ln->t1[i]; + x2 += ln->u2[i] * ln->t1[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + ln->E21[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + ln->E21[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + ln->E21[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + +/* northings */ + x0 = x1 = x2 = 0.0; + for (i = 0; i < ln->count; i++) + { + if (ln->status[i] != 2) + continue; + x0 += ln->u1[i]; + x1 += ln->t2[i] * ln->u1[i]; + x2 += ln->u2[i] * ln->u1[i]; + } + + det = determinant (s0,s1,s2,s1,s3,s4,s2,s4,s5); + if (det == 0.0) + { + signal (SIGFPE, sigfpe); + return -1; + } + ln->N21[0] = determinant (x0,s1,s2,x1,s3,s4,x2,s4,s5)/det; + ln->N21[1] = determinant (s0,x0,s2,s1,x1,s4,s2,x2,s5)/det; + ln->N21[2] = determinant (s0,s1,x0,s1,s3,x1,s2,s4,x2)/det; + + signal (SIGFPE, sigfpe); + return floating_exception ? -1 : 1; +} + + + +static double determinant ( + double a, double b, double c, double d, double e, + double f, double g, double h, double i) +{ +/* compute determinant of 3x3 matrix + * | a b c | + * | d e f | + * | g h i | + */ + return a * (e*i - f*h) - b * (d*i - f*g) + c * (d*h - e*g) ; +} + +static void catch(int n) +{ + floating_exception = 1; + signal (n, catch); +} + +int georef ( + double e1,double n1, + double *e2,double *n2, + double E[3],double N[3]) +{ + *e2 = E[0] + E[1] * e1 + E[2] * n1; + *n2 = N[0] + N[1] * e1 + N[2] * n1; + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/georef.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/globals.h =================================================================== --- trunk/grassaddons/i.points.auto/globals.h (rev 0) +++ trunk/grassaddons/i.points.auto/globals.h 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,85 @@ +#include "defs.h" + +#ifndef GLOBAL +# define GLOBAL extern +# define INIT(x) +#else +# define INIT(x) = x +#endif + +GLOBAL struct Control_Points sPoints; +GLOBAL struct Cell_head cellhd1; +GLOBAL struct Cell_head cellhd2; + + + +/* Variable for the botton "Main-Menu". */ +GLOBAL int m; + +GLOBAL int G_get_color(); + +GLOBAL int SCREEN_TOP; +GLOBAL int SCREEN_BOTTOM; +GLOBAL int SCREEN_LEFT; +GLOBAL int SCREEN_RIGHT; + +GLOBAL int correlation_window_dim; +GLOBAL int K; + +GLOBAL Window *INFO_WINDOW; +GLOBAL Window *MENU_WINDOW; +GLOBAL Window *PROMPT_WINDOW; + +GLOBAL View *VIEW_MAP1; +GLOBAL View *VIEW_TITLE1; +GLOBAL View *VIEW_MAP1_ZOOM; +GLOBAL View *VIEW_TITLE1_ZOOM; + +GLOBAL View *VIEW_MAP2; +GLOBAL View *VIEW_TITLE2; +GLOBAL View *VIEW_MAP2_ZOOM; +GLOBAL View *VIEW_TITLE2_ZOOM; + +GLOBAL View *VIEW_MENU; + +GLOBAL Group group; + +GLOBAL char interrupt_char; +GLOBAL char *tempfile1; +GLOBAL char *tempfile2; +GLOBAL char *tempfile3; +GLOBAL char *digit_points; /* digitizer control points */ +GLOBAL char *digit_results; /* digitizer results */ +GLOBAL int use_digitizer INIT(0); /* is there a digitizer out there? */ + +/* group file list, target cell,vector files */ +GLOBAL char *group_list INIT(NULL); +GLOBAL char *cell_list INIT(NULL); +GLOBAL char *vect_list INIT(NULL); + +GLOBAL int from_keyboard INIT(-1); /* input method */ +GLOBAL int from_digitizer INIT(-1); +GLOBAL int from_screen INIT(-1); +GLOBAL int from_flag INIT(0); + +GLOBAL int dotsize INIT(4); + +GLOBAL int THE_COLORS[10]; +#define BLACK THE_COLORS[0] +#define BLUE THE_COLORS[1] +#define BROWN THE_COLORS[2] +#define GREEN THE_COLORS[3] +#define GREY THE_COLORS[4] +#define ORANGE THE_COLORS[5] +#define PURPLE THE_COLORS[6] +#define RED THE_COLORS[7] +#define WHITE THE_COLORS[8] +#define YELLOW THE_COLORS[9] + +double row_to_northing(); +double col_to_easting(); +double northing_to_row(); +double easting_to_col(); + +#undef INIT + Property changes on: trunk/grassaddons/i.points.auto/globals.h ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/graphics.c =================================================================== --- trunk/grassaddons/i.points.auto/graphics.c (rev 0) +++ trunk/grassaddons/i.points.auto/graphics.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,149 @@ +#include "globals.h" +#include "local_proto.h" +#include +#include + +static View * +makeview (double bottom, double top, double left, double right) +{ + View *view; + + view = (View *) G_malloc (sizeof (View)); + + top = 100-top; + bottom = 100-bottom; + + view->top = SCREEN_TOP + (SCREEN_BOTTOM - SCREEN_TOP) * top / 100.0 ; + view->bottom = SCREEN_TOP + (SCREEN_BOTTOM - SCREEN_TOP) * bottom / 100.0 ; + view->left = SCREEN_LEFT + (SCREEN_RIGHT - SCREEN_LEFT) * left / 100.0 ; + view->right = SCREEN_LEFT + (SCREEN_RIGHT - SCREEN_LEFT) * right / 100.0 ; + + if (view->top < SCREEN_TOP) + view->top = SCREEN_TOP; + if (view->bottom > SCREEN_BOTTOM) + view->bottom = SCREEN_BOTTOM; + if (view->left < SCREEN_LEFT) + view->left = SCREEN_LEFT; + if (view->right > SCREEN_RIGHT) + view->right = SCREEN_RIGHT; + + Outline_box (view->top, view->bottom, view->left, view->right); + + view->top++; + view->bottom--; + view->left++; + view->right--; + + view->nrows = view->bottom - view->top + 1; + view->ncols = view->right - view->left + 1; + view->cell.configured = 0; + + return view; +} + +int +Init_graphics (void) +{ + D_full_screen(); + + + SCREEN_TOP = R_screen_top(); + SCREEN_BOTTOM = R_screen_bot(); + SCREEN_LEFT = R_screen_left(); + SCREEN_RIGHT = R_screen_rite(); + + + BLACK = D_translate_color ("black"); + BLUE = D_translate_color ("blue"); + BROWN = D_translate_color ("brown"); + GREEN = D_translate_color ("green"); + GREY = D_translate_color ("grey"); + ORANGE = D_translate_color ("orange"); + PURPLE = D_translate_color ("purple"); + RED = D_translate_color ("red"); + WHITE = D_translate_color ("white"); + YELLOW = D_translate_color ("yellow"); + + R_standard_color (WHITE); + + VIEW_TITLE1 = makeview (97.5, 100.0, 0.0, 50.0); + VIEW_TITLE2 = makeview (97.5, 100.0, 50.0, 100.0); + VIEW_MAP1 = makeview (51.0, 97.5, 0.0, 50.0); + VIEW_MAP2 = makeview (51.0, 97.5, 50.0, 100.0); + VIEW_TITLE1_ZOOM = makeview (47.5, 51.0, 0.0, 50.0); + VIEW_TITLE2_ZOOM = makeview (47.5, 51.0, 50.0, 100.0); + VIEW_MAP1_ZOOM = makeview (2.5, 47.5, 0.0, 50.0); + VIEW_MAP2_ZOOM = makeview (2.5, 47.5, 50.0, 100.0); + VIEW_MENU = makeview (0.0, 2.5, 0.0, 100.0); + + G_init_colors (&VIEW_MAP1->cell.colors); + G_init_colors (&VIEW_MAP2->cell.colors); + + Erase_view (VIEW_MAP1); + Erase_view (VIEW_MAP1_ZOOM); + Erase_view (VIEW_MAP2); + Erase_view (VIEW_MAP2_ZOOM); + + return 0; +} + +int +Outline_box (int top, int bottom, int left, int right) +{ + R_move_abs (left, top); + R_cont_abs (left, bottom); + R_cont_abs (right, bottom); + R_cont_abs (right, top); + R_cont_abs (left, top); + + return 0; +} + + +int +Text_width (char *text) +{ + int top, bottom, left, right; + + R_get_text_box (text, &top, &bottom, &left, &right); + + if (right > left) + return right-left+1; + else + return left-right+1; +} + +int +Text (char *text, int top, int bottom, int left, int right, int edge) +{ + R_set_window (top, bottom, left, right); + R_move_abs (left+edge, bottom-edge); + R_text (text); + R_set_window (SCREEN_TOP, SCREEN_BOTTOM, SCREEN_LEFT, SCREEN_RIGHT); + + return 0; +} + +int +Uparrow (int top, int bottom, int left, int right) +{ + R_move_abs ((left+right)/2, bottom); + R_cont_abs ((left+right)/2, top); + R_cont_rel ((left-right)/2, (bottom-top)/2); + R_move_abs ((left+right)/2, top); + R_cont_rel ((right-left)/2, (bottom-top)/2); + + return 0; +} + +int +Downarrow (int top, int bottom, int left, int right) +{ + R_move_abs ((left+right)/2, top); + R_cont_abs ((left+right)/2, bottom); + R_cont_rel ((left-right)/2, (top-bottom)/2); + R_move_abs ((left+right)/2, bottom); + R_cont_rel ((right-left)/2, (top-bottom)/2); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/graphics.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/group.c =================================================================== --- trunk/grassaddons/i.points.auto/group.c (rev 0) +++ trunk/grassaddons/i.points.auto/group.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,70 @@ +#include +#include +#include +#include "globals.h" +#include "local_proto.h" + +static int cmp(const void *, const void *); + +int prepare_group_list (void) +{ + FILE *fd; + int *idx; + int n; + int len,len1,len2; + +/* open file to store group file names */ + fd = fopen (group_list, "w"); + if (fd == NULL) + G_fatal_error ("Can't open any tempfiles"); + +/* + * build sorted index into group files + * so that all cell files for a mapset to appear together + */ + idx = (int *) G_calloc (group.ref.nfiles, sizeof (int)); + for (n = 0; n < group.ref.nfiles; n++) + idx[n] = n; + qsort (idx, group.ref.nfiles, sizeof(int), cmp); + +/* determine length of longest mapset name, and longest cell file name */ + len1 = len2 = 0; + for (n = 0; n < group.ref.nfiles; n++) + { + len = strlen (group.ref.file[n].name); + if (len > len1) + len1 = len; + len = strlen (group.ref.file[n].mapset); + if (len > len2) + len2 = len; + } + +/* write lengths, names to file */ + fwrite (&len1, sizeof (len1), 1, fd); + fwrite (&len2, sizeof (len2), 1, fd); + for (n = 0; n < group.ref.nfiles; n++) + fprintf (fd, "%s %s\n", group.ref.file[idx[n]].name, group.ref.file[idx[n]].mapset); + fclose (fd); + + G_free (idx); + + return 0; +} + +static int cmp (const void *aa, const void *bb) +{ + const int *a = aa, *b = bb; + int n; + + if(n = strcmp (group.ref.file[*a].mapset, group.ref.file[*b].mapset)) + return n; + return strcmp (group.ref.file[*a].name, group.ref.file[*b].name); +} + +/* ask the user to pick a file */ +int choose_groupfile (char *name,char *mapset) +{ + int stat; + stat = ask_gis_files ("raster", group_list, name, mapset, -1); + return(stat); +} Property changes on: trunk/grassaddons/i.points.auto/group.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/input.c =================================================================== --- trunk/grassaddons/i.points.auto/input.c (rev 0) +++ trunk/grassaddons/i.points.auto/input.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,296 @@ +#include +#include +#include "globals.h" +#include "local_proto.h" + +static int active = 0; +static int replot; +static int mouse (Objects *,int,int,int); +static int use_mouse_msg(void); +static int draw_objects (Objects *); +static Objects *find (Objects *,int, int); +static int select_option (Objects *,Objects *); +static int draw_option_boxes (Objects *); +static int visible( Objects *); + +#define TEXT_COLOR ORANGE /*WHITE*/ +#define FILL_COLOR BLACK /*BLUE*/ +#define OUTLINE_COLOR RED + +/* Input: drive mouse. returns status of handler that returns != 0 */ +int Input_pointer (Objects *objects) +{ + return mouse (objects,0,0,0); +} + +int Input_box (Objects *objects,int ax,int ay) +{ + return mouse (objects,ax,ay,1); +} + +int Input_other (int (*function)(), char *type) +{ + int stat; + char msg[1024]; + + sprintf (msg, "%s input required", type); + Menu_msg(msg); + + stat = (*function)(); + if (active) + { + use_mouse_msg(); + } + + Menu_msg(""); + return stat; +} + +static int mouse (Objects *objects,int ax,int ay,int box) +{ + int first; + int stat; + int x,y,button; + Objects *obj; + Objects *find(); + + + first = !active; + active = 1; + if (first) + use_mouse_msg(); + + if (box) + { + x = ax + 20; + y = ay + 20; + } + stat = 0; + replot = 1; + while (stat == 0) + { + + + draw_objects (objects); + + if (box) + Mouse_box_anchored (ax, ay, &x, &y, &button) ; + else + Mouse_pointer (&x, &y, &button) ; + + if (!(obj = find (objects, x, y))) + continue; + + + + switch (obj->type) + { + case MENU_OBJECT: + case OTHER_OBJECT: + stat = (*obj->handler)(x,y,button); + break; + case OPTION_OBJECT: + select_option (objects, obj); + draw_option_boxes(objects); + break; + } + + + /*This expression is necessary for the button "Main-Menu". */ + if(m!=0) + return -1; + + + } + +/* if we are first call, mark not active + * indicate that objects above use must be replotted. + */ + if (first) + active = 0; + Menu_msg(""); + + + return stat; +} + + +static int +use_mouse_msg (void) +{ + Curses_write_window (PROMPT_WINDOW, 1, 1, "Use mouse now ...\n"); + + return 0; +} + +static int draw_objects (Objects *objects) +{ + Objects *obj; + int top, bottom, left, right; + int size, edge; + + +/* erase the menu window */ + Erase_view (VIEW_MENU); + R_flush(); + +/* determine sizes and text indentation */ + size = VIEW_MENU->nrows - 4; /* TEXT-SIZE FOR THE BUTTONS */ + edge = 2; + + R_text_size (size, size); + + left = VIEW_MENU->left; + top = VIEW_MENU->top; + bottom = VIEW_MENU->bottom; + + +/* put the (boxed) text on the menu view */ + for (obj = objects; obj->type; obj++) + { + if (!visible(obj)) + continue; + switch (obj->type) + { + case OPTION_OBJECT: + case MENU_OBJECT: + right = left + 2*edge + Text_width (obj->label); + if(!strcmp(obj->label,"LINE")){ + obj->left = left+1; + obj->right = right+1; + } else { + obj->left = left; + obj->right = right; + + } + + obj->top = top; + obj->bottom = bottom; + + R_standard_color (FILL_COLOR); + R_box_abs (left, top, right, bottom); + + R_standard_color (TEXT_COLOR); + Text (obj->label, top, bottom, left, right, edge); + + if(!strcmp(obj->label,"LINE")) + R_standard_color(BLUE); + else R_standard_color (OUTLINE_COLOR); + Outline_box (top, bottom, left, right); + + left = right; + break; + + case INFO_OBJECT: + if (*obj->label == 0) break; + if (*obj->status < 0) break; + right = left + 2*edge + Text_width (obj->label); + R_standard_color (WHITE); + Text (obj->label, top, bottom, left, right, edge); + + left = right; + break; + } + } + draw_option_boxes (objects); + R_flush(); + + return 0; +} + +static Objects *find (Objects *objects,int x, int y) +{ + Objects *other; + other = NULL; + for (; objects->type; objects++) + { + if (!visible (objects)) + continue; + switch (objects->type) + { + case MENU_OBJECT: + case OPTION_OBJECT: + if (x >= objects->left && x <= objects->right + && y >= objects->top && y <= objects->bottom) + return objects; + break; + case OTHER_OBJECT: + other = objects; + break; + } + } + return other; +} + +static int select_option (Objects *objects,Objects *obj) +{ + while (objects->type) + { + if (objects->type == OPTION_OBJECT && *objects->status >= 0 && + objects->binding == obj->binding) + *objects->status = 0; + objects++; + } + *obj->status = 1; + + return 0; +} + +static int draw_option_boxes (Objects *objects) +{ + Objects *x; + + R_standard_color (OUTLINE_COLOR); + for (x = objects; x->type; x++) + { + if (x->type == OPTION_OBJECT && *x->status == 0) + Outline_box (x->top, x->bottom, x->left, x->right); + } + R_standard_color (GREEN); + for (x = objects; x->type; x++) + { + if (x->type == OPTION_OBJECT && *x->status > 0) + Outline_box (x->top, x->bottom, x->left, x->right); + } + + return 0; +} + +static int visible( Objects *object) +{ + if (object->type == OPTION_OBJECT) + return (*object->status >= 0); + return (*object->status > 0); +} + +int Menu_msg(char *msg) +{ + int size, edge; + + size = VIEW_MENU->nrows - 4; + edge = 2; + + Erase_view (VIEW_MENU); + + if (*msg) + { + R_text_size (size, size); + R_standard_color (WHITE); + Text (msg, VIEW_MENU->top, VIEW_MENU->bottom, + VIEW_MENU->left, VIEW_MENU->right, edge); + } + R_flush(); + replot = 1; + + return 0; +} + +int +Start_mouse_in_menu (void) +{ + Set_mouse_xy ( + (VIEW_MENU->left+2*VIEW_MENU->right)/3, + (VIEW_MENU->top+VIEW_MENU->bottom)/2); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/input.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/line.c =================================================================== --- trunk/grassaddons/i.points.auto/line.c (rev 0) +++ trunk/grassaddons/i.points.auto/line.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,226 @@ +#include +#include +#include "globals.h" +#include "local_proto.h" + +static int cancel(); +static int select(int x1,int y1,int button); + + +double temp_e1,temp_e2,temp_n1,temp_n2; +static int flag; +void find_position (int *x1, int *x2,int *y1,int *y2); +int xtemp[2],ytemp[2], first_linex[2],first_liney[2]; + +int +line (void) +{ + int stat,row,col,i; + static int use = 1; + double e1,e2,e3,e4,n1,n2,n3,n4; + static Objects objects1[]= + { + MENU("CANCEL",cancel,&use), + INFO("select first line (left side) ",&use), + OTHER(select, &use), + {0} + }; + + static Objects objects2[]= + { + MENU("CANCEL",cancel,&use), + INFO("select second line (right side) ",&use), + OTHER(select, &use), + {0} + }; + + + flag =0; + stat= Input_pointer (objects1); + if (stat==-1) return 0; + + e1=temp_e1; + e2=temp_e2; + n1=temp_n1; + n2=temp_n2; + flag = 1; + + for (i=0;i<2;i++) + { + first_linex[i]=xtemp[i]; + first_liney[i]=ytemp[i]; + } + + stat=Input_pointer (objects2); + if (stat==-1) + { + R_panel_restore (tempfile2); /* serve al ripristino del quadrato che contiene la linea collogante i 2 punti */ + R_panel_restore (tempfile3); /* serve al ripristino del secondo punto*/ + R_panel_restore (tempfile1); /* serve al ripristino del primo punto*/ + R_panel_delete (tempfile1); + R_panel_delete (tempfile2); + R_panel_delete (tempfile3); + + return 0; + } + + + e3=temp_e1; + e4=temp_e2; + n3=temp_n1; + n4=temp_n2; + I_new_control_point (&group.points, e1, n1, e3, n3, 2); + I_put_control_points (group.name, &group.points); + Compute_equation(); + display_points(1) ; + I_new_control_point (&group.points, e2, n2, e4, n4, 3); + I_put_control_points (group.name, &group.points); + Compute_equation(); + display_points(1) ; + R_standard_color (GREEN); + R_polyline_abs (first_linex ,first_liney,2); + R_polyline_abs (xtemp ,ytemp,2); + R_flush(); + + return 0; /* return, but don't QUIT */ +} + +static int select(int x,int y,int button) +{ + if (button != 1) + return where (x,y); + + if (flag==0) { + if (VIEW_MAP1->cell.configured && In_view (VIEW_MAP1, x, y)) + select_line (VIEW_MAP1, x, y); + else if (VIEW_MAP1_ZOOM->cell.configured && In_view (VIEW_MAP1_ZOOM, x, y)) + select_line (VIEW_MAP1_ZOOM, x, y); + else return 0; + } + if (flag==1) { + if (VIEW_MAP2->cell.configured && In_view (VIEW_MAP2, x, y)) + select_line (VIEW_MAP2, x, y); + else if (VIEW_MAP2_ZOOM->cell.configured && In_view (VIEW_MAP2_ZOOM, x, y)) + select_line (VIEW_MAP2_ZOOM, x, y); + else return 0; + } + return 1 ; /* return but don't quit */ + +}; + +int select_line (View *view,int x1, int y1) +{ + int col, row; + int x2,y2,button=0; + char buf[50]; + + + + col = view_to_col (view, x1); + temp_e1 = col_to_easting (&view->cell.head, col, 0.5); + row = view_to_row (view, y1); + temp_n1 = row_to_northing (&view->cell.head, row, 0.5); + + if (flag== 0) + { + Curses_clear_window (INFO_WINDOW); + Curses_clear_window (MENU_WINDOW); + sprintf (buf, "Point %d marked on image at", group.points.count+1); + Curses_write_window (MENU_WINDOW, 1, 1, buf); + sprintf (buf, "East: %10.2f", temp_e1); + Curses_write_window (MENU_WINDOW, 3, 3, buf); + sprintf (buf, "North: %10.2f", temp_n1); + Curses_write_window (MENU_WINDOW, 4, 3, buf); + } + else + { + + sprintf (buf, "Point %d marked on target image at", group.points.count+1); + Curses_write_window (INFO_WINDOW, 1, 1, buf); + sprintf (buf, "East: %10.2f",temp_e1); + Curses_write_window (INFO_WINDOW, 3, 3, buf); + sprintf (buf, "North: %10.2f", temp_n1); + Curses_write_window (INFO_WINDOW, 4, 3, buf); + } + + R_standard_color (ORANGE); + R_panel_save (tempfile1, y1-dotsize, y1+dotsize, x1-dotsize, x1+dotsize); + dot(x1,y1); + + while (button!=1) + { + R_get_location_with_line (x1,y1,&x2,&y2,&button); + if( button!=1) + where (x2,y2); + if (!(view->cell.configured && In_view (view, x2, y2))) + button=0; + } + + col = view_to_col (view, x2); + temp_e2 = col_to_easting (&view->cell.head, col, 0.5); + row = view_to_row (view, y2); + temp_n2 = row_to_northing (&view->cell.head, row, 0.5); + + if (flag== 0) + { + sprintf (buf, "Point %d marked on image at", group.points.count+2); + Curses_write_window (MENU_WINDOW, 6, 1, buf); + sprintf (buf, "East: %10.2f", temp_e2); + Curses_write_window (MENU_WINDOW, 8, 3, buf); + sprintf (buf, "North: %10.2f", temp_n2); + Curses_write_window (MENU_WINDOW, 9, 3, buf); + } + else + { + sprintf (buf, "Point %d marked on target image at", group.points.count+2); + Curses_write_window (INFO_WINDOW, 6, 1, buf); + sprintf (buf, "East: %10.2f",temp_e2); + Curses_write_window (INFO_WINDOW, 8, 3, buf); + sprintf (buf, "North: %10.2f", temp_n2); + Curses_write_window (INFO_WINDOW, 9, 3, buf); + } + + R_standard_color (ORANGE); + R_panel_save (tempfile3, y2-dotsize, y2+dotsize, x2-dotsize, x2+dotsize); + dot(x2,y2); + + xtemp[0]= x1; + xtemp[1]= x2; + ytemp[0]= y1; + ytemp[1]= y2; + + find_position (&x1,&x2,&y1,&y2); + R_panel_save (tempfile2, y1, y2, x1, x2); + R_polyline_abs (xtemp ,ytemp,2); + + return 1 ; + + } + + void find_position (int *x1, int *x2,int *y1,int *y2) + { int temp; + if (*y2<*y1) { + temp=*y1; + *y1=*y2; + *y2= temp; + } + else if (*y2==*y1) { *y2= *y2+dotsize; + *y1= *y1 - dotsize ; + } + if (*x2<*x1) { + temp=*x1; + *x1=*x2; + *x2= temp; + } + else if (*x2==*x1) { *x2= *x2+dotsize; + *x1= *x1 - dotsize ; + } + } + + + static int cancel() + { + return -1 ; +} + + Property changes on: trunk/grassaddons/i.points.auto/line.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/local_proto.h =================================================================== --- trunk/grassaddons/i.points.auto/local_proto.h (rev 0) +++ trunk/grassaddons/i.points.auto/local_proto.h 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,142 @@ +/* analyze.c */ +int analyze(void); +int points_to_line (double, double, double, double, double *, double *); +/* ask.c */ +int ask_gis_files(char *, char *, char *, char *, int); +int ask_original_map(char *, char *, char *, char *, int); /* AGGIUNTA */ +/* ask_mag.c */ +int ask_magnification(int *); +int draw_mag(void); +/* call.c */ +int call(int (*)(), char *); +/* cell.c */ +int plotcell(int, int); +/* cellhd.c */ +int Outline_cellhd(View *, struct Cell_head *); +/* colors.c */ +int set_colors(struct Colors *); +/* conv.c */ +int view_to_col(View *, int); +int view_to_row(View *, int); +int col_to_view(View *, int); +int row_to_view(View *, int); +double row_to_northing(struct Cell_head *, int, double); +double col_to_easting(struct Cell_head *, int, double); +double northing_to_row(struct Cell_head *, double); +double easting_to_col(struct Cell_head *, double); +/* curses.c */ +int Begin_curses(void); +int End_curses(void); +int Suspend_curses(void); +int Resume_curses(void); +int Curses_allow_interrupts(int); +int Curses_clear_window(Window *); +int Curses_outline_window(Window *); +int Curses_write_window(Window *, int, int, char *); +int Curses_replot_screen(void); +int Curses_prompt_gets(char *, char *); +int Beep(void); +int Curses_getch(int); +/* debug.c */ +int debug(char *); +/* digit.c */ +int setup_digitizer(void); +int digitizer_point(double *, double *); +/* dot.c */ +int dot(int, int); +int save_under_dot(int, int); +int restore_under_dot(void); +int release_under_dot(void); +/* drawcell.c */ +int drawcell(View *); +/* driver.c */ +int driver(void); +/* equ.c */ +int Compute_equation(void); +/* find_points.c */ +int automated_search(void); +void Extract_matrix(void); +void Search_correlation_points(DCELL**, DCELL**, int, int, int, char *, + int, int, DCELL **, int, int, int, int, int, int, int, int,int,int, int); /*Aggiunta*/ +void Extract_portion_of_double_matrix(int, int, int, int, DCELL**, DCELL**); + + + +/* find_points_semi */ +extern void Extract_matrix_semi(void); +extern void Search_correlation_points_semi(DCELL**, DCELL**, int, int, int, char *, + int, int, DCELL **, int, int, int, int, int, int, int, int,int,int); +extern void Extract_portion_of_double_matrix_semi(int, int, int, int, DCELL**, DCELL**); + + +/* find.c */ +int find_target_files(void); +/*georef.c*/ +int compute_georef_equations(struct Control_Points *cp, double E12[3], double N12[3], double E21[3], double N21[3]); +int compute_georef_equations_lp (Lines *ln); +int georef (double e1,double n1,double *e2,double *n2,double E[3],double N[3]); +/* graphics.c */ +int Init_graphics(void); +int Outline_box(int, int, int, int); +int Text_width(char *); +int Text(char *, int, int, int, int, int); +int Uparrow(int, int, int, int); +int Downarrow(int, int, int, int); +/* group.c */ +int prepare_group_list(void); +int choose_groupfile(char *, char *); +/* input.c */ +int Input_pointer(Objects *); +int Input_box(Objects *, int, int); +int Input_other(int (*)(), char *); +int Menu_msg(char *); +int Start_mouse_in_menu(void); +/* line.c */ +int line(void); +int select_line (View *, int, int); +/* main.c */ +int quit(int); +int error(char *, int); +/* mark.c */ +int mark(int, int, int); +int mark_point(View *, int, int); +/* mouse.c */ +int Mouse_pointer(int *, int *, int *); +int Mouse_box_anchored(int, int, int *, int *, int *); +int Get_mouse_xy(int *, int *); +int Set_mouse_xy(int, int); +/* points.c */ +int display_points(int); +int display_points_in_view(View *, int, double *, double *, int *, int); +int display_points_in_view_diff_color(View *, int, double *, double *, int *, int); +int display_points_in_view_diff_color_if_active(View *, int, double *, double *, int *, int); +int display_one_point(View *, double, double); +/* target.c */ +int get_target(void); +int select_current_env(void); +int select_target_env(void); +/* title.c */ +int display_title(View *); +/* view.c */ +int Configure_view(View *, char *, char *, double, double); +int In_view(View *, int, int); +int Erase_view(View *); +double magnification(View *); +/* where.c */ +int where(int, int); +/*write_line.c*/ +int put_control_points ( char *group, struct Control_Points *cp); +int read_control_points (FILE *fd, struct Control_Points *cp); +int new_control_point (struct Control_Points *cp,double e1,double n1,double e2,double n2, int status); +int write_control_points(FILE *fd, struct Control_Points *cp); +int get_control_points (char *group, struct Control_Points *cp); +/* zoom.c */ +int zoom(void); +static int which_zoom(int x, int y, int button); +/* overlap_area.c */ +int overlap_area(int,int,int,int,int, int,int); +/* zoom_box.c */ +int zoom_box(int ,int ); +/* zoom_pnt.c */ +int zoom_point(int , int ); +int zoom_pnt (int ,int ); Property changes on: trunk/grassaddons/i.points.auto/local_proto.h ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/main.c =================================================================== --- trunk/grassaddons/i.points.auto/main.c (rev 0) +++ trunk/grassaddons/i.points.auto/main.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,204 @@ +/***************************************************************************** +* +* MODULE: i.points.auto +* AUTHOR(S): based on i.points; additions by +* Ivan Michelazzi, Luca Miori (MSc theses at ITC-irst) +* http://gisws.media.osaka-cu.ac.jp/grass04/viewpaper.php?id=37 +* Supervisors: Markus Neteler, Stefano Merler, ITC-irst 2003, 2004 +* +* PURPOSE: semi-automated image registration based in FFT correlation +* COPYRIGHT: GPL >=2 +* +*****************************************************************************/ + +#define GLOBAL +#include +#include +#include +#include +#include +#include +#include +#include "globals.h" +#include "local_proto.h" + +#ifdef __GNUC_MINOR__ +int quit (int) __attribute__ ((__noreturn__)); +#else +int quit (int); +#endif +int error (char *, int); + + + +int main (int argc, char *argv[]) +{ + char name[GNAME_MAX], mapset[GMAPSET_MAX]; + struct Cell_head cellhd; + struct GModule *module; + + G_gisinit (argv[0]); + module = G_define_module(); + module->description = + _("Mark or search ground control points on image to be rectified."); + + G_suppress_masking(); /* need to do this for target location */ + + interrupt_char = G_intr_char(); + tempfile1 = G_tempfile(); + tempfile2 = G_tempfile(); + tempfile3 = G_tempfile(); + cell_list = G_tempfile(); + vect_list = G_tempfile(); + group_list = G_tempfile(); + digit_points = G_tempfile(); + digit_results = G_tempfile(); + + if (R_open_driver() != 0) + G_fatal_error(_("No graphics device selected")); + + /* temporary parser code: */ + if(argc == 2) { + strncpy(group.name, argv[1], GNAME_MAX); + if(group.name[0] == '-') + G_fatal_error(_("The parser doesn't work here.")); + } + else { + if (!I_ask_group_old (_("Enter imagery group to be registered"), group.name)) + exit(EXIT_FAILURE); + } + + if (!I_get_group_ref (group.name, &group.ref)) + G_fatal_error ( _("Group [%s] contains no files"), group.name); + + if (group.ref.nfiles <= 0) + G_fatal_error ( _( "Group [%s] contains no files"), group.name); + +/* write group files to group list file */ + prepare_group_list(); + debug("prepare_group_list done"); + +/* get target info and enviroment */ + get_target(); + find_target_files(); + debug("find_target_files done"); + +/* read group control points, if any */ + G_suppress_warnings(1); + if (!I_get_control_points (group.name, &group.points)) + group.points.count = 0; + G_suppress_warnings(0); + +/* determine tranformation equation */ + G_debug(0, "starting Compute_equation()"); + Compute_equation(); + + signal (SIGINT, SIG_IGN); +/* signal (SIGQUIT, SIG_IGN); */ + + R_standard_color (BLUE); + + Init_graphics(); + display_title (VIEW_MAP1); + + G_debug(0, "select_target_env"); + select_target_env (); + display_title (VIEW_MAP2); + select_current_env (); + G_debug(0, "select_target_env done"); + + Begin_curses(); + G_debug(0, "Begin_curses done"); + G_set_error_routine (error); + +/* +#ifdef SIGTSTP + signal (SIGTSTP, SIG_IGN); +#endif +*/ + +/* ask user for group file to be displayed */ + G_debug(0, "ask user for group file to be displayed"); + do + { + if(!choose_groupfile (name, mapset)) + quit(0); + +/* display this file in "map1" */ + } + while (G_get_cellhd (name, mapset, &cellhd) < 0); + G_adjust_window_to_box (&cellhd, &VIEW_MAP1->cell.head, VIEW_MAP1->nrows, VIEW_MAP1->ncols); + Configure_view (VIEW_MAP1, name, mapset, cellhd.ns_res, cellhd.ew_res); + + drawcell(VIEW_MAP1); + display_points(1); + R_flush(); + + Curses_clear_window (PROMPT_WINDOW); + + Erase_view (VIEW_MAP1_ZOOM); + + +/* determine initial input method. */ + setup_digitizer(); + if (use_digitizer) + { + from_digitizer = 1; + from_keyboard = 0; + from_flag = 1; + } + +/* go do the work */ + driver(); + + quit(0); +} + +int quit (int n) +{ + char command[1024]; + + End_curses(); + R_close_driver(); + if (use_digitizer) + { + sprintf (command, "%s/etc/geo.unlock %s", + G_gisbase(), digit_points); + system (command); + } + unlink (tempfile1); + unlink (tempfile2); + unlink (tempfile3); + unlink (cell_list); + unlink (group_list); + unlink (vect_list); + unlink (digit_points); + unlink (digit_results); + exit(n); +} + +int error (char *msg, int fatal) +{ + char buf[200]; + int x,y,button; + +Curses_clear_window (PROMPT_WINDOW); +Curses_write_window (PROMPT_WINDOW,1,1, "LOCATION:\n"); +Curses_write_window (PROMPT_WINDOW,1,12,G_location()); +Curses_write_window (PROMPT_WINDOW,2,1, "MAPSET:\n"); +Curses_write_window (PROMPT_WINDOW,2,12,G_location()); + Beep(); + if (fatal) + sprintf (buf, "ERROR: %s", msg); + else + sprintf (buf, "WARNING: %s (click mouse to continue)", msg); + Menu_msg (buf); + + if (fatal) + quit(1); + Mouse_pointer (&x, &y, &button); + Curses_clear_window (PROMPT_WINDOW); + + return 0; +} + Property changes on: trunk/grassaddons/i.points.auto/main.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/mark.c =================================================================== --- trunk/grassaddons/i.points.auto/mark.c (rev 0) +++ trunk/grassaddons/i.points.auto/mark.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,205 @@ +#include +#include "globals.h" +#include "local_proto.h" + +static int get_point2 (double *,double *); +static int keyboard(); +static int _keyboard(); +static int screen (int,int,int); +static int digitizer(); +static int cancel(); + +int mark(int x,int y,int button) +{ + if (button != 1) + return where (x,y); + + if (VIEW_MAP1->cell.configured && In_view (VIEW_MAP1, x, y)) + mark_point (VIEW_MAP1, x, y); + else if (VIEW_MAP1_ZOOM->cell.configured && In_view (VIEW_MAP1_ZOOM, x, y)) + mark_point (VIEW_MAP1_ZOOM, x, y); + return 0 ; /* return but don't quit */ + + +} + +int mark_point (View *view,int x, int y) +{ + double e1,n1; + double e2,n2; + int row,col; + + char buf[100]; + +/* convert x,y to east,north at center of cell */ + col = view_to_col (view, x); + e1 = col_to_easting (&view->cell.head, col, 0.5); + row = view_to_row (view, y); + n1 = row_to_northing (&view->cell.head, row, 0.5); + + Curses_clear_window (MENU_WINDOW); + sprintf (buf, "Point %d marked on image at", group.points.count+1); + Curses_write_window (MENU_WINDOW, 1, 1, buf); + sprintf (buf, "East: %10.2f", e1); + Curses_write_window (MENU_WINDOW, 3, 3, buf); + sprintf (buf, "North: %10.2f", n1); + Curses_write_window (MENU_WINDOW, 4, 3, buf); + Curses_clear_window (INFO_WINDOW); + + R_standard_color (ORANGE); + save_under_dot (x,y); + dot(x,y); + + if (!get_point2(&e2, &n2)) + { + Curses_clear_window (MENU_WINDOW); + restore_under_dot(); + } + else + { + Curses_write_window (MENU_WINDOW, 7, 1, "Point located at"); + sprintf (buf, "East: %10.2f", e2); + Curses_write_window (MENU_WINDOW, 9, 3, buf); + sprintf (buf, "North: %10.2f", n2); + Curses_write_window (MENU_WINDOW,10, 3, buf); + I_new_control_point (&group.points, e1, n1, e2, n2, 1); + I_put_control_points (group.name, &group.points); + Compute_equation(); + display_points(1); + } + release_under_dot(); + + return 0; +} + +static double N,E; + +static int get_point2 (double *east,double *north) +{ + int digitizer(); + int keyboard(); + int stat; + int screen(); + int cancel(); + static int use = 1; + static Objects objects[] = + { + MENU ("CANCEL", cancel, &use), + INFO ("Mark point on target image", &use), + OTHER (screen, &use), + {0} + }; + + if (from_digitizer > 0) + { + stat = Input_other (digitizer, "Digitizer"); + } + else if (from_screen > 0) + { + set_colors (&VIEW_MAP2->cell.colors); + stat = Input_pointer(objects) > 0; + set_colors (&VIEW_MAP1->cell.colors); + } + else + stat = Input_other (keyboard, "Keyboard"); + + if(stat) + { + *east = E; + *north = N; + } + + return stat ; +} + +static int +keyboard (void) +{ + int ok; + Curses_clear_window (INFO_WINDOW); + ok = _keyboard (); + Curses_clear_window (INFO_WINDOW); + return ok; +} + +static int +_keyboard (void) +{ + char buf[100]; + + while(1) + { + Curses_prompt_gets ("Enter coordinates as east north: ", buf); + G_strip (buf); + if (*buf == 0) + { + return 0; + } + if (sscanf (buf, "%lf %lf", &E, &N) != 2) + { + Beep(); + continue; + } + Curses_clear_window (INFO_WINDOW); + sprintf (buf, "East: %f\n", E); + Curses_write_window (INFO_WINDOW, 2, 2, buf); + sprintf (buf, "North: %f\n", N); + Curses_write_window (INFO_WINDOW, 3, 2, buf); + Curses_write_window (INFO_WINDOW, 5, 1, "Look ok? (y/n) "); + + while(1) + { + int c; + c = Curses_getch(0); + if (c == 'y' || c == 'Y') + return 1; + if (c == 'n' || c == 'N') + break; + Beep(); + } + } + + return 0; +} + +static int +digitizer (void) +{ + return digitizer_point (&E, &N); +} + + +static int screen (int x,int y,int button) +{ + int row,col; + char buf[50]; + + View *view; + if (In_view (VIEW_MAP2, x, y) && VIEW_MAP2->cell.configured) + view = VIEW_MAP2; + else if (In_view (VIEW_MAP2_ZOOM, x, y) && VIEW_MAP2_ZOOM->cell.configured) + view = VIEW_MAP2_ZOOM; + else + return 0; /* ignore mouse event */ + + col = view_to_col (view, x); + E = col_to_easting (&view->cell.head, col, 0.5); + row = view_to_row (view, y); + N = row_to_northing (&view->cell.head, row, 0.5); + + if (button == 1) + return 1; + + sprintf (buf, "East: %10.2f\n", E); + Curses_write_window (INFO_WINDOW, 2, 2, buf); + sprintf (buf, "North: %10.2f\n", N); + Curses_write_window (INFO_WINDOW, 3, 2, buf); + + return 0; +} + +static int +cancel (void) +{ + return -1; +} Property changes on: trunk/grassaddons/i.points.auto/mark.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/mouse.c =================================================================== --- trunk/grassaddons/i.points.auto/mouse.c (rev 0) +++ trunk/grassaddons/i.points.auto/mouse.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,59 @@ +#include +#include "globals.h" + +static int first = 1; +static int curx, cury; + +int +Mouse_pointer (int *x, int *y, int *button) +{ + if (first) + { + curx = (SCREEN_LEFT + SCREEN_RIGHT)/2; + cury = (SCREEN_TOP + SCREEN_BOTTOM)/2; + first = 0; + } + R_get_location_with_pointer (&curx, &cury, button); + *x = curx; + *y = cury; + +#ifdef BUTTON3 + if (*button == 3) quit(0); +#endif + + return 0; +} + +int +Mouse_box_anchored (int x1, int y1, int *x2, int *y2, int *button) +{ + R_get_location_with_box (x1, y1, x2, y2, button); + curx = *x2; + cury = *y2; + first = 0; + +#ifdef BUTTON3 + if (*button == 3) quit(0); +#endif + + return 0; +} + +int +Get_mouse_xy (int *x, int *y) +{ + *x = curx; + *y = cury; + + return 0; +} + +int +Set_mouse_xy (int x, int y) +{ + first = 0; + curx = x; + cury = y; + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/mouse.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/orig/find_points_semi.c.org =================================================================== --- trunk/grassaddons/i.points.auto/orig/find_points_semi.c.org (rev 0) +++ trunk/grassaddons/i.points.auto/orig/find_points_semi.c.org 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,776 @@ +#include +#include +#include +#include +#include "globals.h" +#include "local_proto.h" +#include "raster.h" +#include "imagery.h" +#include "gmath.h" + +#ifdef NULL_VALUE +#undef NULL_VALUE +#endif +#define NULL_VALUE -1 + + +#ifdef DEBUG +#undef DEBUG +#endif + +struct Cell_head cellhd1; +struct Cell_head cellhd2; + +struct Control_Points sPoints; + +double *fft_first[2]; +double *fft_second[2]; +double *fft_prod_con[2]; + + + +View *m1, *m2; + +void Extract_matrix_semi() +{ + struct GModule *module; + struct Control_Points *cp1; + char buf[256]; + char *s; + int rows, cols; + char *first_map_R_mapset; + char *first_map_R_name; + int first_map_R_fd; + char *second_map_R_mapset; + char *second_map_R_name; + int second_map_R_fd; + + int K; + + int correlation_window_dim; + int search_window_dim; + + int squared_search_window_dim; + int search_jump; + + int ncols1, ncols2, nrows1, nrows2; + int left1, top1, left2, top2; + int repeat; + + int n_1, e_1, n_2, e_2, s_1, s_2, w_1, w_2; + int r1_1, r1_2, r2_1, r2_2; + int c1_1, c1_2, c2_1, c2_2; + + int i; + + int h1_r; + int h1_c; + int h2_r; + int h2_c; + + + char *group_name; + char *group_MAPSET; + char *group_LOCATION_NAME; + char *group_GISDBASE; + DCELL *rowbuf1_R; + DCELL *tf1_R; + DCELL *rowbuf2_R; + DCELL *tf2_R; + double **search_window; + double **mat1,**mat2; + int r,c; + int search_border; + int q; + int p1; + int dim_win_c, dim_win_r; + char first_sites[500]; + char second_sites[500]; + char file_name[500]; + char file_name_old[500]; + FILE *first_fp; + FILE *second_fp; + FILE *fp; + FILE *fp_old; + + + + /* Read VIEW_MAP1_ZOOM & VIEW_MAP2_ZOOM informations */ + + + m1=VIEW_MAP1_ZOOM; + m2=VIEW_MAP2_ZOOM; + + first_map_R_name=m1->cell.name; + second_map_R_name=m2->cell.name; + + /* rows & cols of VIEW_MAP1_ZOOM */ + n_1=m1->cell.head.north; + e_1=m1->cell.head.east; + s_1=m1->cell.head.south; + w_1=m1->cell.head.west; + left1 = m1->cell.left; + top1 = m1->cell.top; + + r1_1=s_1/m1->cell.ns_res; + r1_2=n_1/m1->cell.ns_res; + c1_1=w_1/m1->cell.ew_res; + c1_2=e_1/m1->cell.ew_res; + + nrows1=r1_2-r1_1; + ncols1=c1_2-c1_1; + + + /* rows & cols of VIEW_MAP2_ZOOM */ + n_2=m2->cell.head.north; + e_2=m2->cell.head.east; + s_2=m2->cell.head.south; + w_2=m2->cell.head.west; + left2 = m2->cell.left; + top2 = m2->cell.top; + + r2_1=s_2/m2->cell.ns_res; + r2_2=n_2/m2->cell.ns_res; + c2_1=w_2/m2->cell.ew_res; + c2_2=e_2/m2->cell.ew_res; + + nrows2=r2_2-r2_1; + ncols2=c2_2-c2_1; + + + + /* Initialize the GIS calls */ + module = G_define_module(); + module->description = "Fine registration of two stereo images"; + + /* Load environmental vars*/ + group_LOCATION_NAME=buf; + group_LOCATION_NAME=G_getenv("LOCATION_NAME"); + group_GISDBASE=buf; + group_GISDBASE=G_getenv("GISDBASE"); + group_MAPSET=buf; + group_MAPSET=G_getenv("MAPSET"); + + + /* Correlation parameters */ + correlation_window_dim=((ncols1/10+nrows1/10)/2); + K=((ncols1/4+nrows1/4)/2); + + search_window_dim = max_pow2(correlation_window_dim + K); + group_name=group.name; + squared_search_window_dim=search_window_dim*search_window_dim; + search_jump=search_window_dim / 2; + + + + Menu_msg ("Loading first zoom_image..."); + + /* Open first real map*/ + if((first_map_R_mapset = G_find_cell2(first_map_R_name, "")) == NULL) + { + sprintf(buf,"Raster map [%s] not available",first_map_R_name); + G_fatal_error(buf); + } + + + if((first_map_R_fd = G_open_cell_old(first_map_R_name, + first_map_R_mapset)) < 0) + { + sprintf(buf,"Error opening raster map [%s]", first_map_R_name); + G_fatal_error(buf); + } + + /* Set region to first map definition region < m1 > */ + G_get_cellhd (first_map_R_name, first_map_R_mapset, &cellhd1); + G_set_window(&cellhd1); + h1_r=cellhd1.rows; + h1_c=cellhd1.cols; + + + + /* Memory allocation for zoom_map_1 */ + + mat1 = (DCELL **) G_calloc(nrows1,sizeof(DCELL *)); + for(r=0;rcell.ns_res; + cellhd1.south=r1_1*m1->cell.ns_res; + cellhd1.east=c1_2*m1->cell.ew_res; + cellhd1.west=c1_1*m1->cell.ew_res; + + /* Set cellhd2 to zoom_map_2 */ + cellhd2.rows=nrows2; + cellhd2.cols=ncols2; + cellhd2.north=r2_2*m2->cell.ns_res; + cellhd2.south=r1_1*m2->cell.ns_res; + cellhd2.east=c2_2*m2->cell.ew_res; + cellhd2.west=c2_1*m2->cell.ew_res; + + /* Set windows to cellhd1 */ + G_set_window(&cellhd1); + + + + /******************************************/ + /* function --> Search_correlation_points */ + /******************************************/ + Search_correlation_points_semi(mat1, mat2, + search_window_dim, + squared_search_window_dim, + search_jump,group_name, nrows1, ncols1, + search_window, r1_2, c1_1, r2_2, c2_1, + h1_r, h2_r, h1_c, h2_c, nrows2, ncols2 ); + + + + + /* Build group/POINTS file */ + sPoints.count -= 1; + if(sPoints.count > 0) + { + sprintf(file_name,"%s/%s/%s/group/%s/POINTS",group_GISDBASE, + group_LOCATION_NAME,group_MAPSET,group_name); + fp_old = fopen(file_name,"r"); + if( fp_old==NULL) + { + q=0; + } + else + { + q=1; + fclose(fp_old); + } + + if (q==0) + { + fp = fopen(file_name,"a"); + fprintf (fp,"# %7s %15s %15s %15s %9s status\n","", + "image","","target",""); + fprintf (fp,"# %15s %15s %15s %15s (1=ok)\n", + "east","north","east","north"); + fprintf (fp,"#\n"); + + for (i = 0; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + fprintf (fp, " %15f %15f %15f %15f %4d\n", + sPoints.e1[i], sPoints.n1[i], sPoints.e2[i], sPoints.n2[i], sPoints.status[i]); + + } + if(q==1) + { + fp = fopen(file_name,"a"); + for (i = 0; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + fprintf (fp, " %15f %15f %15f %15f %4d\n", sPoints.e1[i], sPoints.n1[i], sPoints.e2[i], sPoints.n2[i], sPoints.status[i]); + } + fclose (fp); + } + + /* Load new control points */ + + for (i = 0; i < sPoints.count; i++) + if ( sPoints.status[i] != -1) + new_control_point (&group.points,sPoints.e1[i], sPoints.n1[i], + sPoints.e2[i], sPoints.n2[i], sPoints.status[i] ); + + /* Build group/REF file */ + /* + sprintf(file_name,"%s/%s/%s/group/%s/REF",group_GISDBASE, + group_LOCATION_NAME, group_MAPSET,group_name); + fp = fopen(file_name,"w"); + fprintf(fp,"%s %s\n",first_map_R_name,first_map_R_mapset); + + fclose(fp); + */ + + /* Build group/TARGET file */ + sprintf(file_name,"%s/%s/%s/group/%s/TARGET",group_GISDBASE, + group_LOCATION_NAME, group_MAPSET,group_name); + fp = fopen(file_name,"w"); + fprintf(fp,"%s\n%s\n",group_LOCATION_NAME,group_MAPSET); + fclose(fp); + + /* Display new points */ + select_current_env (); + display_points_in_view (VIEW_MAP1, 1, + group.points.e1, group.points.n1, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP1_ZOOM, 1, + group.points.e1, group.points.n1, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP2, 1, + group.points.e2, group.points.n2, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP2_ZOOM, 1, + group.points.e2, group.points.n2, + group.points.status, group.points.count); + R_flush(); + + /* Free memory */ + + free( rowbuf1_R); + free( rowbuf2_R); + + + for(r=0;r=nrows2)||(c-search_border+2*search_border>=ncols2)) + { + if (sPoints.count<=1) + { + Menu_msg("DEFINE A NEW REGION."); + sleep(3); + pause; + } + return 0; + } + + Extract_portion_of_double_matrix_semi(r,c,search_border,search_border, + mat2_R,search_window); + mean = 0.0; + for(i=0;i cross-correlation at differnet lag + between the two orig. (complex) windows */ + fft(1,fft_prod_con,squared_search_window_dim,search_window_dim, + search_window_dim); + +#ifdef DEBUG + for(i=0;i cc) + { + cc = fft_prod_con[0][i]; + tmp_r=i/search_window_dim; + tmp_c=i%search_window_dim; + + } + } + + /* Get coordinates of "ending" point */ + if((tmp_r <= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - tmp_c,&cellhd2); + north2 = G_row_to_northing((double) r - tmp_r,&cellhd2); + + } + if((tmp_r <= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - (tmp_c-search_window_dim-1),&cellhd2); + north2 = G_row_to_northing((double) r - tmp_r,&cellhd2); + + } + if((tmp_r >= search_window_dim/2) && (tmp_c <= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - tmp_c,&cellhd2); + north2 = G_row_to_northing((double) r - (tmp_r-search_window_dim-1),&cellhd2); + + } + if((tmp_r >= search_window_dim/2) && (tmp_c >= search_window_dim/2)) + { + + east2 = G_col_to_easting((double) c - (tmp_c-search_window_dim-1),&cellhd2); + north2 = G_row_to_northing((double) r - (tmp_r-search_window_dim-1),&cellhd2); + + } + + + /* Fill the POINTS file*/ + sPoints.e1[sPoints.count-1] = east1; + sPoints.n1[sPoints.count-1] = north1; + sPoints.e2[sPoints.count-1] = east2; + sPoints.n2[sPoints.count-1] = north2; + + sPoints.status[sPoints.count-1] = 1; + sPoints.count += 1; + sPoints.e1=(double *)G_realloc(sPoints.e1,sPoints.count*sizeof(double)); + sPoints.n1=(double *)G_realloc(sPoints.n1,sPoints.count*sizeof(double)); + sPoints.e2=(double *)G_realloc(sPoints.e2,sPoints.count*sizeof(double)); + sPoints.n2=(double *)G_realloc(sPoints.n2,sPoints.count*sizeof(double)); + sPoints.status=(int *)G_realloc(sPoints.status,sPoints.count*sizeof(int)); + } + G_percent (r,dim_win_r, 1); + } + } + + +void Extract_portion_of_double_matrix_semi(int r,int c,int br,int bc,DCELL **mat,DCELL **wind) + /* + extract a squared portion of a matrix mat + given a the indeces of the center [r,c] + and the semilength of the borders [br,bc] + Output to array wind + */ +{ + int i,j; + for(i=0;(i <2*br);i++) + for(j = 0;(j <2*bc);j++) + { + wind[i][j] = mat[r - br + i][c - bc +j]; + } +} + + + + + + + + + + + + + + + + + + + + + + Added: trunk/grassaddons/i.points.auto/orig/globals.h.org =================================================================== --- trunk/grassaddons/i.points.auto/orig/globals.h.org (rev 0) +++ trunk/grassaddons/i.points.auto/orig/globals.h.org 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,114 @@ +#include "defs.h" + +#ifndef GLOBAL +# define GLOBAL extern +# define INIT(x) +#else +# define INIT(x) = x +#endif + + + + +/* Variable for the botton "Main-Menu". */ +GLOBAL int m; + + + + + +GLOBAL int G_get_color(); + +GLOBAL int SCREEN_TOP; +GLOBAL int SCREEN_BOTTOM; +GLOBAL int SCREEN_LEFT; +GLOBAL int SCREEN_RIGHT; + +GLOBAL int correlation_window_dim; +GLOBAL int K; +GLOBAL char *group_name; + + + +GLOBAL Window *INFO_WINDOW; +GLOBAL Window *MENU_WINDOW; +GLOBAL Window *PROMPT_WINDOW; + +GLOBAL View *VIEW_MAP1; +GLOBAL View *VIEW_TITLE1; +GLOBAL View *VIEW_MAP1_ZOOM; +GLOBAL View *VIEW_TITLE1_ZOOM; + +GLOBAL View *VIEW_MAP2; +GLOBAL View *VIEW_TITLE2; +GLOBAL View *VIEW_MAP2_ZOOM; +GLOBAL View *VIEW_TITLE2_ZOOM; + +GLOBAL View *VIEW_MENU; + +GLOBAL Group group; + +GLOBAL char interrupt_char; +GLOBAL char *tempfile1; +GLOBAL char *tempfile2; +GLOBAL char *tempfile3; +GLOBAL char *digit_points; /* digitizer control points */ +GLOBAL char *digit_results; /* digitizer results */ +GLOBAL int use_digitizer INIT(0); /* is there a digitizer out there? */ + +/* group file list, target cell,vector files */ +GLOBAL char *group_list INIT(NULL); +GLOBAL char *cell_list INIT(NULL); +GLOBAL char *vect_list INIT(NULL); + +GLOBAL int from_keyboard INIT(-1); /* input method */ +GLOBAL int from_digitizer INIT(-1); +GLOBAL int from_screen INIT(-1); +GLOBAL int from_flag INIT(0); + +GLOBAL int dotsize INIT(4); + +GLOBAL int THE_COLORS[10]; +#define BLACK THE_COLORS[0] +#define BLUE THE_COLORS[1] +#define BROWN THE_COLORS[2] +#define GREEN THE_COLORS[3] +#define GREY THE_COLORS[4] +#define ORANGE THE_COLORS[5] +#define PURPLE THE_COLORS[6] +#define RED THE_COLORS[7] +#define WHITE THE_COLORS[8] +#define YELLOW THE_COLORS[9] + +double row_to_northing(); +double col_to_easting(); +double northing_to_row(); +double easting_to_col(); + +#undef INIT + + + + + + + + + + + + + + + + + + + + + + + + + + Added: trunk/grassaddons/i.points.auto/overlap_area.c =================================================================== --- trunk/grassaddons/i.points.auto/overlap_area.c (rev 0) +++ trunk/grassaddons/i.points.auto/overlap_area.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,141 @@ +#include +#include "globals.h" +#include "local_proto.h" + +static View *pick_view, *zoom_view, *main_view; +static int target_flag; + + +int overlap_area(int xp, int yp, int xs, int ys, int n_img, int ncols, int nrows) +{ + + int x_1, y_1, x_2, y_2; + int tmp_right, tmp_left; + int tmp_bottom, tmp_top; + int tmp_ncols; + int tmp_nrows; + + int top, bottom, left, right; + int row,col; + struct Cell_head cellhd; + + + + if(n_img==1) + { + pick_view = VIEW_MAP1; + main_view = VIEW_MAP1; + zoom_view = VIEW_MAP1_ZOOM; + target_flag = 0; + printf("info VIEW_MAP1_ZOOM: nrows=%d ncols=%d",zoom_view->nrows,zoom_view->ncols); + } + + else if (n_img==2) + { + pick_view = VIEW_MAP2; + main_view = VIEW_MAP2; + zoom_view = VIEW_MAP2_ZOOM; + target_flag = 1; + } + + else + return 0; + if (!pick_view->cell.configured) return 0; /* just to be sure */ + + + tmp_right = pick_view->cell.right; + tmp_left = pick_view->cell.left; + tmp_ncols = (tmp_right - tmp_left); + + tmp_bottom = pick_view->cell.bottom; + tmp_top = pick_view->cell.top; + tmp_nrows = (tmp_bottom - tmp_top); + + + x_1 = ((tmp_ncols*xp)/ncols); + y_1 = (((pick_view->nrows)*yp)/nrows); + x_2 = ((tmp_ncols*xs)/ncols); + y_2 = (((pick_view->nrows)*ys)/nrows); + + + + + if (x_1 == x_2 || y_1 == y_2) return 0; /* ignore event */ + + + + top = row_to_view (pick_view, y_1); + left = col_to_view (pick_view, x_1); + bottom = row_to_view (pick_view, y_2); + right = col_to_view (pick_view, x_2); + + + if (!In_view (pick_view,right,bottom)) return 0; + + + Menu_msg(""); + + + G_copy (&cellhd, &pick_view->cell.head, sizeof(cellhd)); + + + col = view_to_col(pick_view,left); + row = view_to_row(pick_view,top); + cellhd.north = row_to_northing (&pick_view->cell.head,row,0.0); + cellhd.west = col_to_easting (&pick_view->cell.head,col,0.0); + + + col = view_to_col(pick_view,right); + row = view_to_row(pick_view,bottom); + cellhd.south = row_to_northing (&pick_view->cell.head,row,1.0); + cellhd.east = col_to_easting (&pick_view->cell.head,col,1.0); + + + + cellhd.rows = bottom-top+1; + cellhd.cols = right-left+1; + cellhd.ns_res = (cellhd.north-cellhd.south)/cellhd.rows; + cellhd.ew_res = (cellhd.east-cellhd.west)/cellhd.cols; + + if (zoom_view->cell.configured) + { + R_standard_color (GREY); + Outline_cellhd (main_view, &zoom_view->cell.head); + } + R_standard_color (RED); + Outline_cellhd (main_view, &cellhd); + + if (target_flag) + select_target_env(); + G_adjust_window_to_box (&cellhd, &zoom_view->cell.head, zoom_view->nrows, + zoom_view->ncols); + Configure_view (zoom_view, pick_view->cell.name, pick_view->cell.mapset, + pick_view->cell.ns_res, pick_view->cell.ew_res); + + + drawcell (zoom_view); + select_current_env(); + display_points(1); + + + return 0; + +} + + +static int + +cancel (void) +{ + return -1; +} + + + + + + + + + + Property changes on: trunk/grassaddons/i.points.auto/overlap_area.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/points.c =================================================================== --- trunk/grassaddons/i.points.auto/points.c (rev 0) +++ trunk/grassaddons/i.points.auto/points.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,184 @@ +#include +#include +#include "globals.h" +#include "local_proto.h" + +int display_line (View *view, double *east, double *north,int *status,int count); + +int display_points (int in_color) +{ + display_points_in_view (VIEW_MAP1, in_color, + group.points.e1, group.points.n1, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP1_ZOOM, in_color, + group.points.e1, group.points.n1, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP2, in_color, + group.points.e2, group.points.n2, + group.points.status, group.points.count); + + display_points_in_view (VIEW_MAP2_ZOOM, in_color, + group.points.e2, group.points.n2, + group.points.status, group.points.count); + + return 0; +} + +int display_points_in_view (View *view, int in_color, + double *east, double *north, int *status, int count) +{ + if (!view->cell.configured) return 1; + D_cell_draw_setup(view->top, view->bottom, view->left, view->right); + D_set_clip_window(view->top, view->bottom, view->left, view->right); + while (count-- > 0) + { + if (in_color && ((*status ==2)||(*status ==-2))) + display_line(view,east, north, status,count); + if (in_color && (*status > 0)) + R_standard_color (GREEN); + else if (in_color && ((*status == 0)||(*status <= -2))) + R_standard_color (RED); + else + R_standard_color (GREEN); + + status++; + display_one_point (view, *east++, *north++); + } + + return 0; +} + +/*The first point is displayed with BLUE, and the others with GREEN */ +int display_points_in_view_diff_color (View *view, int in_color, + double *east, double *north, int *status, int count) +{ + if (!view->cell.configured) return 1; + D_cell_draw_setup(view->top, view->bottom, view->left, view->right); + D_set_clip_window(view->top, view->bottom, view->left, view->right); + + count--; + if (in_color && (*status > 0)) + R_standard_color (BLUE); + status++; + display_one_point (view, *east++, *north++); + + + while (count-- > 0) + { + if (in_color && ((*status ==2)||(*status ==-2))) + display_line(view,east, north, status,count); + if (in_color && (*status > 0)) + R_standard_color (GREEN); + + else if (in_color && ((*status == 0)||(*status <= -2))) + R_standard_color (RED); + else + R_standard_color (GREEN); + + status++; + display_one_point (view, *east++, *north++); + } + + return 0; +} + + + +/*Displays only the active points (with GREEN) */ +int display_points_in_view_diff_color_if_active (View *view, int in_color, + double *east, double *north, int *status, int count) +{ + if (!view->cell.configured) return 1; + D_cell_draw_setup(view->top, view->bottom, view->left, view->right); + D_set_clip_window(view->top, view->bottom, view->left, view->right); + + count--; + if (in_color && (*status > 0)) + R_standard_color (BLUE); + status++; + display_one_point (view, *east++, *north++); + + + while (count-- > 0) + { + if (in_color && (*status > 0)) + { + R_standard_color (GREEN); + status++; + display_one_point (view, *east++, *north++); + } + else if (in_color && ((*status == 0)||(*status <= -2))) + { + R_standard_color (RED); + status++; + *east++; + *north++; + } + else + { + R_standard_color (GREEN); + + status++; + display_one_point (view, *east++, *north++); + } + + } + + return 0; +} + + + + + + + + + + + +int display_one_point (View *view, double east, double north) +{ + int row, col, x, y; + + row = northing_to_row (&view->cell.head, north) + .5; + col = easting_to_col (&view->cell.head, east) + .5; + y = row_to_view (view, row); + x = col_to_view (view, col); + if (In_view(view, x, y)) + dot (x,y); + + return 0; +} + + +int display_line (View *view, double *east, double *north,int *status,int count) + { + int row, col, x[2], y[2]; + + if (count==0) return 1; + if ((*(status +1)!=3) && (*(status+1)!=-3)) return 1; + + row = northing_to_row (&view->cell.head, *north) + .5; + col = easting_to_col (&view->cell.head, *east) + .5; + y[0] = row_to_view (view, row); + x[0] = col_to_view (view, col); + + row = northing_to_row (&view->cell.head, *(north+1)) + .5; + col = easting_to_col (&view->cell.head, *(east+1)) + .5; + y[1] = row_to_view (view, row); + x[1] = col_to_view (view, col); + if (*status == 2 ) + R_standard_color (GREEN); + + else R_standard_color (RED); + D_move_abs(x[0],y[0]); + D_cont_abs(x[1],y[1]); + /* R_polyline_abs (x,y,2); */ + /*plot_line(*east,*north,*(east+1),*(north+1)); */ + R_flush(); + } + + Property changes on: trunk/grassaddons/i.points.auto/points.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/target.c =================================================================== --- trunk/grassaddons/i.points.auto/target.c (rev 0) +++ trunk/grassaddons/i.points.auto/target.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,71 @@ +#include +#include +#include "globals.h" + +/* read the target for the group and cast it into the alternate GRASS env */ + +static int which_env; + +int get_target (void) +{ + char location[40]; + char mapset[40]; + char buf[1024]; + int stat; + + if (!I_get_target(group.name, location, mapset)) + { + sprintf(buf, "Target information for group [%s] missing\n", group.name); + goto error; + } + + sprintf (buf, "%s/%s", G_gisdbase(), location); + if (access(buf,0) != 0) + { + sprintf (buf,"Target location [%s] not found\n", location); + goto error; + } + G__create_alt_env(); + G__setenv ("LOCATION_NAME", location); + stat = G__mapset_permissions(mapset); + if (stat > 0) + { + G__setenv ("MAPSET", mapset); + G__create_alt_search_path(); + G__switch_env(); + G__switch_search_path(); + which_env = 0; + return 1; + } + sprintf (buf, "Mapset [%s] in target location [%s] - ", + mapset, location); + strcat (buf, stat == 0 ? "permission denied\n" : "not found\n"); +error: + strcat (buf, "Please run i.target for group "); + strcat (buf, group.name); + G_fatal_error (buf); +} + +int select_current_env (void) +{ + if (which_env != 0) + { + G__switch_env(); + G__switch_search_path(); + which_env = 0; + } + + return 0; +} + +int select_target_env (void) +{ + if (which_env != 1) + { + G__switch_env(); + G__switch_search_path(); + which_env = 1; + } + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/target.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/title.c =================================================================== --- trunk/grassaddons/i.points.auto/title.c (rev 0) +++ trunk/grassaddons/i.points.auto/title.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,56 @@ +#include +#include "globals.h" +#include "local_proto.h" + +int +display_title (View *view) +{ + View *title; + char left[100], center[100]; + int size; + double magnification(); + + *left = 0; + *center = 0; + + if (view->cell.configured) + { + sprintf (center, "%s (mag %.1f)", + view->cell.name, magnification (view)); + } + + if (view == VIEW_MAP1) + { + sprintf (left, "%s", G_location()); + title = VIEW_TITLE1; + } + else if (view == VIEW_MAP1_ZOOM) + { + title = VIEW_TITLE1_ZOOM; + } + + if (view == VIEW_MAP2) + { + sprintf (left, "%s", G_location()); + title = VIEW_TITLE2; + } + else if (view == VIEW_MAP2_ZOOM) + { + title = VIEW_TITLE2_ZOOM; + } + + Erase_view (title); + R_standard_color (ORANGE); /*WHITE*/ + size = title->nrows - 4; + R_text_size (size, size); + Text (left, title->top, title->bottom, title->left, title->right, 2); + if (*center) + { + R_standard_color (YELLOW); + Text (center, title->top, title->bottom, + (title->left + title->right - Text_width (center)) / 2, + title->right, 2); + } + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/title.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/view.c =================================================================== --- trunk/grassaddons/i.points.auto/view.c (rev 0) +++ trunk/grassaddons/i.points.auto/view.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,57 @@ +#include +#include +#include "globals.h" +#include "local_proto.h" + +int Configure_view ( + View *view, + char *name, + char *mapset, + double ns_res, + double ew_res /* original map resolution */ +) +{ + Erase_view(view); + view->cell.configured = 0; + +/* copy the cell name into the view */ + strcpy (view->cell.name, name); + strcpy (view->cell.mapset, mapset); + +/* determine the map edges */ + view->cell.left = view->left + (view->ncols - view->cell.head.cols)/2; + view->cell.right = view->cell.left + view->cell.head.cols - 1; + view->cell.top = view->top + (view->nrows - view->cell.head.rows)/2; + view->cell.bottom = view->cell.top + view->cell.head.rows - 1; + +/* remember original resolutions */ + view->cell.ns_res = ns_res; + view->cell.ew_res = ew_res; + + view->cell.configured = 1; + + return 0; +} + +int +In_view (View *view, int x, int y) +{ + return (x >= view->left && x <= view->right && y >= view->top && y <= view->bottom); +} + +int +Erase_view (View *view) +{ + R_standard_color (BLUE); + R_box_abs (view->left, view->top, view->right, view->bottom); + + return 0; +} + +double +magnification (View *view) +{ + if (!view->cell.configured) + return ((double) 0.0); + return (view->cell.ew_res / view->cell.head.ew_res); +} Property changes on: trunk/grassaddons/i.points.auto/view.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/where.c =================================================================== --- trunk/grassaddons/i.points.auto/where.c (rev 0) +++ trunk/grassaddons/i.points.auto/where.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,66 @@ +#include "globals.h" +#include "local_proto.h" + +static int where_12 (View *,int,int); +static int where_21 (View *,int,int); +static int where_am_i (View *,int,int,Window *,double *,double *,Window *); + +int where (int x, int y) +{ + if (VIEW_MAP1->cell.configured && In_view (VIEW_MAP1, x, y)) + where_12 (VIEW_MAP1, x, y); + else if (VIEW_MAP1_ZOOM->cell.configured && In_view (VIEW_MAP1_ZOOM, x, y)) + where_12 (VIEW_MAP1_ZOOM, x, y); + else if (VIEW_MAP2->cell.configured && In_view (VIEW_MAP2, x, y)) + where_21 (VIEW_MAP2, x, y); + else if (VIEW_MAP2_ZOOM->cell.configured && In_view (VIEW_MAP2_ZOOM, x, y)) + where_21 (VIEW_MAP2_ZOOM, x, y); + return 0 ; /* return but don't quit */ +} + +static int where_12 (View *view,int x, int y) +{ + where_am_i (view, x, y, MENU_WINDOW, group.E12, group.N12, INFO_WINDOW); + + return 0; +} + +static int where_21 (View *view,int x, int y) +{ + where_am_i (view, x, y, INFO_WINDOW, group.E21, group.N21, MENU_WINDOW); + + return 0; +} + +static int where_am_i (View *view,int x, int y,Window *w1, + double *E,double *N,Window *w2) +{ + double e1,n1,e2,n2; + int row,col; + + char buf[100]; + +/* convert x,y to east,north at center of cell */ + col = view_to_col (view, x); + e1 = col_to_easting (&view->cell.head, col, 0.5); + row = view_to_row (view, y); + n1 = row_to_northing (&view->cell.head, row, 0.5); + + Curses_clear_window (w1); + sprintf (buf, "East: %10.2f", e1); + Curses_write_window (w1, 3, 3, buf); + sprintf (buf, "North: %10.2f", n1); + Curses_write_window (w1, 4, 3, buf); + +/* if transformation equation is useable, determine point via equation */ + if (group.equation_stat <= 0) return 1; + + I_georef (e1, n1, &e2, &n2, E, N); + Curses_clear_window (w2); + sprintf (buf, "East: %10.2f", e2); + Curses_write_window (w2, 3, 3, buf); + sprintf (buf, "North: %10.2f", n2); + Curses_write_window (w2, 4, 3, buf); + + return 0; +} Property changes on: trunk/grassaddons/i.points.auto/where.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/zoom.c =================================================================== --- trunk/grassaddons/i.points.auto/zoom.c (rev 0) +++ trunk/grassaddons/i.points.auto/zoom.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,53 @@ +#include "globals.h" +#include "local_proto.h" + +static int cancel(); +static int use_zoom_box = 1; +static int use_zoom_pnt = 0; + + + +int zoom() +{ + static int use = 1; + int cancel(); + /*static int which_zoom();*/ + + static Objects objects[]= + { + MENU("CANCEL",cancel,&use), + INFO("Current ZOOM Type.",&use), + OPTION("BOX", 2, &use_zoom_box), + OPTION("POINT", 2, &use_zoom_pnt), + OTHER(which_zoom, &use), + {0} + }; + + Input_pointer (objects); + return 0; /* return, but don't QUIT */ +} + +static int +which_zoom(int x,int y,int button) +{ + + /* Button one to set point, Button 2 & 3 return location */ + if (button != 1) + return where (x,y); + + + if (use_zoom_box == 1) + zoom_box(x,y); + else zoom_pnt(x,y); + + return 0; +} + + + + +static int +cancel (void) +{ + return -1; +} Property changes on: trunk/grassaddons/i.points.auto/zoom.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/zoom_box.c =================================================================== --- trunk/grassaddons/i.points.auto/zoom_box.c (rev 0) +++ trunk/grassaddons/i.points.auto/zoom_box.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,193 @@ +#include +#include "globals.h" +#include "local_proto.h" + + +static int zoom2(int,int); +static int cancel(void); + +static int x1, y1, x2, y2; +static View *pick_view, *zoom_view, *main_view; +static int target_flag; + + + +int zoom_box (int x,int y) /* called by Input_pointer */ +{ + static int use = 1; + int zoom2(); + int cancel(); + + static Objects objects[] = + { + MENU("CANCEL",cancel,&use), + INFO(" Define the region ",&use), + OTHER(zoom2,&use), + {0} + }; + +/* + * user has marked first corner + * this determines which view is being zoomed + */ + x1 = x; + y1 = y; + + if (In_view (pick_view = VIEW_MAP1, x1, y1)) + { + main_view = VIEW_MAP1; + zoom_view = VIEW_MAP1_ZOOM; + target_flag = 0; + printf("info VIEW_MAP1_ZOOM: nrows=%d ncols=%d",zoom_view->nrows,zoom_view->ncols); + } + else if (In_view (pick_view = VIEW_MAP2, x1, y1)) + { + if (!pick_view->cell.configured) + return 0; /* ignore the mouse event */ + main_view = VIEW_MAP2; + zoom_view = VIEW_MAP2_ZOOM; + target_flag = 1; + } + else if (In_view (pick_view = VIEW_MAP1_ZOOM, x1, y1)) + { + if (!pick_view->cell.configured) + return 0; /* ignore the mouse event */ + main_view = VIEW_MAP1; + zoom_view = VIEW_MAP1_ZOOM; + target_flag = 0; + } + else if (In_view (pick_view = VIEW_MAP2_ZOOM, x1, y1)) + { + if (!pick_view->cell.configured) + return 0; /* ignore the mouse event */ + main_view = VIEW_MAP2; + zoom_view = VIEW_MAP2_ZOOM; + target_flag = 1; + } + else + return 0; /* ignore the mouse event */ + if (!pick_view->cell.configured) return 0; /* just to be sure */ + + return Input_box (objects, x, y); +} + + + + +static int zoom2(int x,int y) +{ + int top, bottom, left, right; + int row,col; + struct Cell_head cellhd; + + x2 = x; + y2 = y; +/* + * user has completed the zoom window. + * must be in same view as first corner + */ + + if (x1 == x2 || y1 == y2) return 0; /* ignore event */ + if (!In_view (pick_view,x2,y2)) return 0; + +/* + * ok, erase menu messages + */ + + Menu_msg(""); + +/* + * assign window coordinates to top,bottom,left,right + */ + if (x1 < x2) + { + left = x1; + right = x2; + } + else + { + left = x2; + right = x1; + } + if (y1 < y2) + { + top = y1; + bottom = y2; + } + else + { + top = y2; + bottom = y1; + } + +/* + * Determine the zoom window (ie, cellhd) + * must copy the current view cellhd first, to preserve header info + * (such as projection, zone, and other items.) + * compute zoom window northings,eastings, rows, cols, and resolution + */ + + G_copy (&cellhd, &pick_view->cell.head, sizeof(cellhd)); + +/* + * convert top to northing at top edge of cell + * left to easting at left edge + */ + col = view_to_col(pick_view,left); + row = view_to_row(pick_view,top); + cellhd.north = row_to_northing (&pick_view->cell.head,row,0.0); + cellhd.west = col_to_easting (&pick_view->cell.head,col,0.0); + +/* + * convert bottom to northing at bottom edge of cell + * right to easting at right edge + */ + col = view_to_col(pick_view,right); + row = view_to_row(pick_view,bottom); + cellhd.south = row_to_northing (&pick_view->cell.head,row,1.0); + cellhd.east = col_to_easting (&pick_view->cell.head,col,1.0); + + + cellhd.rows = bottom-top+1; + cellhd.cols = right-left+1; + cellhd.ns_res = (cellhd.north-cellhd.south)/cellhd.rows; + cellhd.ew_res = (cellhd.east-cellhd.west)/cellhd.cols; + +/* + * Outline the zoom window on the main map + * Turn previous one to grey. + */ + if (zoom_view->cell.configured) + { + R_standard_color (GREY); + Outline_cellhd (main_view, &zoom_view->cell.head); + } + R_standard_color (RED); + Outline_cellhd (main_view, &cellhd); + + +/* + * zoom + */ + if (target_flag) + select_target_env(); + G_adjust_window_to_box (&cellhd, &zoom_view->cell.head, zoom_view->nrows, + zoom_view->ncols); + Configure_view (zoom_view, pick_view->cell.name, pick_view->cell.mapset, + pick_view->cell.ns_res, pick_view->cell.ew_res); + + + + drawcell (zoom_view); + select_current_env(); + display_points(1); + return 1; /* pop back */ + +} + +static int + +cancel (void) +{ + return -1; +} Property changes on: trunk/grassaddons/i.points.auto/zoom_box.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/grassaddons/i.points.auto/zoom_pnt.c =================================================================== --- trunk/grassaddons/i.points.auto/zoom_pnt.c (rev 0) +++ trunk/grassaddons/i.points.auto/zoom_pnt.c 2007-10-21 08:38:25 UTC (rev 1152) @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include "globals.h" +#include "local_proto.h" + +static int cancel(void); + +static View *pick_view, *zoom_view, *main_view; +static int target_flag; + +int zoom_pnt (int x,int y) /* called by Input_pointer */ +{ + int top, bottom, left, right; + int n,row,col; + int nrows, ncols; + struct Cell_head cellhd; + int mag; + double magnification(); + double north, south, east, west; + + if (In_view (pick_view = VIEW_MAP1, x, y)) + { + main_view = VIEW_MAP1; + zoom_view = VIEW_MAP1_ZOOM; + target_flag = 0; + } + else if (In_view (pick_view = VIEW_MAP2, x, y)) + { + if (!pick_view->cell.configured) + return 0; /* ignore the mouse event */ + main_view = VIEW_MAP2; + zoom_view = VIEW_MAP2_ZOOM; + target_flag = 1; + } + else if (In_view (pick_view = VIEW_MAP1_ZOOM, x, y)) + { + if (!pick_view->cell.configured) + return 0; /* ignore the mouse event */ + main_view = VIEW_MAP1; + zoom_view = VIEW_MAP1_ZOOM; + target_flag = 0; + } + else if (In_view (pick_view = VIEW_MAP2_ZOOM, x, y)) + { + if (!pick_view->cell.configured) + return 0; /* ignore the mouse event */ + main_view = VIEW_MAP2; + zoom_view = VIEW_MAP2_ZOOM; + target_flag = 1; + } + else + return 0; /* ignore the mouse event */ + if (!pick_view->cell.configured) return 0; /* just to be sure */ +/* + * make sure point is within edges of image as well + */ + if (x <= pick_view->cell.left) return 0; + if (x >= pick_view->cell.right) return 0; + if (y <= pick_view->cell.top) return 0; + if (y >= pick_view->cell.bottom) return 0; + + +/* + * ok, erase menu messages + */ + Menu_msg(""); + +/* determine magnification of zoom */ + if (zoom_view->cell.configured) + { + if (zoom_view == pick_view) + mag = floor(magnification (zoom_view) + 1.0) + .1; + else + mag = ceil(magnification (zoom_view)) + .1; + } + else + { + mag = floor(magnification (main_view) + 1.0) + .1; + } + if(!ask_magnification (&mag)) + return 1; +/* + * Determine the the zoom window (ie, cellhd) + */ + + G_copy (&cellhd, &main_view->cell.head, sizeof(cellhd)); + cellhd.ns_res = main_view->cell.ns_res / mag; + cellhd.ew_res = main_view->cell.ew_res / mag; + cellhd.cols = (cellhd.east - cellhd.west) / cellhd.ew_res; + cellhd.rows = (cellhd.north - cellhd.south) / cellhd.ns_res; + + +/* convert x,y to col,row */ + + col = view_to_col(pick_view,x); + east = col_to_easting (&pick_view->cell.head, col, 0.5); + col = easting_to_col (&cellhd, east); + + row = view_to_row(pick_view,y); + north = row_to_northing (&pick_view->cell.head, row, 0.5); + row = northing_to_row (&cellhd, north); + + ncols = zoom_view->ncols ; + nrows = zoom_view->nrows ; + + + n = cellhd.cols - col; + if (n > col) + n = col; + if (n+n+1 >= ncols) + { + n = ncols/2; + if (n+n+1 >= ncols) n--; + } + left = col - n; + right = col + n; + + n = cellhd.rows - row; + if (n > row) + n = row; + if (n+n+1 >= nrows) + { + n = nrows/2; + if (n+n+1 >= nrows) n--; + } + top = row - n; + bottom = row + n; + + + north = row_to_northing (&cellhd, top,0.0); + west = col_to_easting (&cellhd,left,0.0); + south = row_to_northing (&cellhd,bottom,1.0); + east = col_to_easting (&cellhd,right,1.0); + + + cellhd.north = north; + cellhd.south = south; + cellhd.east = east ; + cellhd.west = west ; + + cellhd.rows = (cellhd.north-cellhd.south)/cellhd.ns_res; + cellhd.cols = (cellhd.east-cellhd.west)/cellhd.ew_res ; + +/* + * Outline the zoom window on the main map + * Turn previous one to grey. + */ + if (zoom_view->cell.configured) + { + R_standard_color (GREY); + Outline_cellhd (main_view, &zoom_view->cell.head); + } + R_standard_color (RED); + Outline_cellhd (main_view, &cellhd); + + +/* + * zoom + */ + if (target_flag) + select_target_env(); + G_copy (&zoom_view->cell.head, &cellhd, sizeof (cellhd)); + Configure_view (zoom_view, pick_view->cell.name, pick_view->cell.mapset, + pick_view->cell.ns_res, pick_view->cell.ew_res); + drawcell (zoom_view); + select_current_env(); + display_points(1); + + return 1; /* pop back */ +} + + +static int +cancel (void) +{ + return -1; +} Property changes on: trunk/grassaddons/i.points.auto/zoom_pnt.c ___________________________________________________________________ Name: svn:eol-style + native From neteler at grass.itc.it Sun Oct 21 10:42:42 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Thu Oct 25 01:43:48 2007 Subject: [grass-addons] r1153 - in trunk/grassaddons: . i.homography Message-ID: <200710210842.l9L8gg4b031483@grass.itc.it> Author: neteler Date: 2007-10-21 10:42:42 +0200 (Sun, 21 Oct 2007) New Revision: 1153 Added: trunk/grassaddons/i.homography/ trunk/grassaddons/i.homography/Makefile trunk/grassaddons/i.homography/TODO trunk/grassaddons/i.homography/func.h trunk/grassaddons/i.homography/global.h trunk/grassaddons/i.homography/lu.c trunk/grassaddons/i.homography/main.c trunk/grassaddons/i.homography/matrix.c trunk/grassaddons/i.homography/open.c trunk/grassaddons/i.homography/pi.c Log: image rectification based on homography Added: trunk/grassaddons/i.homography/Makefile =================================================================== --- trunk/grassaddons/i.homography/Makefile (rev 0) +++ trunk/grassaddons/i.homography/Makefile 2007-10-21 08:42:42 UTC (rev 1153) @@ -0,0 +1,10 @@ +MODULE_TOPDIR = ../.. + +PGM = i.homography + +LIBES = $(IMAGERYLIB) $(GPROJLIB) $(GISLIB) $(VASKLIB) $(CURSES) $(GMATHLIB) +DEPENDENCIES= $(IMAGERYDEP) $(GPROJDEP) $(GISDEP) $(VASKDEP) $(GMATHDEP) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd Added: trunk/grassaddons/i.homography/TODO =================================================================== --- trunk/grassaddons/i.homography/TODO (rev 0) +++ trunk/grassaddons/i.homography/TODO 2007-10-21 08:42:42 UTC (rev 1153) @@ -0,0 +1,12 @@ +Compile with + make MODULE_TOPDIR=$HOME/grass63/ + +TODO + +Code based on GRASS 5. To be updated to GRASS 6. + +The brent() function in this modules must +be changed to grass63/lib/gmath/brent.c +due to copyright problems. + + Added: trunk/grassaddons/i.homography/func.h =================================================================== --- trunk/grassaddons/i.homography/func.h (rev 0) +++ trunk/grassaddons/i.homography/func.h 2007-10-21 08:42:42 UTC (rev 1153) @@ -0,0 +1,191 @@ +/* +bootstrap.c +*/ + +int Bootsamples(); + +/* +random.c +*/ + +double ran1(); +double gasdev(); + +/* +blob.c +*/ + +void extract_sites_from_blob(); +void find_blob(); + +/* +tree.c +*/ + +int build_maximal_tree(); +void write_tree(); +int read_tree(); +int godown(); +void write_Btree(); +int read_Btree(); +double evaluateB(); +int evaluateB_multiclass(); +void classify_image_TREE(); + +/* +training.c +*/ + +void build_training(); + +/* +percent.c +*/ + +void percent (); + +/* +open.c +*/ + +int open_new_CELL(); +int open_new_DCELL(); + +/* +pca.c +*/ + +void alloc_pca(); +void write_pca(); +void read_pca(); + +/* +dist.c +*/ + +double squared_distance(); +double euclidean_distance(); +double scalar_product(); +double euclidean_norm(); + +/* +getline.c +*/ + +char *GetLine(); + +/* +pi.c +*/ + +void linear_solve(); + +/* +read_list.c +*/ + +void read_list_of_type_1_and_load_raster_maps(); +void read_list_of_type_2(); +void read_list_of_type_2_and_load_raster_maps(); +int read_list_of_sites(); + +/* +filter.c +*/ + +void write_filter(); +void read_filter(); + +/* +test.c +*/ + +void ksone_normal(); +void kstwo(); +double normal_distribution(); +double cumulative_normal_distribution(); + +/* +nn.c +*/ + +void classify_image_NN(); +void write_nn(); +void read_nn(); +void compute_NN_from_training(); +void read_matrix(); + +/* +integration.c +*/ + +double trapzd(); +double trapzd1(); +double trapzd2(); +double qtrap(); +double qtrap1(); +double qtrap2(); + +/* +gm.c +*/ + +void compute_gm(); +void write_gm(); +void read_gm(); +double ComputeDelta(); +void classify_image_GM(); + +/* +sort.c +*/ + +void shell(); +void indexx_1(); +void indexx(); + +/* +eigen.c +*/ + +void tred2(); +int tqli(); +int eigen_of_double_matrix(); +void eigsrt(); + +/* +matrix.c +*/ + +void product_double_matrix_double_matrix(); +void product_double_matrix_double_vector(); +void product_double_vector_double_matrix(); +void transpose_double_matrix(); +void double_matrix_to_vector(); +void extract_portion_of_double_matrix(); +void transpose_double_matrix_rectangular(); + +/* +lu.c +*/ + +void ludcmp(); +void lubksb(); +void inverse_of_double_matrix(); +double determinant_of_double_matrix(); + +/* +stats.c +*/ + +double mean_of_double_array(); +double var_of_double_array(); +double sd_of_double_array(); +double var_of_double_array_given_mean(); +double sd_of_double_array_given_mean(); +void mean_and_var_of_double_matrix_by_row(); +void mean_and_sd_of_double_matrix_by_row(); +void mean_and_var_of_double_matrix_by_col(); +void mean_and_sd_of_double_matrix_by_col(); +double auto_covariance_of_2_double_array(); +void covariance_of_double_matrix(); Added: trunk/grassaddons/i.homography/global.h =================================================================== --- trunk/grassaddons/i.homography/global.h (rev 0) +++ trunk/grassaddons/i.homography/global.h 2007-10-21 08:42:42 UTC (rev 1153) @@ -0,0 +1,212 @@ +/***** + list of RASTERLISTTYPE1 + + name1 class1 + name2 class2 + ... ... +*****/ + +/***** + list of RASTERLISTTYPE2 + + name1 additional_name1 moments1 + name2 additional_name2 moments2 + ... ... ... +*****/ + +/***** + classification CLASSIFICATION1 + + given a list RASTERLISTTYPE1, optionally build a filter, + build the pca model, transform data in pc space, + compute a gaussian mixture +*****/ + +/***** + classification CLASSIFICATION2 + + given a list RASTERLISTTYPE2, use a list of sites as training, + build a window round each site, using the moments compute mean + or mean and var of the value of the raster maps within the + window to form predictor variables, compute a gaussian mixture + or a nearest neighbour model +*****/ + + +#include "gis.h" +#include "func.h" +#include "site.h" + +#define PIG 3.141593 + +#define TRUE 1 +#define FALSE 0 + +#define GaussianMixture 1 +#define NearestNeighbour 2 + +#define TREE 1 +#define BOOSTING 2 +#define BAGGING 3 + +typedef struct +/*manegement of list of type 1*/ +{ + char **mapnames; /*array of raster map names*/ + char **mapclass; /*class of each raster map*/ + int nsamples; /*number of raster map*/ + int rows; /*rows number of each raster map*/ + int cols; /*cols number of each raster map*/ + double **samples; /*for each map, the values of the map stored in an array + of length rows x cols*/ +} Maps; + +typedef struct +/*manegement of list of type 2*/ +{ + char **mapnames; /*array of raster map names*/ + char **varnames; /*additional name for each raster map*/ + int nvar; /*number of raster maps*/ + int rows; /*rows number of each raster map*/ + int cols; /*cols number of each raster map*/ + int *moments; /*for each map, the number of moments of the distribution + to be considered for the classification: + 1 = mean + 2 = mean and var*/ + double ***mapvalues; /*for each map, the values of the map stored in a matrix + of dimension rows x cols*/ +} Variables; + +typedef struct +/*manegement of lists of site files*/ +{ + char *name; /*name of site file*/ + Site **sites; /*sites contained within the site file*/ + int nsites; /*number of sites*/ +} ListSite; + + +typedef struct +/*filter structure, usually considered as average of matricial examples + (usually small raster maps)*/ +{ + int rows; /*rows number of the filter*/ + int cols; /*cols number of the filter*/ + double **values; /*values of the filter, stored in a matrix + of dimension rows x cols*/ +} Filter; + +typedef struct +/*principal components structure. Examples are in matricial form + (usually small raster maps) but matricial examples are here + considered as array of length rows x cols*/ +{ + int rows; /*rows number of the raster maps used to build the PC model*/ + int cols; /*cols number of the raster maps used to build the PC model*/ + double *mean; /*the mean value of the examples, stored in an + array of dimension rows x cols*/ + double *sd; /*the standard deviation of the examples, stored in an + array of dimension rows x cols*/ + double **covar; /*covariance matrix of the examples, stored in a + matrix of dimension (rows x cols)^2*/ + double *eigval; /*eigenvalues of the covariance matrix*/ + double **eigmat; /*eigenvectors matrix of the covariance matrix. + Each column is the eigenvector corresponding to + an eigenvalues*/ + int correlation; /*boolean: + 0 = covariance matrix computed + 1 = correlation matrix computed*/ + int standardize; /*boolean: + 0 = examples are not standardized + 1 = examples are standardized: E <- (E-mean(E))/sd(E)*/ +} Pca; + +typedef struct +/*gaussian mixture models structure*/ +{ + int nclasses; /*number of classes*/ + char **classes; /*array of the class names*/ + int *nsamples; /*number of examples contained in each class*/ + int nvars; /*number of predictor variables*/ + double **mean; /*for each class, the mean value of the examples stored + in an array of length nvars*/ + double ***covar; /*for each class, the covariance matrix of the esamples + stored in a matrix of dimension nvars x nvars*/ + double ***inv_covar; /*for each class, the inverse of the covariance matrix + stored in a matrix of dimension nvars x nvars*/ + double *priors; /* prior probabilities of each class*/ + double *det; /*for each class, the determinant of the inverse of the + covariance matrix*/ +} NormalModel; + +typedef struct +/*Non-intuitive structure: is almost always derived from + the ListSite and Variables structures*/ +{ + int nclasses; /*number of classes*/ + int *number_of_data_for_class; /*number of elements of each class*/ + int rows; /*rows number to be considered for building the window + around each site*/ + int cols; /*cols number to be considered for building the window + around each site*/ + int nsites; /*number of sites*/ + double ****trdata; /*for each raster map, for each class, + for each sample within the class, + the values of the raster map contained within the + window and stored in an array of length rows*cols + = window size */ +} Training; + +typedef struct +/*nearest neighbour structure*/ +{ + int nsites; /*number of examples*/ + int nvar; /*number of predictor variables*/ + double **values; /* for each example, the values of the predictors*/ + char **classes; /* array of the classes of each example*/ + int *num_classes; /*array of the classes of each example + in integer format (for compatibility)*/ +} NN; + +typedef struct +{ + double **data; + char **classes; + int npoints; + int nvar; + + int nclasses; + + + int *npoints_for_class; + double *priors; + char *class; + + + int terminal; + + int left; + int right; + int var; + double value; +} Node; + +typedef struct +/*indeces of a matrix (row,col) and blob thay belog to (number)*/ +{ + int row; /*row index of a point belonging to a blob*/ + int col; /*row index of a point belonging to a blob*/ + int number /* blob number the point belong to*/; +} Blob; + +typedef struct +/*geographical coordinates of the center of a blob and minimum + value of the blob itself*/ +{ + double east; /*east value of the center*/ + double north; /*north value of the center*/ + double min; /*minimum value of the blob*/ + int n; /*number of points whitin the blob*/ +} BlobSites; + + Added: trunk/grassaddons/i.homography/lu.c =================================================================== --- trunk/grassaddons/i.homography/lu.c (rev 0) +++ trunk/grassaddons/i.homography/lu.c 2007-10-21 08:42:42 UTC (rev 1153) @@ -0,0 +1,192 @@ +/* + Some of the following routines are borrowed from "Numerical Recipes in C" + other are written and tested by Stefano Merler + + for + + LU matrix decomposition, linear equation solution (Ax=b), inversion + of matrices and deteminant computation +*/ + +#include +#include +#include + + +#define CTINY 1.0e-32 + +void ludcmp(a,n,indx,d) + /* + LU decomposition of n x n matrix a. + */ + int n,*indx; + double **a,*d; +{ + int i,imax=0,j,k; + double big,dum,sum,temp; + double *vv; + + vv=(double *)calloc(n,sizeof(double)); + *d=1.0; + for (i=0;ibig) big=temp; + if (big==0.0) + { fprintf(stderr,"Singular matrix in routine ludcmp\n"); + exit(1); + } + vv[i]=1.0/big; + } + for (j=0;j=big) + { + big=dum; + imax=i; + } + } + if (j!=imax) + { + for (k=0;k=0) + for (j=ii;j<=i-1;j++) sum -=a[i][j]*b[j]; + else if (sum!=0.0) ii=i; + b[i]=sum; + } + for (i=n-1;i>=0;i--) + { + sum=b[i]; + for (j=i+1;j=v2). Read the file COPYING that comes with GRASS +* for details. +* +*****************************************************************************/ +#include +#include +#include +#include +#include +#include "gis.h" +#include "global.h" +#include "imagery.h" +#include "gprojects.h" + +/* #define DEBUG 1 */ + +#define ITMAX 20000 +#define CGOLD 0.3819660 +#define ZEPS 1.0e-10 + +#define SIGN(a,b) ((b) > 0.0 ? fabs(a) : -fabs(a)) +#define SHFT(a,b,c,d) (a)=(b); (b)=(c); (c)=(d); + +void coords(); +void show_env(); +void select_target_env(); +void select_current_env(); +void proj(); +void georef_window (); +void points_to_line (double e1, double n1, double e2, double n2, double *t, double *u); + +static int which_env = -1; + +static double offsetx /*= 1660000.0*/; +static double offsety/* = 5100000.0*/; + +FILE *file_test; + + + + +int main(int argc, char *argv[]) +{ + struct Option *opt1; + struct Option *opt2; + struct Option *opt3; + struct Option *opt4; + struct Option *opt5; + char risp[100]; + char *input_name; + char *output_name; + char *output_location; + char *output_mapset; + char *input_group; + char *data_location; + int i,j,k; + int permissions; + char *setname; + char tempbuf[1000]; + double PROJECTIVE[9]; + double I_PROJECTIVE[9]; + char *input_mapset; + char *input_location; + struct Cell_head input_cellhd; + struct Cell_head output_cellhd; + int outfd,infd; + DCELL *output_cell; + CELL *rowbuf; + int **matrix; + double e,n; + int x,y; + double translated_n; + double translated_w; + struct Control_Points cp; + int r,c,rp; + double **A; + double *X,*Y; + double newE,newN; + double error; + double t1, u1,t2,u2; + double err_test_RMS=0; + double x1,y1,x2,y2,homography_x2,homography_y2, diff_x2,diff_y2; + double p_optimal; + double parziale; + int stampa=0; + + double estimate (double parameter) { + + j=0; + for(i=0;ikey = "input"; + opt1->type = TYPE_STRING; + opt1->required = YES; + opt1->gisprompt = "old,cell,raster" ; + opt1->description = "input raster map to be rectified"; + + opt2 = G_define_option(); + opt2->key = "output"; + opt2->type = TYPE_STRING; + opt2->required = YES; + opt2->gisprompt = "new,cell,raster" ; + opt2->description = "output raster map of the rectified map"; + + opt3 = G_define_option(); + opt3->key = "location"; + opt3->type = TYPE_STRING; + opt3->required = YES; + opt3->description = "location of the rectified raster map"; + + opt4 = G_define_option(); + opt4->key = "mapset"; + opt4->type = TYPE_STRING; + opt4->required = YES; + opt4->description = "mapset of the rectified raster map"; + + opt5 = G_define_option() ; + opt5->key = "group"; + opt5->type = TYPE_STRING; + opt5->required = YES; + opt5->description= "input group containing points for homography computation"; + + + /***** Start of main *****/ + + if (G_parser(argc, argv)) + exit(-1); + + input_name = opt1->answer; + output_name = opt2->answer; + output_location = opt3->answer; + output_mapset = opt4->answer; + input_group = opt5->answer; + + input_mapset=G_find_cell2 (input_name, ""); + setname = output_location ? output_mapset : G_store(G_mapset()); + input_location=G_location(); + data_location=G_gisdbase(); + + /*sprintf(tempbuf,"cp %s/%s/%s/colr/%s %s/%s/%s/colr/%s",data_location, + input_location, input_mapset,input_name,data_location, + output_location,output_mapset,output_name); */ + G_debug(3,"%s/%s/%s/cell/%s %s/%s/%s/cell/%s",data_location, + input_location, input_mapset,input_name,data_location, + output_location,output_mapset,output_name); + + /* READ POINTS*/ + if(!I_find_group(input_group)){ + fprintf(stderr,"Group %s not in current mapset\n",input_group); + exit(0); + } + + I_get_control_points(input_group,&cp); + +#ifdef DEBUG + for(i=0;i yes, everything else --> no \n"); + scanf("%1c",risp); + + if (risp[0] == 'y') + { + file_test=fopen ("TEST_SET","r"); + if(file_test==NULL) G_fatal_error("File 'TEST_SET' not found."); + } + while (risp[0]!='\n') scanf("%1c",risp); + + + + /*COMPUTE PROJECTIVE PARAMETERS*/ + + if (cp.count == 0) + exit(-1); + +/*offsetx = cp.e2[0] - 10000; + offsety = cp.n2[0] - 10000;*/ + + i=0; + while(cp.status[i]!=1 && i < cp.count) + i++; + if(i >=cp.count && cp.status[i]!=1) + i=0; + offsetx = cp.e2[i] - cp.e1[i]; + offsety = cp.n2[i] - cp.n1[i]; + + r=0; + for(i=0;i=0) + fprintf (stdout,"Computing...\n"); + + /*OPEN RASTER FILE IN THE TARGET LOCATION*/ + G_get_window (&output_cellhd); + G_set_window (&output_cellhd); + outfd = open_new_DCELL(output_name); + if (outfd < 0) + return 0; + output_cell=G_allocate_d_raster_buf(); + + + /*COMPUTE RECTIFICATION*/ + translated_n = output_cellhd.north - offsety; + translated_w = output_cellhd.west - offsetx; + for(i=0;i=0)&&(x=0)&&(ywest, w1->north, &e, &n, param); + n += offsety; + e += offsetx; + w2->north = w2->south = n; + w2->west = w2->east = e; + + proj (w1->east, w1->north, &e, &n, param); + n += offsety; + e += offsetx; + if (n > w2->north) w2->north = n; + if (n < w2->south) w2->south = n; + if (e > w2->east ) w2->east = e; + if (e < w2->west ) w2->west = e; + + proj (w1->west, w1->south, &e, &n, param); + n += offsety; + e += offsetx; + if (n > w2->north) w2->north = n; + if (n < w2->south) w2->south = n; + if (e > w2->east ) w2->east = e; + if (e < w2->west ) w2->west = e; + + proj (w1->east, w1->south, &e, &n, param); + n += offsety; + e += offsetx; + if (n > w2->north) w2->north = n; + if (n < w2->south) w2->south = n; + if (e > w2->east ) w2->east = e; + if (e < w2->west ) w2->west = e; + + w2->ns_res = (w2->north - w2->south) / w1->rows; + w2->ew_res = (w2->east - w2->west ) / w1->cols; + w2->cols=w1->cols; + w2->rows=w1->rows; +} + +/*SELECT CURRENT ENV*/ +void select_current_env() +{ + if (which_env < 0) + { + G__create_alt_env(); + which_env = 0; + } + if (which_env != 0) + { + G__switch_env(); + which_env = 0; + } +} + +/*SELECT TARGET ENV*/ +void select_target_env() +{ + if (which_env < 0) + { + G__create_alt_env(); + which_env = 1; + } + if (which_env != 1) + { + G__switch_env(); + which_env = 1; + } +} +/*PRINT ENV*/ +void show_env() +{ + fprintf (stdout,"env(%d) switch to LOCATION %s, MAPSET %s\n", which_env, + G__getenv("LOCATION_NAME")==NULL ? "?" : G__getenv("LOCATION_NAME"), + G__getenv("MAPSET")==NULL ? "?" : G__getenv("MAPSET")); + sleep(2); +} + +void coords(e,n,x,y,win) + double e,n; + int *x,*y; + struct Cell_head *win; +{ + *y=(int)(e - win->west) / win->ew_res; + *x=(int)(win->north - n) / win->ns_res; +} + +void points_to_line (double e1, double n1, double e2, double n2, double *t, double *u) +{ + double a,b,c; + a=(n1 - n2); + b= (e2 - e1); + c= (n2*e1 - n1*e2); + *t= a/c; + *u=b/c; + /* printf( " \n a %f b %f c %f t %f u %f \n\n",a,b,c,*t,*u); */ +} Added: trunk/grassaddons/i.homography/matrix.c =================================================================== --- trunk/grassaddons/i.homography/matrix.c (rev 0) +++ trunk/grassaddons/i.homography/matrix.c 2007-10-21 08:42:42 UTC (rev 1153) @@ -0,0 +1,162 @@ +/* + The following routines are written and tested by Stefano Merler + + for + + management of matrices and arrays + + Supported function for + - product matrix matrix or vector matrix + - transpose matrix + - conversion of matrix to array + - extraction of portion of matrix +*/ + +#include + +void product_double_matrix_double_matrix(x,y,r,cr,c,out) + /* + product of matrices x * y, + r = rows of x + cr= cols of x = rows of y + c = cols of y + out is the r x c matrix. + */ + double **x, **y, **out; + int r,cr,c; +{ + int i,j,h; + + for(i=0; i Author: landa Date: 2007-10-22 11:12:22 +0200 (Mon, 22 Oct 2007) New Revision: 1154 Modified: trunk/grassaddons/gui/display_driver/driver.cpp trunk/grassaddons/gui/display_driver/driver.h trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/render.py Log: Digitization tool: fix query tool Mapdisplay: zoom fix (calculate center coordinates) Modified: trunk/grassaddons/gui/display_driver/driver.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-21 08:42:42 UTC (rev 1153) +++ trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-22 09:12:22 UTC (rev 1154) @@ -565,6 +565,20 @@ region.map_width = map_width; region.map_height = map_height; +#ifdef DEBUG: + std::cerr << "region: n=" << north + << "; s=" << south + << "; e=" << east + << "; w=" << west + << "; ns_res=" << ns_res + << "; ew_res=" << ew_res + << "; center_easting=" << center_easting + << "; center_northing=" << center_northing + << "; map_width=" << map_width + << "; map_height=" << map_height + << std::endl; +#endif + // calculate real region region.map_res = (region.ew_res > region.ns_res) ? region.ew_res : region.ns_res; @@ -916,13 +930,14 @@ \brief Get PseudoDC vertex id of selected line \param[in] x,y coordinates of click + \param[in] thresh threshold value \return id of center, left and right vertex \return 0 no line found \return -1 on error */ -std::vector DisplayDriver::GetSelectedVertex(double x, double y) +std::vector DisplayDriver::GetSelectedVertex(double x, double y, double thresh) { int startId; int line, type; @@ -940,8 +955,6 @@ startId = 1; line = selected[0]; - std::cerr << line << std::endl; - type = Vect_read_line (mapInfo, points, cats, line); // find the closest vertex (x, y) @@ -960,7 +973,10 @@ } } } - + + if (minDist > thresh) + return returnId; + // desc = &(ids[line]); // translate id Modified: trunk/grassaddons/gui/display_driver/driver.h =================================================================== --- trunk/grassaddons/gui/display_driver/driver.h 2007-10-21 08:42:42 UTC (rev 1153) +++ trunk/grassaddons/gui/display_driver/driver.h 2007-10-22 09:12:22 UTC (rev 1154) @@ -159,7 +159,7 @@ std::vector GetSelected(bool grassId); int SetSelected(std::vector id); - std::vector GetSelectedVertex(double x, double y); + std::vector GetSelectedVertex(double x, double y, double thresh); /* general */ void CloseMap(); Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-21 08:42:42 UTC (rev 1153) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-22 09:12:22 UTC (rev 1154) @@ -99,9 +99,9 @@ self.settings["categoryMode"] = "Next to use" # query tool - self.settings["query"] = "length" - self.settings["queryLength"] = ("shorter than", 0) - self.settings["queryDangle"] = (0,) + self.settings["query"] = ("length", False) # name, select by box + self.settings["queryLength"] = ("shorter than", 0) # gt or lt, threshold + self.settings["queryDangle"] = ("shorter than", 0) else: self.settings = settings @@ -382,7 +382,7 @@ # reload map (needed for v.edit) self.driver.ReloadMap() - + return True def CopyCats(self, cats, ids): @@ -749,7 +749,7 @@ x, y = coords - id = self.__display.GetSelectedVertex(x, y) + id = self.__display.GetSelectedVertex(x, y, self.GetThreshold()) Debug.msg(4, "CDisplayDriver.GetSelectedVertex(): id=%s" % \ (",".join(["%d" % v for v in id]))) @@ -1074,6 +1074,13 @@ sizer = wx.StaticBoxSizer(box, wx.VERTICAL) LocUnits = self.parent.MapWindow.Map.ProjInfo()['units'] + + self.queryBox = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=_("Select by box")) + self.queryBox.SetValue(settings["query"][1]) + + sizer.Add(item=self.queryBox, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) + sizer.Add((0, 5)) + # # length # @@ -1103,23 +1110,28 @@ self.queryDangle = wx.RadioButton(parent=panel, id=wx.ID_ANY, label=_("dangle")) self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) sizer.Add(item=self.queryDangle, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) - flexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5) + flexSizer = wx.FlexGridSizer (cols=4, hgap=5, vgap=5) flexSizer.AddGrowableCol(0) - txt = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select dangles shorter than")) + txt = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Select dangles")) + self.queryDangleSL = wx.Choice (parent=panel, id=wx.ID_ANY, + choices = [_("shorter than"), _("longer than")]) + self.queryDangleSL.SetStringSelection(settings["queryDangle"][0]) self.queryDangleValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(100, -1), initial=1, min=0, max=1e6) - self.queryDangleValue.SetValue(settings["queryDangle"][0]) + self.queryDangleValue.SetValue(settings["queryDangle"][1]) units = wx.StaticText(parent=panel, id=wx.ID_ANY, label="%s" % LocUnits) flexSizer.Add(txt, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(self.queryDangleSL, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(self.queryDangleValue, proportion=0, flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(units, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL) sizer.Add(item=flexSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=1) - if settings["query"] == "length": + if settings["query"][0] == "length": self.queryLength.SetValue(True) else: self.queryDangle.SetValue(True) + # enable & disable items self.OnChangeQuery(None) @@ -1212,11 +1224,13 @@ # length self.queryLengthSL.Enable(True) self.queryLengthValue.Enable(True) + self.queryDangleSL.Enable(False) self.queryDangleValue.Enable(False) else: # dangle self.queryLengthSL.Enable(False) self.queryLengthValue.Enable(False) + self.queryDangleSL.Enable(True) self.queryDangleValue.Enable(True) def OnOK(self, event): @@ -1269,12 +1283,13 @@ # query tool if self.queryLength.GetValue(): - self.parent.digit.settings["query"] = "length" + self.parent.digit.settings["query"] = ("length", self.queryBox.IsChecked()) else: - self.parent.digit.settings["query"] = "dangle" + self.parent.digit.settings["query"] = ("dangle", self.queryBox.IsChecked()) self.parent.digit.settings["queryLength"] = (self.queryLengthSL.GetStringSelection(), int(self.queryLengthValue.GetValue())) - self.parent.digit.settings["queryDangle"] = (int(self.queryDangleValue.GetValue()),) + self.parent.digit.settings["queryDangle"] = (self.queryDangleSL.GetStringSelection(), + int(self.queryDangleValue.GetValue()),) # update driver settings self.parent.digit.driver.UpdateSettings() Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-21 08:42:42 UTC (rev 1153) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-22 09:12:22 UTC (rev 1154) @@ -228,7 +228,7 @@ line = stream.readline() if not line: break - line = line.replace('\n', '') + line = line.replace('\n', '').strip() lineList.append(line) return lineList Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-21 08:42:42 UTC (rev 1153) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-22 09:12:22 UTC (rev 1154) @@ -218,9 +218,10 @@ self.pdcVector = None # pseudoDC for temporal objects (select box, measurement tool, etc.) self.pdcTmp = wx.PseudoDC() + self.redrawAll = True # redraw all pdc layers, Tmp layer is redrawn always (speed issue) # will store an off screen empty bitmap for saving to file - self._Buffer = '' + self._buffer = '' self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None) @@ -376,7 +377,7 @@ Draw PseudoDC to buffered paint DC """ - dc = wx.BufferedPaintDC(self, self._Buffer) + dc = wx.BufferedPaintDC(self, self._buffer) # we need to clear the dc BEFORE calling PrepareDC bg = wx.Brush(self.GetBackgroundColour()) @@ -390,16 +391,35 @@ # and update region rgn = self.GetUpdateRegion().GetBox() dc.SetClippingRect(rgn) - # draw to the dc using the calculated clipping rect - self.pdc.DrawToDCClipped(dc, rgn) - # draw vector map layer - if self.pdcVector: - self.pdcVector.DrawToDCClipped(dc, rgn) + if self.redrawAll: # redraw pdc and pdcVector + # draw to the dc using the calculated clipping rect + self.pdc.DrawToDCClipped(dc, rgn) + # draw vector map layer + if self.pdcVector: + self.pdcVector.DrawToDCClipped(dc, rgn) + + self._bufferLast = None + else: # do not redraw pdc and pdcVector + if self._bufferLast is None: + # draw to the dc + self.pdc.DrawToDC(dc) + + if self.pdcVector: + self.pdcVector.DrawToDC(dc) + + # store buffered image + # self._bufferLast = wx.BitmapFromImage(self._buffer.ConvertToImage()) + self._bufferLast = dc.GetAsBitmap((0, 0, self.Map.width, self.Map.height)) + + pdcLast = wx.PseudoDC() + pdcLast.DrawBitmap(bmp=self._bufferLast, x=0, y=0) + pdcLast.DrawToDC(dc) + # draw temporal object on the foreground self.pdcTmp.DrawToDCClipped(dc, rgn) - + def OnSize(self, event): """ Scale map image so that it is @@ -414,7 +434,7 @@ # Make new off screen bitmap: this bitmap will always have the # current drawing in it, so it can be used to save the image to # a file, or whatever. - self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height) + self._buffer = wx.EmptyBitmap(self.Map.width, self.Map.height) # get the image to be rendered self.img = self.GetImage() @@ -446,11 +466,11 @@ This draws the psuedo DC to a buffer that can be saved to a file. """ - dc = wx.BufferedPaintDC(self, self._Buffer) + dc = wx.BufferedPaintDC(self, self._buffer) self.pdc.DrawToDC(dc) if self.pdcVector: self.pdcVector.DrawToDC(dc) - self._Buffer.SaveFile(FileName, FileType) + self._buffer.SaveFile(FileName, FileType) def GetOverlay(self): """ @@ -612,8 +632,8 @@ # drag not only background image # FIXME: when mapdisplay window is hiden by other window, - # self._Buffer contains grey holes - self.dragimg = wx.DragImage(self._Buffer) + # self._buffer contains grey holes + self.dragimg = wx.DragImage(self._buffer) self.dragimg.BeginDrag((0, 0), self) self.dragimg.GetImageRect(moveto) self.dragimg.Move(moveto) @@ -649,13 +669,14 @@ def MouseDraw(self, pdc=None): """ - Mouse zoom rectangles and lines + Mouse rectangles and lines """ if not pdc: return Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s" % \ (self.mouse['use'], self.mouse['box'])) + if self.mouse['box'] == "box": boxid = wx.ID_NEW mousecoords = [self.mouse['begin'][0], self.mouse['begin'][1], \ @@ -814,7 +835,9 @@ self.ClearLines(pdc=self.pdcTmp) else: self.mouse['begin'] = self.mouse['end'] - + elif self.mouse['use'] == 'zoom': + print "#", self.mouse['begin'] + self.redrawAll = False elif self.mouse["use"] == "pointer" and self.parent.digittoolbar: # digitization digitToolbar = self.parent.digittoolbar @@ -998,6 +1021,9 @@ self.mouse['end'] = event.GetPositionTuple()[:] if self.mouse['use'] in ["zoom", "pan"]: + if self.mouse['use'] == 'zoom': + print "#", self.mouse['end'] + self.redrawAll = True # set region in zoom or pan self.Zoom(self.mouse['begin'], self.mouse['end'], self.zoomtype) @@ -1079,12 +1105,9 @@ if nselected > 0: # highlight selected features - self.UpdateMap(render=False) + # self.UpdateMap(render=False) if digitToolbar.action in ["moveLine", "moveVertex", "copyCats", "editLine"]: - # -> move line || move vertex - self.UpdateMap(render=False) - # get pseudoDC id of objects which should be redrawn if digitToolbar.action == "moveLine": # -> move line @@ -1093,6 +1116,8 @@ elif digitToolbar.action == "moveVertex": # -> move vertex self.moveIds = digitClass.driver.GetSelectedVertex(pos1) + if len(self.moveIds) == 0: # no vertex found + digitClass.driver.SetSelected([]) elif digitToolbar.action == "editLine": # -> edit line @@ -1106,8 +1131,11 @@ # choose first or last node of line self.moveIds.reverse() - else: + # -> move line || move vertex + self.UpdateMap(render=False) + else: # no vector object found self.UpdateMap(render=False, renderVector=False) + elif digitToolbar.action in ["splitLine", "addVertex", "removeVertex"]: pointOnLine = digitClass.driver.SelectLineByPoint(pos1, type="line") @@ -1330,7 +1358,7 @@ elif digitToolbar.action == "moveVertex": # move vertex digitClass.MoveSelectedVertex(pFrom, - move) + move) else: # edit line pass @@ -1503,7 +1531,7 @@ x, y = self.pdcVector.GetIdBounds(self.moveIds[1])[0:2] self.pdcVector.RemoveId(self.moveIds[1]+1) self.polycoords.append((x, y)) - self.polycoords.append(self.mouse['end']) + self.polycoords.append(self.pdcVector.GetIdBounds(self.moveIds[0])[0:2]) if self.moveIds[2] > 0: # next vertex x, y = self.pdcVector.GetIdBounds(self.moveIds[2])[0:2] self.pdcVector.RemoveId(self.moveIds[2]-1) @@ -1630,6 +1658,8 @@ x2, y2 = end newreg = {} + print "#", begin, end, self.Pixel2Cell(begin), self.Pixel2Cell(end) + # threshold - too small squares do not make sense # can only zoom to windows of > 10x10 screen pixels if x2 > 10 and y2 > 10 and zoomtype != 0: @@ -1663,8 +1693,10 @@ self.Map.region['s'] = newreg['s'] self.Map.region['e'] = newreg['e'] self.Map.region['w'] = newreg['w'] - self.Map.region['center_easting'] = newreg['w'] + (newreg['e'] - newreg['w']) / 2 - self.Map.region['center_northing'] = newreg['s'] + (newreg['n'] - newreg['s']) / 2 + self.Map.region['center_easting'] = self.Map.region['w'] + \ + (self.Map.region['e'] - self.Map.region['w']) / 2 + self.Map.region['center_northing'] = self.Map.region['s'] + \ + (self.Map.region['n'] - self.Map.region['s']) / 2 self.ZoomHistory(newreg['n'], newreg['s'], newreg['e'], newreg['w']) @@ -1683,8 +1715,15 @@ self.Map.region['s'] = zoom[1] self.Map.region['e'] = zoom[2] self.Map.region['w'] = zoom[3] + self.Map.region['center_easting'] = self.Map.region['w'] + \ + (self.Map.region['e'] - self.Map.region['w']) / 2 + self.Map.region['center_northing'] = self.Map.region['s'] + \ + (self.Map.region['n'] - self.Map.region['s']) / 2 + self.UpdateMap() + self.parent.StatusbarUpdate() + def ZoomHistory(self, n, s, e, w): """ Manages a list of last 10 zoom extents @@ -1719,37 +1758,33 @@ item = self.tree.GetSelection() try: - layer = self.tree.layers[item].maplayer + layer = self.tree.GetPyData(item)[0]['maplayer'] except: + layer = None + + if layer is None: return - + Debug.msg (3, "BufferedWindow.ZoomToMap(): layer=%s, type=%s" % \ (layer.name, layer.type)) # selected layer must be a valid map if layer.type in ('raster', 'rgb', 'his', 'shaded', 'arrow'): - cmdlist = ["g.region", "-ugp", "rast=%s" % layer.name] + self.Map.region = self.Map.GetRegion(rast="%s" % layer.name) elif layer.type in ('vector', 'thememap', 'themechart'): - cmdlist = ["g.region", "-ugp", "vect=%s" % layer.name] + self.Map.region = self.Map.GetRegion(vect="%s" % layer.name) else: return - # get map extents using g.region and update display - p = gcmd.Command(cmdlist) + self.Map.SetRegion() - if p.returncode == 0: - output = p.module_stdout.read().split('\n') - for line in output: - line = line.strip() - if '=' in line: key,val = line.split('=') - zoomreg[key] = float(val) - self.Map.region['n'] = zoomreg['n'] - self.Map.region['s'] = zoomreg['s'] - self.Map.region['e'] = zoomreg['e'] - self.Map.region['w'] = zoomreg['w'] - self.ZoomHistory(self.Map.region['n'],self.Map.region['s'],self.Map.region['e'],self.Map.region['w']) - self.UpdateMap() + self.ZoomHistory(self.Map.region['n'], self.Map.region['s'], + self.Map.region['e'], self.Map.region['w']) + self.UpdateMap() + + self.parent.StatusbarUpdate() + def ZoomToWind(self, event): """ Set display geometry to match computational @@ -1758,9 +1793,14 @@ self.Map.region = self.Map.GetRegion() self.Map.SetRegion() - self.ZoomHistory(self.Map.region['n'],self.Map.region['s'],self.Map.region['e'],self.Map.region['w']) + + self.ZoomHistory(self.Map.region['n'], self.Map.region['s'], + self.Map.region['e'], self.Map.region['w']) + self.UpdateMap() + self.parent.StatusbarUpdate() + def DisplayToWind(self, event): """ Set computational region (WIND file) to @@ -2294,9 +2334,13 @@ def OnToggleStatus(self, event): """Toggle status text""" self.statusText = event.GetString() + self.StatusbarUpdate() + def StatusbarUpdate(self): + """Update statusbar content""" + if self.statusText == "Coordinates": - self.statusbar.SetStatusText("None,None", 0) + self.statusbar.SetStatusText("", 0) self.showRegion.Hide() elif self.statusText == "Extent": self.statusbar.SetStatusText("%.2f-%.2f,%.2f-%.2f" % Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-10-21 08:42:42 UTC (rev 1153) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-10-22 09:12:22 UTC (rev 1154) @@ -381,11 +381,13 @@ except: return False - def GetRegion(self): + def GetRegion(self, rast=None, vect=None): """ - Returns dictionary with output from g.region -gp + Returns dictionary with output from g.region -ugpc - Example: + Optionaly raster or vector map layer can be given. + + Return e.g.: {"n":"4928010", "s":"4913700", "w":"589980",...} """ @@ -395,10 +397,16 @@ os.unsetenv("GRASS_REGION") # do not update & shell style output - cmdRegion = gcmd.Command(["g.region", "-u", "-g", "-p", "-c"]) + cmdList = ["g.region", "-u", "-g", "-p", "-c"] + if rast: + cmdList.append('rast=%s' % rast) + elif vect: + cmdList.append('vect=%s' % vect) + + cmdRegion = gcmd.Command(cmdList) + for reg in cmdRegion.ReadStdOutput(): - reg = reg.strip() key, val = reg.split("=", 1) try: region[key] = float(val) From landa at grass.itc.it Mon Oct 22 13:06:13 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:48 2007 Subject: [grass-addons] r1155 - trunk/grassaddons/gui/gui_modules Message-ID: <200710221106.l9MB6D6v021049@grass.itc.it> Author: landa Date: 2007-10-22 13:06:08 +0200 (Mon, 22 Oct 2007) New Revision: 1155 Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py Log: Zooming based on center point of display window. Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-22 09:12:22 UTC (rev 1154) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-22 11:06:08 UTC (rev 1155) @@ -450,6 +450,9 @@ # reposition checkbox in statusbar self.parent.StatusbarReposition() + # update statusbar + self.parent.StatusbarUpdate() + def OnIdle(self, event): """ Only re-render a compsite map image from GRASS during @@ -763,6 +766,8 @@ self.Zoom(begin, end, zoomtype) # redraw map self.UpdateMap() + # update statusbar + self.parent.StatusbarUpdate() return # left mouse button pressed @@ -836,7 +841,6 @@ else: self.mouse['begin'] = self.mouse['end'] elif self.mouse['use'] == 'zoom': - print "#", self.mouse['begin'] self.redrawAll = False elif self.mouse["use"] == "pointer" and self.parent.digittoolbar: # digitization @@ -1022,7 +1026,6 @@ if self.mouse['use'] in ["zoom", "pan"]: if self.mouse['use'] == 'zoom': - print "#", self.mouse['end'] self.redrawAll = True # set region in zoom or pan self.Zoom(self.mouse['begin'], self.mouse['end'], self.zoomtype) @@ -1030,6 +1033,9 @@ # redraw map self.UpdateMap(render=True) + # update statusbar + self.parent.StatusbarUpdate() + elif self.mouse["use"] == "query": # querying self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1]) @@ -1658,8 +1664,6 @@ x2, y2 = end newreg = {} - print "#", begin, end, self.Pixel2Cell(begin), self.Pixel2Cell(end) - # threshold - too small squares do not make sense # can only zoom to windows of > 10x10 screen pixels if x2 > 10 and y2 > 10 and zoomtype != 0: @@ -1689,17 +1693,30 @@ # if new region has been calculated, set the values if newreg : - self.Map.region['n'] = newreg['n'] - self.Map.region['s'] = newreg['s'] - self.Map.region['e'] = newreg['e'] - self.Map.region['w'] = newreg['w'] - self.Map.region['center_easting'] = self.Map.region['w'] + \ - (self.Map.region['e'] - self.Map.region['w']) / 2 - self.Map.region['center_northing'] = self.Map.region['s'] + \ - (self.Map.region['n'] - self.Map.region['s']) / 2 + self.Map.region['center_easting'] = newreg['w'] + \ + (newreg['e'] - newreg['w']) / 2 + self.Map.region['center_northing'] = newreg['s'] + \ + (newreg['n'] - newreg['s']) / 2 + self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width + self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height + + # calculete bounding box from center coordinates + if self.Map.region["ewres"] > self.Map.region["nsres"]: + res = self.Map.region["ewres"] + else: + res = self.Map.region["nsres"] - self.ZoomHistory(newreg['n'], newreg['s'], newreg['e'], newreg['w']) + ew = (self.Map.width / 2) * res + ns = (self.Map.height / 2) * res + self.Map.region['n'] = self.Map.region['center_northing'] + ns + self.Map.region['s'] = self.Map.region['center_northing'] - ns + self.Map.region['e'] = self.Map.region['center_easting'] + ew + self.Map.region['w'] = self.Map.region['center_easting'] - ew + + self.ZoomHistory(self.Map.region['n'], self.Map.region['s'], + self.Map.region['e'], self.Map.region['w']) + def ZoomBack(self): """ Zoom to previous extents in zoomhistory list @@ -1709,19 +1726,34 @@ if len(self.zoomhistory) > 1: self.zoomhistory.pop() zoom = self.zoomhistory[len(self.zoomhistory)-1] - + # (n, s, e, w) if zoom: - self.Map.region['n'] = zoom[0] - self.Map.region['s'] = zoom[1] - self.Map.region['e'] = zoom[2] - self.Map.region['w'] = zoom[3] - self.Map.region['center_easting'] = self.Map.region['w'] + \ - (self.Map.region['e'] - self.Map.region['w']) / 2 - self.Map.region['center_northing'] = self.Map.region['s'] + \ - (self.Map.region['n'] - self.Map.region['s']) / 2 + # zoom to selected region + self.Map.region['center_easting'] = zoom[3] + \ + (zoom[2] - zoom[3]) / 2 + self.Map.region['center_northing'] = zoom[1] + \ + (zoom[0] - zoom[1]) / 2 + self.Map.region["ewres"] = (zoom[2] - zoom[3]) / self.Map.width + self.Map.region["nsres"] = (zoom[0] - zoom[1]) / self.Map.height + + # calculete bounding box from center coordinates + if self.Map.region["ewres"] > self.Map.region["nsres"]: + res = self.Map.region["ewres"] + else: + res = self.Map.region["nsres"] + ew = (self.Map.width / 2) * res + ns = (self.Map.height / 2) * res + + self.Map.region['n'] = self.Map.region['center_northing'] + ns + self.Map.region['s'] = self.Map.region['center_northing'] - ns + self.Map.region['e'] = self.Map.region['center_easting'] + ew + self.Map.region['w'] = self.Map.region['center_easting'] - ew + + # update map self.UpdateMap() + # update statusbar self.parent.StatusbarUpdate() def ZoomHistory(self, n, s, e, w): From landa at grass.itc.it Tue Oct 23 10:03:56 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:48 2007 Subject: [grass-addons] r1156 - trunk/grassaddons/gui Message-ID: <200710230803.l9N83uC1000905@grass.itc.it> Author: landa Date: 2007-10-23 10:03:54 +0200 (Tue, 23 Oct 2007) New Revision: 1156 Modified: trunk/grassaddons/gui/wxgui.py Log: Disable xmlproc (not available on Mac OS) Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-22 11:06:08 UTC (rev 1155) +++ trunk/grassaddons/gui/wxgui.py 2007-10-23 08:03:54 UTC (rev 1156) @@ -30,9 +30,10 @@ import types import re # for GRC (workspace file) parsering -from xml.parsers.xmlproc import xmlproc -from xml.parsers.xmlproc import xmlval -from xml.parsers.xmlproc import xmldtd +# xmlproc not available on Mac OS +# from xml.parsers.xmlproc import xmlproc +# from xml.parsers.xmlproc import xmlval +# from xml.parsers.xmlproc import xmldtd import xml.sax import xml.sax.handler HandlerBase=xml.sax.handler.ContentHandler @@ -471,22 +472,22 @@ gisbase = os.getenv("GISBASE") dtdFilename = os.path.join(gisbase, "etc", "wx", "gui_modules", "grass-grc.dtd") - # parse xml agains dtd - dtd = xmldtd.load_dtd(dtdFilename) - parser = xmlproc.XMLProcessor() - parser.set_application(xmlval.ValidatingApp(dtd, parser)) - parser.dtd = dtd - parser.ent = dtd - try: - # TODO: set_error_handler(self,err) - parser.parse_resource(filename) - except: - dlg = wx.MessageDialog(self, _("Unable to open workspace file <%s>. " - "It is not valid GRC XML file.") % filename, - _("Error"), wx.OK | wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False + # validate xml agains dtd + # dtd = xmldtd.load_dtd(dtdFilename) + # parser = xmlproc.XMLProcessor() + # parser.set_application(xmlval.ValidatingApp(dtd, parser)) + # parser.dtd = dtd + # parser.ent = dtd + # try: + # # TODO: set_error_handler(self,err) + # parser.parse_resource(filename) + # except: + # dlg = wx.MessageDialog(self, _("Unable to open workspace file <%s>. " + # "It is not valid GRC XML file.") % filename, + # _("Error"), wx.OK | wx.ICON_ERROR) + # dlg.ShowModal() + # dlg.Destroy() + # return False # delete current layer tree content self.OnWorkspaceNew() From landa at grass.itc.it Tue Oct 23 12:25:51 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:48 2007 Subject: [grass-addons] r1157 - trunk/grassaddons/gui/gui_modules Message-ID: <200710231025.l9NAPpu3002528@grass.itc.it> Author: landa Date: 2007-10-23 12:25:45 +0200 (Tue, 23 Oct 2007) New Revision: 1157 Modified: trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/render.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Basic map scale implemented (TODO: screen resolution must be given by user). Minor bugfixes in digit tool. Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-23 08:03:54 UTC (rev 1156) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-23 10:25:45 UTC (rev 1157) @@ -99,7 +99,7 @@ self.settings["categoryMode"] = "Next to use" # query tool - self.settings["query"] = ("length", False) # name, select by box + self.settings["query"] = ("length", True) # name, select by box self.settings["queryLength"] = ("shorter than", 0) # gt or lt, threshold self.settings["queryDangle"] = ("shorter than", 0) else: @@ -520,14 +520,38 @@ def SelectLinesByQuery(self, pos1, pos2): """Select features by query""" + thresh = self.settings['queryLength'][1] + if self.settings['query'][0] == "length": + if self.settings["queryLength"][0] == "shorter than": + thresh = -1 * thresh + else: + if self.settings["queryDangle"][0] == "shorter than": + thresh = -1 * thresh + w, n = pos1 + e, s = pos2 + + if self.settings['query'][1] == False: # select globaly + vInfo = gcmd.Command(['v.info', + 'map=%s' % self.map, + '-g']) + for item in vInfo.ReadStdOutput(): + if 'north' in item: + n = float(item.split('=')[1]) + elif 'south' in item: + s = float(item.split('=')[1]) + elif 'east' in item: + e = float(item.split('=')[1]) + elif 'west' in item: + w = float(item.split('=')[1]) + vEdit = (['v.edit', '--q', 'map=%s' % self.map, 'tool=select', - 'bbox=%f,%f,%f,%f' % (pos1[0], pos1[1], pos2[0], pos2[1]), - 'query=%s' % self.settings['query'], - 'thresh=%f' % self.settings['queryLength'][1]]) + 'bbox=%f,%f,%f,%f' % (w, n, e, s), + 'query=%s' % self.settings['query'][0], + 'thresh=%f' % thresh]) if self.settings['query'] == "length" and \ self.settings['queryLength'][0] == "longer than": Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-23 08:03:54 UTC (rev 1156) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-23 10:25:45 UTC (rev 1157) @@ -430,6 +430,7 @@ # set size of the input image self.Map.ChangeMapSize(self.GetClientSize()) + self.Map.AlignExtentFromDisplay() # align extent based on center point and display resolution # Make new off screen bitmap: this bitmap will always have the # current drawing in it, so it can be used to save the image to @@ -602,14 +603,7 @@ # update statusbar # self.Map.SetRegion() - if self.parent.statusText == "Extent": - self.parent.statusbar.SetStatusText("%.2f-%.2f,%.2f-%.2f" % - (self.Map.region["w"], self.Map.region["e"], - self.Map.region["s"], self.Map.region["n"]), 1) - elif self.parent.statusText == "Geometry": - self.parent.statusbar.SetStatusText("rows=%d;cols=%d;nsres=%.2f;ewres=%.2f" % - (self.Map.region["rows"], self.Map.region["cols"], - self.Map.region["nsres"], self.Map.region["ewres"]), 1) + self.parent.StatusbarUpdate() return True @@ -1137,8 +1131,8 @@ # choose first or last node of line self.moveIds.reverse() - # -> move line || move vertex - self.UpdateMap(render=False) + # -> move line || move vertex + self.UpdateMap(render=False) else: # no vector object found self.UpdateMap(render=False, renderVector=False) @@ -1693,27 +1687,15 @@ # if new region has been calculated, set the values if newreg : + # calculate new center point and display resolution self.Map.region['center_easting'] = newreg['w'] + \ (newreg['e'] - newreg['w']) / 2 self.Map.region['center_northing'] = newreg['s'] + \ (newreg['n'] - newreg['s']) / 2 self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height - - # calculete bounding box from center coordinates - if self.Map.region["ewres"] > self.Map.region["nsres"]: - res = self.Map.region["ewres"] - else: - res = self.Map.region["nsres"] + self.Map.AlignExtentFromDisplay() - ew = (self.Map.width / 2) * res - ns = (self.Map.height / 2) * res - - self.Map.region['n'] = self.Map.region['center_northing'] + ns - self.Map.region['s'] = self.Map.region['center_northing'] - ns - self.Map.region['e'] = self.Map.region['center_easting'] + ew - self.Map.region['w'] = self.Map.region['center_easting'] - ew - self.ZoomHistory(self.Map.region['n'], self.Map.region['s'], self.Map.region['e'], self.Map.region['w']) @@ -1735,21 +1717,8 @@ (zoom[0] - zoom[1]) / 2 self.Map.region["ewres"] = (zoom[2] - zoom[3]) / self.Map.width self.Map.region["nsres"] = (zoom[0] - zoom[1]) / self.Map.height - - # calculete bounding box from center coordinates - if self.Map.region["ewres"] > self.Map.region["nsres"]: - res = self.Map.region["ewres"] - else: - res = self.Map.region["nsres"] + self.Map.AlignExtentFromDisplay() - ew = (self.Map.width / 2) * res - ns = (self.Map.height / 2) * res - - self.Map.region['n'] = self.Map.region['center_northing'] + ns - self.Map.region['s'] = self.Map.region['center_northing'] - ns - self.Map.region['e'] = self.Map.region['center_easting'] + ew - self.Map.region['w'] = self.Map.region['center_easting'] - ew - # update map self.UpdateMap() @@ -1809,6 +1778,7 @@ return self.Map.SetRegion() + self.Map.AlignExtentFromDisplay() self.ZoomHistory(self.Map.region['n'], self.Map.region['s'], self.Map.region['e'], self.Map.region['w']) @@ -1843,7 +1813,7 @@ # We ONLY want to set extents here. Don't mess with resolution. Leave that # for user to set explicitly with g.region - new = self.Map.alignResolution() + new = self.Map.AlignResolution() cmdRegion = ["g.region", "--o", "n=%f" % new['n'], @@ -1927,7 +1897,7 @@ def SaveRegion(self, wind): """Save region settings""" - new = self.Map.alignResolution() + new = self.Map.AlignResolution() cmdRegion = ["g.region", "-u", @@ -2041,36 +2011,35 @@ self.toggleStatus = wx.Choice(self.statusbar, wx.ID_ANY, choices = ["Coordinates", "Extent", - "Geometry"]) + "Geometry", + "Map scale"]) self.statusText = "Coordinates" self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.toggleStatus) # auto-rendering checkbox - self.autoRender = wx.CheckBox(self.statusbar, wx.ID_ANY, _("Render")) + self.autoRender = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY, + label=_("Render")) self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.autoRender) self.autoRender.SetValue(False) self.autoRender.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering"))) # show region - self.showRegion = wx.CheckBox(self.statusbar, wx.ID_ANY, _("Show")) + self.showRegion = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY, + label=_("Show")) self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.showRegion) self.showRegion.SetValue(False) self.showRegion.Hide() self.showRegion.SetToolTip(wx.ToolTip (_("Show/hide computational " "region extent (set with g.region)"))) + # map scale + self.mapScale = wx.TextCtrl(parent=self.statusbar, id=wx.ID_ANY, + value="", style=wx.TE_PROCESS_ENTER, + size=(150, -1)) + self.mapScale.Hide() + self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.mapScale) + self.Map.SetRegion() # set region - # map_frame_statusbar_fields = [ - # # field 0 -> region - # "Ext:%.2f(W)-%.2f(E),%.2f(N)-%.2f(S); " - # "Res:%.2f(NS),%.2f(EW)" % - # (self.Map.region["w"], self.Map.region["e"], - # self.Map.region["n"], self.Map.region["s"], - # self.Map.region["nsres"], self.Map.region["ewres"]), - # # field 1 -> coordinates - # "%s,%s" % (None, None)] - # for i in range(len(map_frame_statusbar_fields)): - # self.statusbar.SetStatusText(map_frame_statusbar_fields[i], i) - self.statusbar.SetStatusText("None,None", 0) - self.StatusbarReposition() # reposition checkbox + self.StatusbarReposition() # reposition statusbar + # # Init map display # @@ -2082,14 +2051,6 @@ self.MapWindow.SetCursor(self.cursors["default"]) # - # Init zoom history - # - self.MapWindow.ZoomHistory(self.Map.region['n'], - self.Map.region['s'], - self.Map.region['e'], - self.Map.region['w']) - - # # Decoration overlays # self.ovlchk = self.MapWindow.ovlchk @@ -2129,6 +2090,14 @@ # self.digit = Digit(mapwindow=self.MapWindow) + # + # Init zoom history + # + self.MapWindow.ZoomHistory(self.Map.region['n'], + self.Map.region['s'], + self.Map.region['e'], + self.Map.region['w']) + def AddToolbar(self, name): """ Add defined toolbar to the window @@ -2368,36 +2337,112 @@ self.statusText = event.GetString() self.StatusbarUpdate() + def OnChangeMapScale(self, event): + """Map scale changed by user""" + scale = event.GetString() + + try: + if scale[:2] != '1:': + raise ValueError + value = int(scale[2:]) + except ValueError: + self.mapScale.SetValue('1:' + str(int(self.mapScaleValue))) + return + + dEW = value * (self.Map.region['cols'] / self.ppm[0]) + dNS = value * (self.Map.region['rows'] / self.ppm[1]) + self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2 + self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2 + self.Map.region['w'] = self.Map.region['center_easting'] - dEW / 2 + self.Map.region['e'] = self.Map.region['center_easting'] + dEW / 2 + + # add to zoom history + self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'], + self.Map.region['e'], self.Map.region['w']) + + # redraw a map + self.MapWindow.UpdateMap() + def StatusbarUpdate(self): """Update statusbar content""" + self.showRegion.Hide() + self.mapScale.Hide() + self.mapScaleValue = self.ppm = None + if self.statusText == "Coordinates": self.statusbar.SetStatusText("", 0) - self.showRegion.Hide() + elif self.statusText == "Extent": self.statusbar.SetStatusText("%.2f-%.2f,%.2f-%.2f" % (self.Map.region["w"], self.Map.region["e"], - self.Map.region["n"], self.Map.region["s"]), 0) + self.Map.region["s"], self.Map.region["n"]), 0) self.showRegion.Show() + elif self.statusText == "Geometry": self.statusbar.SetStatusText("rows=%d;cols=%d;nsres=%.2f;ewres=%.2f" % (self.Map.region["rows"], self.Map.region["cols"], self.Map.region["nsres"], self.Map.region["ewres"]), 0) - self.showRegion.Hide() + elif self.statusText == "Map scale": + # TODO: need to be fixed... + ### screen X region problem + ### user should specify ppm + dc = wx.ScreenDC() + dpSizePx = wx.DisplaySize() # display size in pixels + dpSizeMM = wx.DisplaySizeMM() # display size in mm (system) + dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches + sysPpi = dc.GetPPI() + comPpi = (dpSizePx[0] / dpSizeIn[0], + dpSizePx[1] / dpSizeIn[1]) + + ppi = comPpi # pixel per inch + self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter + (ppi[1] / 2.54) * 100) + + Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f " + "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \ + (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1], + dpSizeIn[0], dpSizeIn[1], + sysPpi[0], sysPpi[1], comPpi[0], comPpi[1], + self.ppm[0], self.ppm[1])) + + region = self.Map.region + + heightCm = region['rows'] / self.ppm[1] * 100 + widthCm = region['cols'] / self.ppm[0] * 100 + + Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" % + (widthCm, heightCm)) + + xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0]) + yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1]) + scale = (xscale + yscale) / 2 + Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \ + (xscale, yscale, scale)) + + self.statusbar.SetStatusText("") + self.mapScale.SetValue("1:%ld" % scale) + self.mapScaleValue = scale + self.mapScale.Show() + else: self.statusbar.SetStatusText("", 1) def StatusbarReposition(self): """Reposition checkbox in statusbar""" # reposition checkbox - widgets = {0: self.showRegion, - 1: self.toggleStatus, - 2: self.autoRender} - for idx, win in widgets.iteritems(): + widgets = [(0, self.showRegion), + (0, self.mapScale), + (1, self.toggleStatus), + (2, self.autoRender)] + for idx, win in widgets: rect = self.statusbar.GetFieldRect(idx) - if idx == 0: # show region + if idx == 0: # show region / mapscale wWin, hWin = win.GetBestSize() - x, y = rect.x + rect.width - wWin, rect.y-1 + if win == self.showRegion: + x, y = rect.x + rect.width - wWin, rect.y-1 + else: + x, y = rect.x + 3, rect.y-1 w, h = wWin, rect.height+2 else: # choice || auto-rendering x, y = rect.x, rect.y-1 Modified: trunk/grassaddons/gui/gui_modules/render.py =================================================================== --- trunk/grassaddons/gui/gui_modules/render.py 2007-10-23 08:03:54 UTC (rev 1156) +++ trunk/grassaddons/gui/gui_modules/render.py 2007-10-23 10:25:45 UTC (rev 1157) @@ -328,24 +328,20 @@ return self.region - def alignResolution(self): + def AlignResolution(self): """ Sets display extents to even multiple of - current resolution in WIND file from SW corner. + current resolution defined in WIND file from SW corner. This must be done manually as using the -a flag can produce incorrect extents. - - Used for saving current display settings to WIND file """ # new values to use for saving to region file new = {} -# windreg = {} n = s = e = w = 0.0 nwres = ewres = 0.0 # Get current values for region and display -# windreg = self.GetRegion() nsres = self.GetRegion()['nsres'] ewres = self.GetRegion()['ewres'] @@ -363,8 +359,31 @@ new['w'] = ewres * round(w/ewres) new['n'] = new['s'] + (new['rows'] * nsres) new['e'] = new['w'] + (new['cols'] * ewres) + return new + def AlignExtentFromDisplay(self): + """Sets display extents (n,s,e,w) to even multiple of + current display resolution from center point""" + + # calculate new bounding box based on center of display + if self.region["ewres"] > self.region["nsres"]: + res = self.region["ewres"] + else: + res = self.region["nsres"] + + Debug.msg(3, "Map.AlignExtentFromDisplay(): width=%d, height=%d, res=%f, center=%f,%f" % \ + (self.width, self.height, res, self.region['center_easting'], + self.region['center_northing'])) + + ew = (self.width / 2) * res + ns = (self.height / 2) * res + + self.region['n'] = self.region['center_northing'] + ns + self.region['s'] = self.region['center_northing'] - ns + self.region['e'] = self.region['center_easting'] + ew + self.region['w'] = self.region['center_easting'] - ew + def ChangeMapSize(self, (width, height)): """Change size of rendered map. @@ -437,7 +456,7 @@ # adjust region settigns to match monitor self.region = self.__adjustRegion() - # newextents = self.alignResolution() + # newextents = self.AlignResolution() # self.region['n'] = newextents['n'] # self.region['s'] = newextents['s'] # self.region['e'] = newextents['e'] Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-23 08:03:54 UTC (rev 1156) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-23 10:25:45 UTC (rev 1157) @@ -512,7 +512,7 @@ def OnQuery(self, event): """Query selected lines/boundaries""" - Debug.msg(2, "Digittoolbar.OnQuery(): %s" % self.parent.digit.settings["query"]) + Debug.msg(2, "Digittoolbar.OnQuery(): %s" % self.parent.digit.settings["query"][0]) self.action="queryLine" self.parent.MapWindow.mouse['box'] = 'box' From landa at grass.itc.it Wed Oct 24 22:51:27 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Thu Oct 25 01:43:49 2007 Subject: [grass-addons] r1158 - in trunk/grassaddons/gui: display_driver gui_modules Message-ID: <200710242051.l9OKpRhG003368@grass.itc.it> Author: landa Date: 2007-10-24 22:51:22 +0200 (Wed, 24 Oct 2007) New Revision: 1158 Modified: trunk/grassaddons/gui/display_driver/driver.cpp trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Digitization tool: bugfix in display driver, break tool introduced (v.edit need to be fixed) x split Modified: trunk/grassaddons/gui/display_driver/driver.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-23 10:25:45 UTC (rev 1157) +++ trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-24 20:51:22 UTC (rev 1158) @@ -307,7 +307,7 @@ wxPoint *point; wxPen *pen; - if (!IsSelected(line) && !drawSegments && !settings.vertex.enabled) + if (!IsSelected(line) && !settings.vertex.enabled) return -1; // determine color @@ -322,7 +322,6 @@ } else { dcId = 1; - dc->SetId(dcId); } } @@ -332,7 +331,7 @@ for (int i = 1; i < pointsScreen->GetCount() - 1; i++, dcId += 2) { point = (wxPoint*) pointsScreen->Item(i)->GetData(); - if (drawSegments) { + if (IsSelected(line) && drawSegments) { dc->SetId(dcId); dc->SetPen(*pen); wxRect rect (*point, *point); @@ -565,7 +564,7 @@ region.map_width = map_width; region.map_height = map_height; -#ifdef DEBUG: +#ifdef DEBUG std::cerr << "region: n=" << north << "; s=" << south << "; e=" << east Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-23 10:25:45 UTC (rev 1157) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-24 20:51:22 UTC (rev 1158) @@ -450,6 +450,11 @@ return self.__ModifyLines('merge') + def BreakLine(self): + """Break selected lines""" + + return self.__ModifyLines('break') + def SnapLine(self): """Snap selected lines""" @@ -520,11 +525,12 @@ def SelectLinesByQuery(self, pos1, pos2): """Select features by query""" - thresh = self.settings['queryLength'][1] if self.settings['query'][0] == "length": + thresh = self.settings['queryLength'][1] if self.settings["queryLength"][0] == "shorter than": thresh = -1 * thresh else: + thresh = self.settings['queryDangle'][1] if self.settings["queryDangle"][0] == "shorter than": thresh = -1 * thresh @@ -1313,7 +1319,7 @@ self.parent.digit.settings["queryLength"] = (self.queryLengthSL.GetStringSelection(), int(self.queryLengthValue.GetValue())) self.parent.digit.settings["queryDangle"] = (self.queryDangleSL.GetStringSelection(), - int(self.queryDangleValue.GetValue()),) + int(self.queryDangleValue.GetValue())) # update driver settings self.parent.digit.driver.UpdateSettings() Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-23 10:25:45 UTC (rev 1157) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-24 20:51:22 UTC (rev 1158) @@ -113,7 +113,6 @@ except Exception, e: print "Command Thread: ",e - pass time.sleep(0.1) @@ -1058,14 +1057,13 @@ if digitToolbar.action in ["deleteLine", "moveLine", "moveVertex", "copyCats", "editLine", "flipLine", "mergeLine", "snapLine", - "queryLine"]: + "queryLine", "breakLine"]: nselected = 0 # -> delete line || move line || move vertex if digitToolbar.action in ["moveVertex", "editLine"]: if len(digitClass.driver.GetSelected()) == 0: - # -> move vertex (select by point) - # return vertex coordinates (tuple) nselected = digitClass.driver.SelectLineByPoint(pos1, type="line") + # return point on the line elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsIds"): @@ -1104,8 +1102,6 @@ nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) if nselected > 0: - # highlight selected features - # self.UpdateMap(render=False) if digitToolbar.action in ["moveLine", "moveVertex", "copyCats", "editLine"]: # get pseudoDC id of objects which should be redrawn @@ -1133,6 +1129,8 @@ # -> move line || move vertex self.UpdateMap(render=False) + if digitToolbar.action != "copyCats": + redrawAll = False else: # no vector object found self.UpdateMap(render=False, renderVector=False) @@ -1169,7 +1167,9 @@ 'map=%s' % digitClass.settings['backgroundMap'], 'cats=%s' % ",".join(["%d" % v for v in self.copyIds]), '-i', - 'color=yellow'] + 'color=yellow', + 'fcolor=yellow', + 'type=point,line,boundary,centroid'] self.layerTmp = self.Map.AddLayer(type='vector', command=dVectTmp) self.UpdateMap(render=True, renderVector=False) @@ -1359,9 +1359,9 @@ # move vertex digitClass.MoveSelectedVertex(pFrom, move) - else: # edit line - pass + redrawAll = True + del self.moveBegin del self.moveCoords del self.moveIds @@ -1389,6 +1389,9 @@ x, y = self.pdcVector.GetIdBounds(id)[0:2] coords.append(self.Pixel2Cell((x, y))) digitClass.EditLine(line, coords) + + redrawAll = True + del self.moveBegin del self.moveCoords del self.moveIds @@ -1396,6 +1399,8 @@ digitClass.FlipLine() elif digitToolbar.action == "mergeLine": digitClass.MergeLine() + elif digitToolbar.action == "breakLine": + digitClass.BreakLine() elif digitToolbar.action == "snapLine": digitClass.SnapLine() elif digitToolbar.action == "connectLine": @@ -1462,12 +1467,14 @@ "addVertex", "removeVertex", "moveVertex", "copyCats", "flipLine", "mergeLine", "snapLine", "connectLine", "copyLine", - "queryLine"]: + "queryLine", "breakLine"]: # varios tools -> unselected selected features digitClass.driver.SetSelected([]) if digitToolbar.action in ["moveLine", "moveVertex", "editLine"] and \ hasattr(self, "moveBegin"): - # move feature -> delete 'move' variables + + redrawAll = True + del self.moveBegin del self.moveCoords del self.moveIds @@ -1522,7 +1529,7 @@ # (vertex, left vertex, left line, # right vertex, right line) - # self.pdcVector.RemoveId(self.moveIds[0]) + ## self.pdcVector.RemoveId(self.moveIds[0]) # do not draw static lines self.polycoords = [] if digitToolbar.action == "moveVertex": @@ -1537,9 +1544,9 @@ self.pdcVector.RemoveId(self.moveIds[2]-1) self.polycoords.append((x, y)) else: # edit line - # self.pdcVector.TranslateId(self.moveIds[-1], dx, dy) - # self.pdcVector.RemoveId(self.moveIds[-1]) # last vertex - # self.pdcVector.RemoveId(self.moveIds[-1] - 1) # line + ## self.pdcVector.TranslateId(self.moveIds[-1], dx, dy) + ## self.pdcVector.RemoveId(self.moveIds[-1]) # last vertex + ## self.pdcVector.RemoveId(self.moveIds[-1] - 1) # line try: if self.moveIds[-1] > 0: # previous vertex x, y = self.pdcVector.GetIdBounds(self.moveIds[-1])[0:2] @@ -2232,7 +2239,7 @@ # reset mouse['box'] if needed if self.digittoolbar.action in ['addLine']: - if digittoolbar.type in ['point', 'centroid']: + if self.digittoolbar.type in ['point', 'centroid']: self.MapWindow.mouse['box'] = 'point' else: # line, boundary self.MapWindow.mouse['box'] = 'line' Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-23 10:25:45 UTC (rev 1157) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-24 20:51:22 UTC (rev 1158) @@ -370,6 +370,10 @@ except: pass + # close settings dialog if still open + if self.settingsDialog: + self.settingsDialog.OnCancel(None) + # disable the toolbar self.parent.RemoveToolbar ("digit") @@ -440,7 +444,8 @@ if not self.settingsDialog: self.settingsDialog = DigitSettingsDialog(parent=self.parent, title=_("Digitization settings"), - style=wx.DEFAULT_DIALOG_STYLE).Show() + style=wx.DEFAULT_DIALOG_STYLE) + self.settingsDialog.Show() def OnAdditionalToolMenu(self, event): """Menu for additional tools""" @@ -451,19 +456,23 @@ toolMenu.AppendItem(copy) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnCopy, copy) - flip = wx.MenuItem(toolMenu, wx.ID_ANY, 'Flip selected lines/boudaries') + flip = wx.MenuItem(toolMenu, wx.ID_ANY, 'Flip selected lines') toolMenu.AppendItem(flip) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnFlip, flip) - merge = wx.MenuItem(toolMenu, wx.ID_ANY, 'Merge selected lines/boundaries') + merge = wx.MenuItem(toolMenu, wx.ID_ANY, 'Merge selected lines') toolMenu.AppendItem(merge) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnMerge, merge) - snap = wx.MenuItem(toolMenu, wx.ID_ANY, 'Snap selected lines/boundaries') + breakL = wx.MenuItem(toolMenu, wx.ID_ANY, 'Break selected lines at intersection') + toolMenu.AppendItem(breakL) + self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnBreak, breakL) + + snap = wx.MenuItem(toolMenu, wx.ID_ANY, 'Snap selected lines (only to nodes)') toolMenu.AppendItem(snap) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnSnap, snap) - connect = wx.MenuItem(toolMenu, wx.ID_ANY, 'Connect selected two lines/boundaries') + connect = wx.MenuItem(toolMenu, wx.ID_ANY, 'Connect two selected lines') toolMenu.AppendItem(connect) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnConnect, connect) @@ -471,7 +480,7 @@ toolMenu.AppendItem(query) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnQuery, query) - zbulk = wx.MenuItem(toolMenu, wx.ID_ANY, 'Z bulk-labeling 3D lines') + zbulk = wx.MenuItem(toolMenu, wx.ID_ANY, 'Z bulk-labeling of 3D lines') toolMenu.AppendItem(zbulk) self.parent.MapWindow.Bind(wx.EVT_MENU, self.OnZBulk, zbulk) @@ -498,6 +507,12 @@ self.action="mergeLine" self.parent.MapWindow.mouse['box'] = 'box' + def OnBreak(self, event): + """Break selected lines/boundaries""" + Debug.msg(2, "Digittoolbar.OnBreak():") + self.action="breakLine" + self.parent.MapWindow.mouse['box'] = 'box' + def OnSnap(self, event): """Snap selected features""" Debug.msg(2, "Digittoolbar.OnSnap():") From landa at grass.itc.it Fri Oct 26 23:04:01 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Fri Oct 26 23:04:04 2007 Subject: [grass-addons] r1159 - in trunk/grassaddons/gui: display_driver gui_modules Message-ID: <200710262104.l9QL41Xe011766@grass.itc.it> Author: landa Date: 2007-10-26 23:03:56 +0200 (Fri, 26 Oct 2007) New Revision: 1159 Modified: trunk/grassaddons/gui/display_driver/driver.cpp trunk/grassaddons/gui/display_driver/driver.h trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Basic changes to enable zooming, panning when new feature is digitized Modified: trunk/grassaddons/gui/display_driver/driver.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-24 20:51:22 UTC (rev 1158) +++ trunk/grassaddons/gui/display_driver/driver.cpp 2007-10-26 21:03:56 UTC (rev 1159) @@ -731,6 +731,9 @@ /** \brief Select vector objects by given bounding box + If line id is already in the list of selected lines, then it will + be excluded from this list. + \param[in] x1,y1,x2,y2 corners coordinates of bounding box \return number of selected features @@ -767,7 +770,12 @@ for (int i = 0; i < list->n_values; i++) { line = list->value[i]; - selected.push_back(line); + if (!IsSelected(line)) { + selected.push_back(line); + } + else { + selected.erase(GetSelectedIter(line)); + } } // remove all duplicate ids @@ -840,13 +848,29 @@ */ bool DisplayDriver::IsSelected(int line) { - for(std::vector::const_iterator i = selected.begin(), e = selected.end(); + if (GetSelectedIter(line) != selected.end()) + return true; + + return false; +} + +/** + \brief Is vector object selected? + + \param[in] line id + + \return item iterator + \return selected.end() if object is not selected +*/ +std::vector::iterator DisplayDriver::GetSelectedIter(int line) +{ + for(std::vector::iterator i = selected.begin(), e = selected.end(); i != e; ++i) { if (line == *i) - return true; + return i; } - return false; + return selected.end(); } /** @@ -928,6 +952,8 @@ /** \brief Get PseudoDC vertex id of selected line + Set bounding box for vertices of line. + \param[in] x,y coordinates of click \param[in] thresh threshold value @@ -957,6 +983,7 @@ type = Vect_read_line (mapInfo, points, cats, line); // find the closest vertex (x, y) + DCid = 1; for(int idx = 0; idx < points->n_points; idx++) { dist = Vect_points_distance(x, y, 0.0, points->x[idx], points->y[idx], points->z[idx], 0); @@ -971,6 +998,12 @@ Gid = idx; } } + + Cell2Pixel(points->x[idx], points->y[idx], points->z[idx], + &vx, &vy, &vz); + wxRect rect (wxPoint (vx, vy), wxPoint (vx, vy)); + dc->SetIdBounds(DCid, rect); + DCid+=2; } if (minDist > thresh) @@ -979,25 +1012,16 @@ // desc = &(ids[line]); // translate id - // DCid = Gid * 2 + desc->startId; DCid = Gid * 2 + 1; // add selected vertex returnId.push_back(DCid); - Cell2Pixel(points->x[Gid], points->y[Gid], points->z[Gid], - &vx, &vy, &vz); - wxRect rect (wxPoint (vx, vy), wxPoint (vx, vy)); - dc->SetIdBounds(DCid, rect); // left vertex if (DCid == startId) { returnId.push_back(-1); } else { returnId.push_back(DCid - 2); - Cell2Pixel(points->x[Gid-1], points->y[Gid-1], points->z[Gid-1], - &vx, &vy, &vz); - wxRect rect (wxPoint (vx, vy), wxPoint (vx, vy)); - dc->SetIdBounds(DCid-2, rect); } // right vertex @@ -1006,10 +1030,6 @@ } else { returnId.push_back(DCid + 2); - Cell2Pixel(points->x[Gid+1], points->y[Gid+1], points->z[Gid+1], - &vx, &vy, &vz); - wxRect rect (wxPoint (vx, vy), wxPoint (vx, vy)); - dc->SetIdBounds(DCid + 2, rect); } return returnId; Modified: trunk/grassaddons/gui/display_driver/driver.h =================================================================== --- trunk/grassaddons/gui/display_driver/driver.h 2007-10-24 20:51:22 UTC (rev 1158) +++ trunk/grassaddons/gui/display_driver/driver.h 2007-10-26 21:03:56 UTC (rev 1159) @@ -1,6 +1,6 @@ #include // debug #include -#include +//#include #include // For compilers that support precompilation, includes "wx.h". @@ -140,6 +140,7 @@ /* select feature */ bool IsSelected(int line); + std::vector::iterator GetSelectedIter(int line); void ResetTopology(); Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-24 20:51:22 UTC (rev 1158) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-26 21:03:56 UTC (rev 1159) @@ -20,7 +20,7 @@ AUTHORS: The GRASS Development Team Michael Barton Jachym Cepicky - Martin Landa + Martin Landa COPYRIGHT: (C) 2006-2007 by the GRASS Development Team This program is free software under the GNU General Public @@ -42,12 +42,12 @@ try: import subprocess except: - CompatPath = os.path.join( os.getenv("GISBASE"),"etc","wx") + CompatPath = os.path.join( os.getenv("GISBASE"), "etc", "wx") sys.path.append(CompatPath) from compat import subprocess -for gmpath in [os.path.join( os.getenv("GISBASE"),"etc","wx","gui_modules" ), - os.path.join( os.getenv("GISBASE"),"etc","wx","icons" )]: +for gmpath in [os.path.join( os.getenv("GISBASE"), "etc", "wx", "gui_modules" ), + os.path.join( os.getenv("GISBASE"), "etc", "wx", "icons" )]: sys.path.append(gmpath) import render @@ -150,8 +150,10 @@ # self.pen = None # pen for drawing zoom boxes, etc. self.polypen = None # pen for drawing polylines (measurements, profiles, etc) - self.polycoords = [] # List of wx.Point tuples defining a polyline - self.lineid = None # ID of rubber band line + # List of wx.Point tuples defining a polyline (geographical coordinates) + self.polycoords = [] + # ID of rubber band line + self.lineid = None # ID of poly line resulting from cumulative rubber band lines (e.g. measurement) self.plineid = None @@ -191,14 +193,13 @@ # the screen, begin and end of dragging, and type of drawing # self.mouse = { - 'l': False, - 'r': False, - 'm': False, - 'pos': [None, None], - 'begin': [0, 0], - 'end': [0, 0], - 'use': "pointer", - 'box': "point" + 'l' : False, + 'r' : False, + 'm' : False, + 'begin': [0, 0], # screen coordinates + 'end' : [0, 0], + 'use' : "pointer", + 'box' : "point" } self.zoomtype = 1 # 1 zoom in, 0 no zoom, -1 zoom out @@ -217,7 +218,8 @@ self.pdcVector = None # pseudoDC for temporal objects (select box, measurement tool, etc.) self.pdcTmp = wx.PseudoDC() - self.redrawAll = True # redraw all pdc layers, Tmp layer is redrawn always (speed issue) + # redraw all pdc's, pdcTmp layer is redrawn always (speed issue) + self.redrawAll = True # will store an off screen empty bitmap for saving to file self._buffer = '' @@ -373,9 +375,17 @@ def OnPaint(self, event): """ - Draw PseudoDC to buffered paint DC + Draw PseudoDC's to buffered paint DC + + self.pdc for background and decorations + self.pdcVector for vector map which is edited + self.pdcTmp for temporaly drawn objects (self.polycoords) + + If self.redrawAll is False on self.pdcTmp content is re-drawn """ + Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll) + dc = wx.BufferedPaintDC(self, self._buffer) # we need to clear the dc BEFORE calling PrepareDC @@ -417,8 +427,9 @@ pdcLast.DrawToDC(dc) # draw temporal object on the foreground - self.pdcTmp.DrawToDCClipped(dc, rgn) - + # self.pdcTmp.DrawToDCClipped(dc, rgn) + self.pdcTmp.DrawToDC(dc) + def OnSize(self, event): """ Scale map image so that it is @@ -513,8 +524,8 @@ or to the geometry of the canvas. """ - Debug.msg (2, "BufferedWindow.UpdateMap(): render=%s" % \ - (render)) + Debug.msg (2, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s" % \ + (render, renderVector)) # # render background image if needed @@ -533,7 +544,6 @@ self.pdcTmp.Clear() self.pdcTmp.RemoveAll() - # # draw background map image to PseudoDC # @@ -588,16 +598,19 @@ if hasattr(self, "regionCoords"): reg = self.Map.GetWindow() self.polypen = wx.Pen(colour='red', width=2, style=wx.SOLID) - c2p = self.Cell2Pixel self.regionCoords = [] - self.regionCoords.append(c2p((reg['west'],reg['north']))) - self.regionCoords.append(c2p((reg['east'],reg['north']))) - self.regionCoords.append(c2p((reg['east'],reg['south']))) - self.regionCoords.append(c2p((reg['west'],reg['south']))) - self.regionCoords.append(c2p((reg['west'],reg['north']))) + self.regionCoords.append((reg['west'], reg['north'])) + self.regionCoords.append((reg['east'], reg['north'])) + self.regionCoords.append((reg['east'], reg['south'])) + self.regionCoords.append((reg['west'], reg['south'])) + self.regionCoords.append((reg['west'], reg['north'])) # draw region extent self.DrawLines(pdc=self.pdcTmp, polycoords=self.regionCoords) + # redraw pdcTmp if needed + if len(self.polycoords) > 0: + self.DrawLines(self.pdcTmp) + # # update statusbar # @@ -621,14 +634,6 @@ dc.SetBackground(wx.Brush("White")) dc.Clear() - #if not self.img: - # return False - - # bitmap = wx.BitmapFromImage(self.img) - - # drag not only background image - # FIXME: when mapdisplay window is hiden by other window, - # self._buffer contains grey holes self.dragimg = wx.DragImage(self._buffer) self.dragimg.BeginDrag((0, 0), self) self.dragimg.GetImageRect(moveto) @@ -663,20 +668,31 @@ self.RefreshRect(r, False) self.lastpos = (event.GetX(),event.GetY()) - def MouseDraw(self, pdc=None): + def MouseDraw(self, pdc=None, begin=None, end=None): """ - Mouse rectangles and lines + Mouse box or line from 'begin' to 'end' + + If not given from self.mouse['begin'] to self.mouse['end']. + """ + self.redrawAll = False + if not pdc: return - Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s" % \ - (self.mouse['use'], self.mouse['box'])) + if begin is None: + begin = self.mouse['begin'] + if end is None: + end = self.mouse['end'] + Debug.msg (4, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \ + (self.mouse['use'], self.mouse['box'], + begin[0], begin[1], end[0], end[1])) + if self.mouse['box'] == "box": boxid = wx.ID_NEW - mousecoords = [self.mouse['begin'][0], self.mouse['begin'][1], \ - self.mouse['end'][0], self.mouse['end'][1]] + mousecoords = [begin[0], begin[1], + end[0], end[1]] r = pdc.GetIdBounds(boxid) r.Inflate(4,4) pdc.ClearId(boxid) @@ -685,12 +701,12 @@ self.Draw(pdc, drawid=boxid, pdctype='box', coords=mousecoords) elif self.mouse['box'] == "line": self.lineid = wx.ID_NEW - mousecoords = [self.mouse['begin'][0], self.mouse['begin'][1], \ - self.mouse['end'][0], self.mouse['end'][1]] - x1=min(self.mouse['begin'][0],self.mouse['end'][0]) - x2=max(self.mouse['begin'][0],self.mouse['end'][0]) - y1=min(self.mouse['begin'][1],self.mouse['end'][1]) - y2=max(self.mouse['begin'][1],self.mouse['end'][1]) + mousecoords = [begin[0], begin[1], \ + end[0], end[1]] + x1=min(begin[0],end[0]) + x2=max(begin[0],end[0]) + y1=min(begin[1],end[1]) + y2=max(begin[1],end[1]) r = wx.Rect(x1,y1,x2-x1,y2-y1) r.Inflate(4,4) try: @@ -703,20 +719,32 @@ self.Draw(pdc, drawid=self.lineid, pdctype='line', coords=mousecoords) def DrawLines(self, pdc=None, polycoords=None): - """Draw polylines in PseudoDC""" + """Draw polyline in PseudoDC + Set self.pline to wx.NEW_ID + 1 + + polycoords - list of polyline vertices, geographical coordinates + (if not given, self.polycoords is used) + + """ + if not pdc: - return - + pdc = self.pdcTmp + if not polycoords: polycoords = self.polycoords if len(polycoords) > 0: self.plineid = wx.ID_NEW + 1 - self.Draw(pdc, drawid=self.plineid, pdctype='polyline', coords=polycoords) + # convert from EN to XY + coords = [] + for p in polycoords: + coords.append(self.Cell2Pixel(p)) + self.Draw(pdc, drawid=self.plineid, pdctype='polyline', coords=coords) + Debug.msg (4, "BufferedWindow.DrawLines(): coords=%s, id=%s" % \ - (polycoords, self.plineid)) + (coords, self.plineid)) return self.plineid @@ -742,29 +770,36 @@ """ Mouse motion and button click notifier """ - wheel = event.GetWheelRotation() # +- int + if self.redrawAll is False: + self.redrawAll = True + wheel = event.GetWheelRotation() # zoom with mouse wheel if wheel != 0: Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel) # zoom 1/2 of the screen - begin = [self.Map.width/4, self.Map.height/4] - end = [self.Map.width - self.Map.width/4, - self.Map.height - self.Map.height/4] + begin = (self.Map.width / 4, self.Map.height / 4) + end = (self.Map.width - self.Map.width / 4, + self.Map.height - self.Map.height / 4) + if wheel > 0: zoomtype = 1 else: zoomtype = -1 + # zoom self.Zoom(begin, end, zoomtype) + # redraw map self.UpdateMap() + + self.OnPaint(None) + # update statusbar self.parent.StatusbarUpdate() - return # left mouse button pressed - if event.LeftDown(): + elif event.LeftDown(): self.OnLeftDown(event) # left mouse button released @@ -774,13 +809,14 @@ # dragging elif event.Dragging(): Debug.msg (5, "BufferedWindow.MouseAction(): Dragging") - currpos = event.GetPositionTuple()[:] - end = (currpos[0] - self.mouse['begin'][0], \ - currpos[1] - self.mouse['begin'][1]) + current = event.GetPositionTuple()[:] + previous = self.mouse['begin'] + move = (current[0] - previous[0], + current[1] - previous[1]) # dragging or drawing box with left button if self.mouse['use'] == 'pan': - self.DragMap(end) + self.DragMap(move) # dragging decoration overlay item elif (self.mouse['use'] == 'pointer' and not self.parent.digittoolbar) and \ @@ -812,9 +848,6 @@ elif event.Moving(): self.OnMouseMoving(event) - # store current mouse position - self.mouse['pos'] = event.GetPositionTuple()[:] - def OnLeftDown(self, event): """ Left mouse button pressed @@ -827,14 +860,13 @@ if self.mouse["use"] in ["measure", "profile"]: # measure || profile if len(self.polycoords) == 0: - self.mouse['end'] = self.mouse['begin'] - self.polycoords.append(self.mouse['begin']) + self.polycoords.append(self.Pixel2Cell(self.mouse['begin'])) self.ClearLines(pdc=self.pdcTmp) else: self.mouse['begin'] = self.mouse['end'] elif self.mouse['use'] == 'zoom': - self.redrawAll = False + pass elif self.mouse["use"] == "pointer" and self.parent.digittoolbar: # digitization digitToolbar = self.parent.digittoolbar @@ -854,8 +886,9 @@ # calculate position of 'update record' dialog offset = 5 - posWindow = self.ClientToScreen((self.mouse['begin'][0] + offset, - self.mouse['begin'][1] + offset)) + position = self.mouse['begin'] + posWindow = self.ClientToScreen((position[0] + offset, + position[1] + offset)) if digitToolbar.action not in ["moveVertex", "addVertex", "removeVertex", "editLine"]: @@ -867,8 +900,8 @@ if digitToolbar.type in ["point", "centroid"]: # add new point digitClass.AddPoint(map=map, - type=digitToolbar.type, - x=east, y=north) + type=digitToolbar.type, + x=east, y=north) self.UpdateMap(render=False) # redraw map @@ -887,25 +920,18 @@ sqlfile.file.write(sql + ";\n") sqlfile.file.flush() executeCommand = gcmd.Command(cmd=["db.execute", - "--q", - "input=%s" % sqlfile.name]) + "--q", + "input=%s" % sqlfile.name]) elif digitToolbar.type in ["line", "boundary"]: - # add new point to the line - self.polycoords.append(event.GetPositionTuple()[:]) - self.mouse['begin'] = self.polycoords[-1] + # add new point to the line + self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:])) self.DrawLines(pdc=self.pdcTmp) elif digitToolbar.action == "editLine" and hasattr(self, "moveIds"): - coords=self.polycoords[-2:] - idLine = wx.NewId() - self.pdcVector.SetId(idLine) - self.pdcVector.DrawLine(coords[0][0], coords[0][1], - coords[1][0], coords[1][1]) - idNode = wx.NewId() - self.pdcVector.SetIdBounds(idNode, (coords[1][0], coords[1][1], - coords[1][0], coords[1][1])) - self.moveIds.append(idNode) + self.polycoords.append(self.Pixel2Cell(self.mouse['begin'])) + self.moveIds.append(wx.NewId()) + self.DrawLines(pdc=self.pdcTmp) elif digitToolbar.action == "deleteLine": pass @@ -913,13 +939,13 @@ elif digitToolbar.action in ["moveLine", "moveVertex", "editLine"] and \ not hasattr(self, "moveBegin"): self.moveBegin = [0, 0] - self.moveCoords = self.mouse['begin'] + self.moveCoords = self.Pixel2Cell(self.mouse['begin']) self.moveIds = [] if digitToolbar.action in ["moveVertex", "editLine"]: # set pen - self.polypen = wx.Pen(colour=digitClass.settings["symbolHighlight"][1], - width=2, style=wx.SHORT_DASH) - self.pdcVector.SetPen(self.polypen) + self.pen = self.polypen = wx.Pen(colour=digitClass.settings["symbolHighlight"][1], + width=2, style=wx.SHORT_DASH) + self.pdcTmp.SetPen(self.polypen) elif digitToolbar.action == "splitLine": pass @@ -986,12 +1012,15 @@ if len(self.polycoords) > 1: # start new line self.polycoords = [] self.ClearLines(pdc=self.pdcTmp) - self.polycoords.append(event.GetPositionTuple()[:]) + self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:])) if len(self.polycoords) == 1: - self.mouse['begin'] = self.polycoords[-1] + begin = self.Pixel2Cell(self.polycoords[-1]) + end = self.Pixel2Cell(self.mouse['end']) else: - self.mouse['end'] = self.polycoords[-1] - self.DrawLines(pdc=self.pdcTmp) + end = self.Pixel2Cell(self.polycoords[-1]) + begin = self.Pixel2Cell(self.mouse['begin']) + + self.DrawLines(self.pdcTmp, begin, end) elif digitToolbar.action == "connectLine": if len(digitClass.driver.GetSelected()) > 1: # if two line selected -> reset @@ -1018,8 +1047,6 @@ self.mouse['end'] = event.GetPositionTuple()[:] if self.mouse['use'] in ["zoom", "pan"]: - if self.mouse['use'] == 'zoom': - self.redrawAll = True # set region in zoom or pan self.Zoom(self.mouse['begin'], self.mouse['end'], self.zoomtype) @@ -1035,11 +1062,10 @@ elif self.mouse["use"] in ["measure", "profile"]: # measure or profile - self.mouse['end'] = event.GetPositionTuple()[:] if self.mouse["use"] == "measure": self.parent.MeasureDist(self.mouse['begin'], self.mouse['end']) try: - self.polycoords.append(self.mouse['end']) + self.polycoords.append(self.Pixel2Cell(self.mouse['end'])) self.pdc.ClearId(self.lineid) self.DrawLines(pdc=self.pdcTmp) except: @@ -1050,7 +1076,6 @@ digitToolbar = self.parent.digittoolbar digitClass = self.parent.digit - self.mouse['end'] = event.GetPositionTuple()[:] pos1 = self.Pixel2Cell(self.mouse['begin']) pos2 = self.Pixel2Cell(self.mouse['end']) @@ -1063,8 +1088,25 @@ if digitToolbar.action in ["moveVertex", "editLine"]: if len(digitClass.driver.GetSelected()) == 0: nselected = digitClass.driver.SelectLineByPoint(pos1, type="line") - # return point on the line + if digitToolbar.action == "editLine": + self.UpdateMap(render=False) + selVertex = digitClass.driver.GetSelectedVertex(pos1)[0] + ids = digitClass.driver.GetSelected(grassId=False) + # move this line to tmp layer + self.polycoords = [] + for id in ids: + if id % 2: # register only vertices + self.moveIds.append(id) + e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2]) + self.polycoords.append((e, n)) + self.pdcVector.RemoveId(id) + if selVertex < ids[-1] / 2: + # choose first or last node of line + self.moveIds.reverse() + self.polycoords.reverse() + self.UpdateMap(render=False, renderVector=False) + elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsIds"): # collect categories @@ -1103,7 +1145,8 @@ if nselected > 0: if digitToolbar.action in ["moveLine", "moveVertex", - "copyCats", "editLine"]: + "copyCats"] and \ + len(self.moveIds) == 0: # get pseudoDC id of objects which should be redrawn if digitToolbar.action == "moveLine": # -> move line @@ -1115,40 +1158,31 @@ if len(self.moveIds) == 0: # no vertex found digitClass.driver.SetSelected([]) - elif digitToolbar.action == "editLine": - # -> edit line - # get id of selected vertex (last or first node) - selVertex = digitClass.driver.GetSelectedVertex(pos1)[0] - ids = digitClass.driver.GetSelected(grassId=False) - for id in ids: - if id % 2: # vertex - self.moveIds.append(id) - if selVertex < ids[-1] / 2: - # choose first or last node of line - self.moveIds.reverse() - - # -> move line || move vertex - self.UpdateMap(render=False) + if digitToolbar.action != "editLine": + # -> move line || move vertex + self.UpdateMap(render=False) if digitToolbar.action != "copyCats": - redrawAll = False + pass else: # no vector object found - self.UpdateMap(render=False, renderVector=False) + #self.UpdateMap(render=False) + pass elif digitToolbar.action in ["splitLine", "addVertex", "removeVertex"]: pointOnLine = digitClass.driver.SelectLineByPoint(pos1, - type="line") + type="line") if pointOnLine: self.UpdateMap(render=False) # highlight object if digitToolbar.action in ["splitLine", "addVertex"]: - self.DrawCross(pdc=self.pdcVector, coords=self.Cell2Pixel(pointOnLine), + self.DrawCross(pdc=self.pdcTmp, coords=self.Cell2Pixel(pointOnLine), size=5) elif digitToolbar.action == "removeVertex": # get only id of vertex id = digitClass.driver.GetSelectedVertex(pos1)[0] x, y = self.pdcVector.GetIdBounds(id)[0:2] self.pdcVector.RemoveId(id) - self.DrawCross(pdc=self.pdcVector, coords=(x, y), + self.DrawCross(pdc=self.pdcTmp, coords=(x, y), size=5) + elif digitToolbar.action == "copyLine": if digitClass.settings['backgroundMap'] == '': # no background map -> copy from current vector map layer @@ -1178,8 +1212,8 @@ elif digitToolbar.action == "zbulkLine" and len(self.polycoords) == 2: # select lines to be labeled - pos1 = self.Pixel2Cell(self.polycoords[0]) - pos2 = self.Pixel2Cell(self.polycoords[1]) + pos1 = self.polycoords[0] + pos2 = self.polycoords[1] nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) if nselected > 0: @@ -1300,22 +1334,24 @@ dlg.Destroy() if map: - mapcoords = [] + # mapcoords = [] # xy -> EN - for coord in self.polycoords: - mapcoords.append(self.Pixel2Cell(coord)) + # for coord in self.polycoords: + # mapcoords.append(self.Pixel2Cell(coord)) digitClass.AddLine(map=map, - type=digitToolbar.type, - coords=mapcoords) + type=digitToolbar.type, + coords=self.polycoords) + position = self.Cell2Pixel(self.polycoords[-1]) + self.polycoords = [] self.UpdateMap(render=False) # add new record into atribute table if digitClass.settings["addRecord"]: - offset = 5 - posWindow = self.ClientToScreen((self.polycoords[-1][0] + offset, - self.polycoords[-1][1] + offset)) + offset = 5 + posWindow = self.ClientToScreen((position[0] + offset, + position[1] + offset)) # select attributes based on layer and category addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map, @@ -1332,24 +1368,14 @@ executeCommand = gcmd.Command(cmd=["db.execute", "--q", "input=%s" % sqlfile.name]) - # clean up saved positions - self.polycoords = [] elif digitToolbar.action == "deleteLine": # -> delete selected vector features digitClass.DeleteSelectedLines() elif digitToolbar.action in ["moveLine", "moveVertex"] and \ hasattr(self, "moveBegin"): - # move vector feature - # move = [self.Distance((0,0), (self.moveBegin[0], 0))[0], - # self.Distance((0,0), (0, self.moveBegin[1]))[0]] # TODO d.measure - # ES -> EN - # if self.moveBegin[0] < 0.0: - # move[0] *= -1.0 - # if self.moveBegin[1] > 0.0: - # move[1] *= -1.0 pTo = self.Pixel2Cell(event.GetPositionTuple()) - pFrom = self.Pixel2Cell(self.moveCoords) + pFrom = self.moveCoords move = (pTo[0]-pFrom[0], pTo[1]-pFrom[1]) if digitToolbar.action == "moveLine": @@ -1360,8 +1386,6 @@ digitClass.MoveSelectedVertex(pFrom, move) - redrawAll = True - del self.moveBegin del self.moveCoords del self.moveIds @@ -1384,14 +1408,8 @@ pass elif digitToolbar.action == "editLine" and hasattr(self, "moveBegin"): line = digitClass.driver.GetSelected() - coords = [] - for id in self.moveIds: # avoid last point - x, y = self.pdcVector.GetIdBounds(id)[0:2] - coords.append(self.Pixel2Cell((x, y))) - digitClass.EditLine(line, coords) + digitClass.EditLine(line, self.polycoords) - redrawAll = True - del self.moveBegin del self.moveCoords del self.moveIds @@ -1415,8 +1433,8 @@ del self.layerTmp elif digitToolbar.action == "zbulkLine" and len(self.polycoords) == 2: - pos1 = self.Pixel2Cell(self.polycoords[0]) - pos2 = self.Pixel2Cell(self.polycoords[1]) + pos1 = self.polycoords[0] + pos2 = self.polycoords[1] selected = digitClass.driver.GetSelected() dlg = DigitZBulkDialog(parent=self, title=_("Z bulk-labeling dialog"), @@ -1429,6 +1447,7 @@ if digitToolbar.action != "addLine": # unselect and re-render digitClass.driver.SetSelected([]) + self.polycoords = [] self.UpdateMap(render=False) event.Skip() @@ -1447,22 +1466,16 @@ Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \ [removed,]) - self.mouse['begin'] = self.polycoords[-1] + self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1]) except: pass - if digitToolbar.action == "editLine" and len(self.moveIds) > 0: + if digitToolbar.action == "editLine": # remove last vertex & line - self.pdcVector.RemoveId(self.moveIds[-1]) # remove last vertex - if self.moveIds[-1] > self.moveIds[-2]: - self.pdcVector.RemoveId(self.moveIds[-1] - 1) # remove last segment - else: - self.pdcVector.RemoveId(self.moveIds[-1] + 1) # remove last segment self.moveIds.pop() + + self.UpdateMap(render=False, renderVector=False) - self.ClearLines(pdc=self.pdcTmp) - self.UpdateMap(render=False, renderVector=False) - self.DrawLines(pdc=self.pdcTmp) elif digitToolbar.action in ["deleteLine", "moveLine", "splitLine", "addVertex", "removeVertex", "moveVertex", "copyCats", "flipLine", "mergeLine", @@ -1473,8 +1486,6 @@ if digitToolbar.action in ["moveLine", "moveVertex", "editLine"] and \ hasattr(self, "moveBegin"): - redrawAll = True - del self.moveBegin del self.moveCoords del self.moveIds @@ -1491,6 +1502,7 @@ self.UpdateMap(render=True, renderVector=False) del self.layerTmp + self.polycoords = [] self.UpdateMap(render=False) # render vector elif digitToolbar.action == "zbulkLine": @@ -1502,6 +1514,7 @@ def OnMouseMoving(self, event): """Motion event and no mouse buttons were pressed""" + digitToolbar = self.parent.digittoolbar if self.mouse["use"] == "pointer" and digitToolbar: digitClass = self.parent.digit @@ -1510,8 +1523,7 @@ (self.mouse['end'][0], self.mouse['end'][1])) if digitToolbar.action == "addLine" and digitToolbar.type in ["line", "boundary"]: if len(self.polycoords) > 0: - # draw mouse moving - self.MouseDraw(self.pdcTmp) + self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1])) elif digitToolbar.action in ["moveLine", "moveVertex", "editLine"] \ and hasattr(self, "moveBegin"): dx = self.mouse['end'][0] - self.mouse['begin'][0] @@ -1529,35 +1541,32 @@ # (vertex, left vertex, left line, # right vertex, right line) - ## self.pdcVector.RemoveId(self.moveIds[0]) # do not draw static lines - self.polycoords = [] if digitToolbar.action == "moveVertex": + self.polycoords = [] self.pdcVector.TranslateId(self.moveIds[0], dx, dy) if self.moveIds[1] > 0: # previous vertex - x, y = self.pdcVector.GetIdBounds(self.moveIds[1])[0:2] + x, y = self.Pixel2Cell(self.pdcVector.GetIdBounds(self.moveIds[1])[0:2]) self.pdcVector.RemoveId(self.moveIds[1]+1) self.polycoords.append((x, y)) - self.polycoords.append(self.pdcVector.GetIdBounds(self.moveIds[0])[0:2]) + x, y = self.Pixel2Cell(self.pdcVector.GetIdBounds(self.moveIds[0])[0:2]) + self.polycoords.append((x, y)) if self.moveIds[2] > 0: # next vertex - x, y = self.pdcVector.GetIdBounds(self.moveIds[2])[0:2] + x, y = self.Pixel2Cell(self.pdcVector.GetIdBounds(self.moveIds[2])[0:2]) self.pdcVector.RemoveId(self.moveIds[2]-1) self.polycoords.append((x, y)) + + self.ClearLines(pdc=self.pdcTmp) + self.DrawLines(pdc=self.pdcTmp) + else: # edit line - ## self.pdcVector.TranslateId(self.moveIds[-1], dx, dy) - ## self.pdcVector.RemoveId(self.moveIds[-1]) # last vertex - ## self.pdcVector.RemoveId(self.moveIds[-1] - 1) # line try: if self.moveIds[-1] > 0: # previous vertex - x, y = self.pdcVector.GetIdBounds(self.moveIds[-1])[0:2] - self.polycoords.append((x, y)) - self.polycoords.append(self.mouse['end']) + self.MouseDraw(pdc=self.pdcTmp, + begin=self.Cell2Pixel(self.polycoords[-1])) except: # no line - self.pdcVector.RemoveId(self.moveIds[-1]) - self.moveIds = [] - - self.ClearLines(pdc=self.pdcTmp) - self.DrawLines(pdc=self.pdcTmp) + self.moveIds = [] + self.polycoords = [] self.Refresh() # TODO: use RefreshRect() self.mouse['begin'] = self.mouse['end'] @@ -1706,6 +1715,9 @@ self.ZoomHistory(self.Map.region['n'], self.Map.region['s'], self.Map.region['e'], self.Map.region['w']) + if self.redrawAll is False: + self.redrawAll = True + def ZoomBack(self): """ Zoom to previous extents in zoomhistory list @@ -2695,7 +2707,7 @@ mstring = 'segment = %s %s\ttotal distance = %s %s\n' \ % (strdist,dunits,strtotdist,tdunits) - self.gismanager.goutput.cmd_output.write(mstring) + self.gismanager.goutput.cmd_output.AddText(mstring) return dist Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-24 20:51:22 UTC (rev 1158) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-26 21:03:56 UTC (rev 1159) @@ -407,7 +407,7 @@ """Edit line""" Debug.msg(2, "Digittoolbar.OnEditLine():") self.action="editLine" - self.parent.MapWindow.mouse['box'] = 'point' + self.parent.MapWindow.mouse['box'] = 'line' def OnMoveLine(self, event): """Move line""" From landa at grass.itc.it Sat Oct 27 00:02:58 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sat Oct 27 00:03:00 2007 Subject: [grass-addons] r1160 - trunk/grassaddons/gui/gui_modules Message-ID: <200710262202.l9QM2wkU012833@grass.itc.it> Author: landa Date: 2007-10-27 00:02:54 +0200 (Sat, 27 Oct 2007) New Revision: 1160 Modified: trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Digitization tool: Display category dialog is not modal now, can be updated. Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-26 21:03:56 UTC (rev 1159) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-26 22:02:54 UTC (rev 1160) @@ -1000,7 +1000,7 @@ text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Snapping threshold")) self.snappingValue = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(50, -1), initial=self.parent.digit.settings["snapping"][0], - min=0, max=1e6) + min=1, max=1e6) self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue) self.snappingUnit = wx.ComboBox(parent=panel, id=wx.ID_ANY, size=(125, -1), choices=["screen pixels", "map units"]) @@ -1348,6 +1348,7 @@ # {layer: [categories]} self.cats = {} + # do not display dialog if no line is found (-> self.cats) if self.__GetCategories(queryCoords, qdist) == 0 or not self.line: Debug.msg(3, "DigitCategoryDialog(): nothing found!") @@ -1395,7 +1396,7 @@ except: newCat = 1 self.catNew = wx.TextCtrl(parent=self, id=wx.ID_ANY, size=(50, -1), - value=str(newCat)) + value=str(newCat)) btnAddCat = wx.Button(self, wx.ID_ADD) flexSizer.Add(item=layerNewTxt, proportion=0, flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) @@ -1448,6 +1449,7 @@ btnApply.Bind(wx.EVT_BUTTON, self.OnApply) btnOk.Bind(wx.EVT_BUTTON, self.OnOK) btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat) + btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) # list # self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) @@ -1500,6 +1502,7 @@ dlg.ShowModal() dlg.Destroy() return False + def OnRightDown(self, event): """Mouse right button down""" x = event.GetX() @@ -1591,6 +1594,10 @@ event.Skip() + def OnCancel(self, event): + """Cancel button clicked""" + self.Close() + def OnApply(self, event): """Apply button clicked""" @@ -1616,7 +1623,10 @@ 'id=%d' % self.line] gcmd.Command(vEditCmd) - + + # reload map (needed for v.edit) + self.parent.parent.digit.driver.ReloadMap() + self.cats_orig = copy.deepcopy(self.cats) event.Skip() @@ -1662,6 +1672,34 @@ """Get id of selected line of 'None' if no line is selected""" return self.line + def UpdateDialog(self, queryCoords, qdist): + """Update dialog + + Return True if updated otherwise False + """ + + # {layer: [categories]} + self.cats = {} + + # do not display dialog if no line is found (-> self.cats) + if self.__GetCategories(queryCoords, qdist) == 0 or not self.line: + Debug.msg(3, "DigitCategoryDialog(): nothing found!") + return False + + # make copy of cats (used for 'reload') + self.cats_orig = copy.deepcopy(self.cats) + + # polulate list + self.itemDataMap = self.list.Populate(update=True) + + try: + newCat = max(self.cats[1]) + 1 + except: + newCat = 1 + self.catNew.SetValue(str(newCat)) + + return True + class CategoryListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.TextEditMixin): Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-26 21:03:56 UTC (rev 1159) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-26 22:02:54 UTC (rev 1160) @@ -389,8 +389,8 @@ dc = wx.BufferedPaintDC(self, self._buffer) # we need to clear the dc BEFORE calling PrepareDC - bg = wx.Brush(self.GetBackgroundColour()) - dc.SetBackground(bg) + #bg = wx.Brush(self.GetBackgroundColour()) + dc.SetBackground(wx.Brush("White")) dc.Clear() # use PrepareDC to set position correctly @@ -976,26 +976,34 @@ executeCommand = gcmd.Command(cmd=["db.execute", "--q", "input=%s" % sqlfile.name]) + + # unselect & re-draw + if redraw: + digitClass.driver.SetSelected([]) + self.UpdateMap(render=False) + else: # displayCats - categoryDlg = DigitCategoryDialog(parent=self, - map=map, - queryCoords=(east, north), - qdist=qdist, - pos=posWindow, - title=_("Update categories")) - - if categoryDlg.GetLine(): + if digitToolbar.categoryDialog is None: + # open new dialog + digitToolbar.categoryDialog = DigitCategoryDialog(parent=self, + map=map, + queryCoords=(east, north), + qdist=qdist, + pos=posWindow, + title=_("Update categories")) + else: + # update currently open dialog + digitToolbar.categoryDialog.UpdateDialog(queryCoords=(east, north), + qdist=qdist) + + line = digitToolbar.categoryDialog.GetLine() + if line: # highlight feature & re-draw map - digitClass.driver.SetSelected([categoryDlg.GetLine()]) + digitClass.driver.SetSelected([line]) self.UpdateMap(render=False) - redraw = True + redraw = False - if categoryDlg.ShowModal() == wx.ID_OK: - pass - # unselect & re-draw - if redraw: - digitClass.driver.SetSelected([]) - self.UpdateMap(render=False) + digitToolbar.categoryDialog.Show() elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsList"): Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-26 21:03:56 UTC (rev 1159) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-26 22:02:54 UTC (rev 1160) @@ -243,8 +243,9 @@ self.comboid = None - # only one dialog settings can be one + # only one dialog can be open self.settingsDialog = None + self.categoryDialog = None # create toolbars (two rows) self.toolbar = [] @@ -370,10 +371,13 @@ except: pass - # close settings dialog if still open + # close dialogs if still open if self.settingsDialog: self.settingsDialog.OnCancel(None) + if self.categoryDialog: + self.categoryDialog.OnCancel(None) + # disable the toolbar self.parent.RemoveToolbar ("digit") From landa at grass.itc.it Sat Oct 27 18:47:38 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sat Oct 27 18:47:41 2007 Subject: [grass-addons] r1161 - trunk/grassaddons/gui/gui_modules Message-ID: <200710271647.l9RGlcFQ014770@grass.itc.it> Author: landa Date: 2007-10-27 18:45:41 +0200 (Sat, 27 Oct 2007) New Revision: 1161 Modified: trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/toolbars.py Log: Digitization tool: Display attributes dialog enabled to be non-modal Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-26 22:02:54 UTC (rev 1160) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-27 16:45:41 UTC (rev 1161) @@ -32,6 +32,7 @@ import os import locale import string +import tempfile import wx import wx.lib.mixins.listctrl as listmix @@ -597,15 +598,17 @@ def __init__(self, parent, map, layer=-1, cat=-1, # select by layer/cat queryCoords=None, qdist=-1, # select by point - style=wx.DEFAULT_DIALOG_STYLE, pos=wx.DefaultPosition, + style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, + pos=wx.DefaultPosition, action="add"): + self.parent = parent # mapdisplay.BufferedWindow self.map = map self.layer = layer + self.action = action self.cat = cat self.queryCoords = queryCoords self.qdist = qdist - self.action = action # id of selected line self.line = None @@ -619,13 +622,13 @@ if (self.layer == -1 and len(layers) <= 0) or \ (self.layer > 0 and self.layer not in layers): if self.layer == -1: - label = "Database connection for vector map <%s> " \ - "is not defined in DB file." % (self.map) + label = _("Database connection for vector map <%s> " + "is not defined in DB file.") % (self.map) else: - label = "Layer <%d> is not available for vector map <%s>." % \ + label = _("Layer <%d> is not available for vector map <%s>.") % \ (self.layer, self.map) - dlg = wx.MessageDialog(None, + dlg = wx.MessageDialog(self.parent, _("No attribute table found.\n" "%s") % (label), _("Error"), wx.OK | wx.ICON_ERROR) @@ -634,7 +637,7 @@ self.mapInfo = None return - wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, + wx.Dialog.__init__(self, parent=self.parent, id=wx.ID_ANY, title="", style=style, pos=pos) # dialog body @@ -643,97 +646,16 @@ if self.queryCoords: # select by position self.line, nselected = self.mapInfo.SelectByPoint(self.queryCoords, self.qdist) + # notebook - notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT) - for layer in layers: # for each layer - if self.layer > 0 and \ - self.layer != layer: - continue + self.notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT) - if not self.queryCoords: # select using layer/cat - nselected = self.mapInfo.SelectFromTable(layer, self.cat) + self.closeDialog = wx.CheckBox(parent=self, id=wx.ID_ANY, + label=_("Close dialog on submit")) + self.closeDialog.SetValue(True) - if nselected <= 0 and self.action != "add": - continue # nothing selected ... + self.UpdateDialog(cat, queryCoords, qdist) - if self.action == "add": - if nselected <= 0: - table = self.mapInfo.layers[layer]["table"] - columns = self.mapInfo.tables[table] - for name in columns.keys(): - if name == "cat": - self.mapInfo.tables[table][name][1].append(self.cat) - else: - self.mapInfo.tables[table][name][1].append('') - else: # change status 'add' -> 'update' - self.action = "update" - - panel = wx.Panel(parent=notebook, id=wx.ID_ANY) - notebook.AddPage(page=panel, text=_(" %s %d ") % (_("Layer"), layer)) - - # notebook body - border = wx.BoxSizer(wx.VERTICAL) - - table = self.mapInfo.layers[layer]["table"] - columns = self.mapInfo.tables[table] - # value - if len(columns["cat"][1]) == 0: # no cats - sizer = wx.BoxSizer(wx.VERTICAL) - txt = wx.StaticText(parent=panel, id=wx.ID_ANY, - label=_("No categories available.")) - sizer.Add(txt, proportion=1, - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.EXPAND) - border.Add(item=sizer, proportion=1, - flag=wx.ALL | wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER, - border=10) - panel.SetSizer(border) - continue - for idx in range(len(columns["cat"][1])): - flexSizer = wx.FlexGridSizer (cols=4, hgap=3, vgap=3) - flexSizer.AddGrowableCol(0) - # columns - for name in columns.keys(): - type = columns[name][0] - value = columns[name][1][idx] - if name.lower() == "cat": - box = wx.StaticBox (parent=panel, id=wx.ID_ANY, - label=" %s %s " % (_("Category"), value)) - boxFont = self.GetFont() - boxFont.SetWeight(wx.FONTWEIGHT_BOLD) - box.SetFont(boxFont) - sizer = wx.StaticBoxSizer(box, wx.VERTICAL) - colValue = box - else: - colName = wx.StaticText(parent=panel, id=wx.ID_ANY, - label=name) - colType = wx.StaticText(parent=panel, id=wx.ID_ANY, - label="[" + type.lower() + "]") - delimiter = wx.StaticText(parent=panel, id=wx.ID_ANY, label=":") - - colValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value=value, - size=(250, -1)) # TODO: validator - colValue.SetName(name) - self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue) - - flexSizer.Add(colName, proportion=0, - flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) - flexSizer.Add(colType, proportion=0, - flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) - flexSizer.Add(delimiter, proportion=0, - flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) - flexSizer.Add(colValue, proportion=0, - flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) - # add widget reference to self.columns - columns[name][2].append(colValue.GetId()) # name, type, values, id - - # for each attribute (including category) END - sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=1) - border.Add(item=sizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) - # for each category END - - panel.SetSizer(border) - # for each layer END - # set title if self.action == "update": self.SetTitle(_("Update attributes")) @@ -743,56 +665,68 @@ self.SetTitle(_("Display attributes")) # buttons + btnCancel = wx.Button(self, wx.ID_CANCEL) + btnReset = wx.Button(self, wx.ID_UNDO, _("&Reload")) + btnSubmit = wx.Button(self, wx.ID_OK, _("&Submit")) + btnSizer = wx.StdDialogButtonSizer() - btnCancel = wx.Button(self, wx.ID_CANCEL) btnSizer.AddButton(btnCancel) - btnReset = wx.Button(self, wx.ID_APPLY, _("&Reset")) btnSizer.AddButton(btnReset) - btnSubmit = wx.Button(self, wx.ID_OK, _("Submit")) + btnSizer.SetNegativeButton(btnReset) btnSubmit.SetDefault() btnSizer.AddButton(btnSubmit) btnSizer.Realize() - mainSizer.Add(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) - #mainSizer.Add(item=border, proportion=1, - #flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) + mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) + mainSizer.Add(item=self.closeDialog, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, + border=5) mainSizer.Add(item=btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5) # bindigs btnReset.Bind(wx.EVT_BUTTON, self.OnReset) + btnSubmit.Bind(wx.EVT_BUTTON, self.OnSubmit) + btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) self.SetSizer(mainSizer) mainSizer.Fit(self) - if notebook.GetPageCount() == 0: + # set min size for dialog + self.SetMinSize(self.GetBestSize()) + + if self.notebook.GetPageCount() == 0: Debug.msg(2, "DisplayAttributesDialog(): Nothing found!") self.mapInfo = None def __SelectAttributes(self, layer): """Select attributes""" + pass def OnSQLStatement(self, event): """Update SQL statement""" pass - def GetSQLString(self): - """Create SQL statement string based on self.sqlStatement""" + def GetSQLString(self, updateValues=False): + """Create SQL statement string based on self.sqlStatement + + If updateValues is True, update dataFrame according to values + in textfields. + """ sqlCommands = [] # find updated values for each layer/category for layer in self.mapInfo.layers.keys(): # for each layer table = self.mapInfo.layers[layer]["table"] columns = self.mapInfo.tables[table] - for idx in range(len(columns["cat"][1])): # for each category + for idx in range(len(columns["cat"]['values'])): # for each category updatedColumns = [] updatedValues = [] for name in columns.keys(): if name == "cat": - cat = columns[name][1][idx] + cat = columns[name]['values'][idx] continue - type = columns[name][0] - value = columns[name][1][idx] - id = columns[name][2][idx] + type = columns[name]['type'] + value = columns[name]['values'][idx] + id = columns[name]['ids'][idx] try: newvalue = self.FindWindowById(id).GetValue() except: @@ -804,6 +738,8 @@ updatedValues.append(newvalue) else: updatedValues.append("'" + newvalue + "'") + if updateValues: + columns[name]['values'][idx] = newvalue if self.action != "add" and len(updatedValues) == 0: continue @@ -835,6 +771,7 @@ # for each layer END Debug.msg(3, "DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands) + return sqlCommands def OnReset(self, event): @@ -842,22 +779,156 @@ for layer in self.mapInfo.layers.keys(): table = self.mapInfo.layers[layer]["table"] columns = self.mapInfo.tables[table] - for idx in range(len(columns["cat"][1])): + for idx in range(len(columns["cat"]['values'])): for name in columns.keys(): - type = columns[name][0] - value = columns[name][1][idx] - id = columns[name][2][idx] + type = columns[name]['type'] + value = columns[name]['values'][idx] + id = columns[name]['ids'][idx] if name.lower() != "cat": self.FindWindowById(id).SetValue(value) - def OnSubmit(self, event): - """Submit record""" + def OnCancel(self, event): + """Cancel button pressed""" + self.parent.parent.digittoolbar.attributesDialog = None + self.parent.parent.digit.driver.SetSelected([]) + self.parent.UpdateMap(render=False) + self.Close() + def OnSubmit(self, event): + """Submit records""" + sqlCommands = self.GetSQLString(updateValues=True) + if len(sqlCommands) > 0: + sqlfile = tempfile.NamedTemporaryFile(mode="w") + for sql in sqlCommands: + sqlfile.file.write(sql + ";\n") + sqlfile.file.flush() + gcmd.Command(cmd=["db.execute", + "--q", + "input=%s" % sqlfile.name]) + + if self.closeDialog.IsChecked(): + self.OnCancel(event) + def GetLine(self): """Get id of selected line or 'None' if no line is selected""" return self.line + def UpdateDialog(self, cat=-1, queryCoords=None, qdist=-1): + """Update dialog + + Return True if updated otherwise False + """ + self.cat = cat + self.queryCoords = queryCoords + self.qdist = qdist + + if not self.mapInfo: + return False + + self.mapInfo.Reset() + + layers = self.mapInfo.layers.keys() # get available layers + + # id of selected line + if self.queryCoords: # select by position + self.line, nselected = self.mapInfo.SelectByPoint(queryCoords, + qdist) + # reset notebook + self.notebook.DeleteAllPages() + + for layer in layers: # for each layer + if self.layer > 0 and \ + self.layer != layer: + continue + + if not self.queryCoords: # select using layer/cat + nselected = self.mapInfo.SelectFromTable(layer, self.cat) + + if nselected <= 0 and self.action != "add": + continue # nothing selected ... + + if self.action == "add": + if nselected <= 0: + table = self.mapInfo.layers[layer]["table"] + columns = self.mapInfo.tables[table] + for name in columns.keys(): + if name == "cat": + self.mapInfo.tables[table][name]['values'].append(self.cat) + else: + self.mapInfo.tables[table][name]['values'].append('') + else: # change status 'add' -> 'update' + self.action = "update" + + panel = wx.Panel(parent=self.notebook, id=wx.ID_ANY) + self.notebook.AddPage(page=panel, text=_(" %s %d ") % (_("Layer"), layer)) + + # notebook body + border = wx.BoxSizer(wx.VERTICAL) + + table = self.mapInfo.layers[layer]["table"] + columns = self.mapInfo.tables[table] + + # value + if len(columns["cat"]['values']) == 0: # no cats + sizer = wx.BoxSizer(wx.VERTICAL) + txt = wx.StaticText(parent=panel, id=wx.ID_ANY, + label=_("No categories available.")) + sizer.Add(txt, proportion=1, + flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.EXPAND) + border.Add(item=sizer, proportion=1, + flag=wx.ALL | wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER, + border=10) + panel.SetSizer(border) + continue + for idx in range(len(columns["cat"]['values'])): + flexSizer = wx.FlexGridSizer (cols=4, hgap=3, vgap=3) + flexSizer.AddGrowableCol(3) + # columns + for name in columns.keys(): + type = columns[name]['type'] + value = columns[name]['values'][idx] + if name.lower() == "cat": + box = wx.StaticBox (parent=panel, id=wx.ID_ANY, + label=" %s %s " % (_("Category"), value)) + boxFont = self.GetFont() + boxFont.SetWeight(wx.FONTWEIGHT_BOLD) + box.SetFont(boxFont) + sizer = wx.StaticBoxSizer(box, wx.VERTICAL) + colValue = box + else: + colName = wx.StaticText(parent=panel, id=wx.ID_ANY, + label=name) + colType = wx.StaticText(parent=panel, id=wx.ID_ANY, + label="[" + type.lower() + "]") + delimiter = wx.StaticText(parent=panel, id=wx.ID_ANY, label=":") + + colValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value=value, + size=(250, -1)) # TODO: validator + colValue.SetName(name) + self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue) + + flexSizer.Add(colName, proportion=0, + flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(colType, proportion=0, + flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(delimiter, proportion=0, + flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) + flexSizer.Add(colValue, proportion=1, + flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) + # add widget reference to self.columns + columns[name]['ids'].append(colValue.GetId()) # name, type, values, id + + # for each attribute (including category) END + sizer.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=1) + border.Add(item=sizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) + # for each category END + + panel.SetSizer(border) + # for each layer END + + return True + class VectorAttributeInfo: """Class providing information about attribute tables linked to the vector map""" @@ -865,7 +936,7 @@ self.map = map # {layer number : {table, database, driver}) self.layers = {} - # {table : [(column name, type, value)]} + # {table : {column name : type, values, ids}} self.tables = {} if not self.__CheckDBConnection(): # -> self.layers @@ -903,13 +974,15 @@ "layer=%d" % layer]) table = self.layers[layer]["table"] - columns = {} # {name: type, [values], [ids]} + columns = {} # {name: {type, [values], [ids]}} if columnsCommand.returncode == 0: for line in columnsCommand.ReadStdOutput(): columnType, columnName = line.split('|') columnType = columnType.lower().strip() - columns[columnName] = [columnType, [], []] + columns[columnName] = { 'type' : columnType, + 'values' : [], + 'ids' : []} else: pass @@ -937,7 +1010,7 @@ name = name.strip() # append value to the column try: - self.tables[table][name][1].append(value.strip()) + self.tables[table][name]['values'].append(value.strip()) except: read = False @@ -974,11 +1047,20 @@ if selectCommand.returncode == 0: for line in selectCommand.ReadStdOutput(): name, value = line.split('|') - self.tables[table][name][1].append(value) + self.tables[table][name]['values'].append(value) nselected = 1 return nselected + def Reset(self): + """Reset""" + for layer in self.layers: + table = self.layers[layer]["table"] # get table desc + columns = self.tables[table] + for name in self.tables[table].keys(): + self.tables[table][name]['values'] = [] + self.tables[table][name]['ids'] = [] + def main(argv=None): if argv is None: argv = sys.argv Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-26 22:02:54 UTC (rev 1160) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-27 16:45:41 UTC (rev 1161) @@ -174,11 +174,15 @@ layer = self.settings["layer"] cat = self.SetCategory() - addstring="""%s 1 1 - %f %f""" % (key, x, y) + if layer > 0 and cat != "None": + addstring = "%s 1 1\n" % (key) + else: + addstring = "%s 1\n" % (key) + addstring += "%f %f\n" % (x, y) + if layer > 0 and cat != "None": - addstring += "\n%d %d" % (layer, cat) + addstring += "%d %d\n" % (layer, cat) Debug.msg (3, "VEdit.AddPoint(): map=%s, type=%s, layer=%d, cat=%d, x=%f, y=%f" % \ (map, type, layer, cat, x, y)) else: @@ -206,17 +210,21 @@ key = "L" flags = [] - addstring="""%s %d 1\n""" % (key, len(coords)) + if layer > 0 and cat != "None": + addstring = "%s %d 1\n" % (key, len(coords)) + else: + addstring = "%s %d\n" % (key, len(coords)) + for point in coords: - addstring += """%f %f\n""" % \ + addstring += "%f %f\n" % \ (float(point[0]), float(point [1])) if layer > 0 and cat != "None": - addstring += "\n%d %d" % (layer, cat) + addstring += "%d %d\n" % (layer, cat) Debug.msg (3, "Vline.AddLine(): type=%s, layer=%d, cat=%d coords=%s" % \ (key, layer, cat, coords)) else: - Debug.msg (3, "Vline.AddLine(): type=%s, layer=%d, cat=%d coords=%s" % \ + Debug.msg (3, "Vline.AddLine(): type=%s, coords=%s" % \ (key, coords)) Debug.msg (4, "VEdit.AddLine(): input=%s" % addstring) @@ -398,6 +406,9 @@ 'cats=%s' % ",".join(["%d" % v for v in cats]), 'ids=%s' % ",".join(["%d" % v for v in ids])]) + # reload map (needed for v.edit) + self.driver.ReloadMap() + return True def EditLine(self, line, coords): @@ -1414,7 +1425,7 @@ # buttons btnApply = wx.Button(self, wx.ID_APPLY) btnCancel = wx.Button(self, wx.ID_CANCEL) - btnReload = wx.Button(self, wx.ID_UNDO, _("Reload")) + btnReload = wx.Button(self, wx.ID_UNDO, _("&Reload")) btnOk = wx.Button(self, wx.ID_OK) btnOk.SetDefault() @@ -1585,7 +1596,7 @@ return True def OnReload(self, event): - """Reload button clicked""" + """Reload button pressed""" # restore original list self.cats = copy.deepcopy(self.cats_orig) @@ -1595,11 +1606,14 @@ event.Skip() def OnCancel(self, event): - """Cancel button clicked""" + """Cancel button pressed""" + self.parent.parent.digittoolbar.categoryDialog = None + self.parent.parent.digit.driver.SetSelected([]) + self.parent.UpdateMap(render=False) self.Close() def OnApply(self, event): - """Apply button clicked""" + """Apply button pressed""" # action : (catsFrom, catsTo) check = {'catadd': (self.cats, self.cats_orig), @@ -1632,12 +1646,12 @@ event.Skip() def OnOK(self, event): - """OK button clicked""" + """OK button pressed""" self.OnApply(event) - self.Close() + self.OnCancel(event) def OnAddCat(self, event): - """Button 'Add' new category clicked""" + """Button 'Add' new category pressed""" try: layer = int(self.layerNew.GetValue()) cat = int(self.catNew.GetValue()) @@ -1678,6 +1692,9 @@ Return True if updated otherwise False """ + # line id (if not found remains 'None') + self.line = None + # {layer: [categories]} self.cats = {} Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-26 22:02:54 UTC (rev 1160) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-27 16:45:41 UTC (rev 1161) @@ -685,7 +685,7 @@ if end is None: end = self.mouse['end'] - Debug.msg (4, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \ + Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \ (self.mouse['use'], self.mouse['box'], begin[0], begin[1], end[0], end[1])) @@ -955,33 +955,29 @@ redraw = False if digitToolbar.action == "displayAttrs": # select attributes based on coordinates (all layers) - updateRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map, - queryCoords=(east, north), - qdist=qdist, - pos=posWindow, - action="update") - if updateRecordDlg.mapInfo and \ - updateRecordDlg.GetLine(): + if digitToolbar.attributesDialog is None: + digitToolbar.attributesDialog = dbm.DisplayAttributesDialog(parent=self, map=map, + queryCoords=(east, + north), + qdist=qdist, + pos=posWindow, + action="update") + else: + # update currently open dialog + digitToolbar.attributesDialog.UpdateDialog(queryCoords=(east, north), + qdist=qdist) + + line = digitToolbar.attributesDialog.GetLine() + if digitToolbar.attributesDialog.mapInfo and line: # highlight feature & re-draw map - digitClass.driver.SetSelected([updateRecordDlg.GetLine()]) - self.UpdateMap(render=False) - redraw = True - if updateRecordDlg.ShowModal() == wx.ID_OK: - sqlCommands = updateRecordDlg.GetSQLString() - if len(sqlCommands) > 0: - sqlfile = tempfile.NamedTemporaryFile(mode="w") - for sql in sqlCommands: - sqlfile.file.write(sql + ";\n") - sqlfile.file.flush() - executeCommand = gcmd.Command(cmd=["db.execute", - "--q", - "input=%s" % sqlfile.name]) - - # unselect & re-draw - if redraw: + digitClass.driver.SetSelected([line]) + if not digitToolbar.attributesDialog.IsShown(): + digitToolbar.attributesDialog.Show() + else: digitClass.driver.SetSelected([]) - self.UpdateMap(render=False) - + if digitToolbar.attributesDialog.IsShown(): + digitToolbar.attributesDialog.Hide() + else: # displayCats if digitToolbar.categoryDialog is None: # open new dialog @@ -997,14 +993,19 @@ qdist=qdist) line = digitToolbar.categoryDialog.GetLine() + redraw = False if line: # highlight feature & re-draw map digitClass.driver.SetSelected([line]) - self.UpdateMap(render=False) - redraw = False + if not digitToolbar.categoryDialog.IsShown(): + digitToolbar.categoryDialog.Show() + else: + digitClass.driver.SetSelected([]) + if digitToolbar.categoryDialog.IsShown(): + digitToolbar.categoryDialog.Hide() + + self.UpdateMap(render=False) - digitToolbar.categoryDialog.Show() - elif digitToolbar.action == "copyCats": if not hasattr(self, "copyCatsList"): self.copyCatsList = [] @@ -1152,9 +1153,7 @@ nselected = digitClass.driver.SelectLinesByBox(pos1, pos2) if nselected > 0: - if digitToolbar.action in ["moveLine", "moveVertex", - "copyCats"] and \ - len(self.moveIds) == 0: + if digitToolbar.action in ["moveLine", "moveVertex"]: # get pseudoDC id of objects which should be redrawn if digitToolbar.action == "moveLine": # -> move line @@ -1169,8 +1168,7 @@ if digitToolbar.action != "editLine": # -> move line || move vertex self.UpdateMap(render=False) - if digitToolbar.action != "copyCats": - pass + else: # no vector object found #self.UpdateMap(render=False) pass @@ -1408,8 +1406,10 @@ digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) elif digitToolbar.action == "copyCats": try: + print "#", self.copyCatsList + print "#", self.copyCatsIds digitClass.CopyCats(self.copyCatsList, - self.copyCatsIds) + self.copyCatsIds) del self.copyCatsList del self.copyCatsIds except: Modified: trunk/grassaddons/gui/gui_modules/toolbars.py =================================================================== --- trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-26 22:02:54 UTC (rev 1160) +++ trunk/grassaddons/gui/gui_modules/toolbars.py 2007-10-27 16:45:41 UTC (rev 1161) @@ -244,8 +244,9 @@ self.comboid = None # only one dialog can be open - self.settingsDialog = None - self.categoryDialog = None + self.settingsDialog = None + self.categoryDialog = None + self.attributesDialog = None # create toolbars (two rows) self.toolbar = [] From landa at grass.itc.it Sat Oct 27 21:52:16 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Sat Oct 27 21:52:18 2007 Subject: [grass-addons] r1162 - trunk/grassaddons/gui/gui_modules Message-ID: <200710271952.l9RJqGJI016504@grass.itc.it> Author: landa Date: 2007-10-27 21:52:09 +0200 (Sat, 27 Oct 2007) New Revision: 1162 Added: trunk/grassaddons/gui/gui_modules/gselect.py Removed: trunk/grassaddons/gui/gui_modules/select.py Modified: trunk/grassaddons/gui/gui_modules/digit.py trunk/grassaddons/gui/gui_modules/georect.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/menuform.py trunk/grassaddons/gui/gui_modules/profile.py trunk/grassaddons/gui/gui_modules/rules.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py Log: Module select renamed to gselect Modified: trunk/grassaddons/gui/gui_modules/digit.py =================================================================== --- trunk/grassaddons/gui/gui_modules/digit.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/digit.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -43,7 +43,7 @@ import gcmd import dbm from debug import Debug as Debug -import select +import gselect try: driverPath = os.path.join( os.getenv("GISBASE"), "etc","wx", "display_driver") sys.path.append(driverPath) @@ -1022,7 +1022,7 @@ flexSizer1.Add(self.snappingUnit, proportion=0, flag=wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) # background map text = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Backgroud vector map")) - self.backgroundMap = select.Select(parent=panel, id=wx.ID_ANY, size=(200,-1), + self.backgroundMap = gselect.Select(parent=panel, id=wx.ID_ANY, size=(200,-1), type="vector") self.backgroundMap.SetValue(self.parent.digit.settings["backgroundMap"]) self.backgroundMap.Bind(wx.EVT_TEXT, self.OnChangeBackgroundMap) Modified: trunk/grassaddons/gui/gui_modules/georect.py =================================================================== --- trunk/grassaddons/gui/gui_modules/georect.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/georect.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -59,7 +59,7 @@ import render import toolbars import menuform -import select +import gselect import disp_print import gcmd from debug import Debug as Debug @@ -458,7 +458,7 @@ box = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(self, -1, 'Select display image/map:', style=wx.ALIGN_LEFT) box.Add(label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - self.selection = select.Select(self, id=wx.ID_ANY, size=(300,-1), + self.selection = gselect.Select(self, id=wx.ID_ANY, size=(300,-1), type=maptype ) box.Add(self.selection, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) self.sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) Copied: trunk/grassaddons/gui/gui_modules/gselect.py (from rev 1158, trunk/grassaddons/gui/gui_modules/select.py) =================================================================== --- trunk/grassaddons/gui/gui_modules/gselect.py (rev 0) +++ trunk/grassaddons/gui/gui_modules/gselect.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -0,0 +1,289 @@ +""" +MODULE: gselect + +CLASSES: + * Select + * TreeCrtlComboPopup + +PURPOSE: Custon control that selects GRASS GIS elements + +AUTHORS: The GRASS Development Team. Michael Barton & Martin Landa + +COPYRIGHT: (C) 2007 by the GRASS Development Team + This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" + +import os +import sys + +import wx +import wx.combo + +GuiModulePath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") +sys.path.append(GuiModulePath) + +import gcmd + +class SelectDialog(wx.Dialog): + def __init__(self, parent, id=wx.ID_ANY, title='Select GIS element', + pos=wx.DefaultPosition, size=(-1,-1), type='cell', + style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER): + """ + A dialog box for the GIS element selector control so that it can be launched f + rom a button or other control. + """ + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.selection = '' + + sizer = wx.BoxSizer(wx.VERTICAL) + + box = wx.BoxSizer(wx.HORIZONTAL) + self.selection = Select(self, id=wx.ID_ANY, size=(300,-1),type=type) + box.Add(self.selection, 0, wx.ALIGN_CENTER|wx.ALL, 5) + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) + + btnsizer = wx.StdDialogButtonSizer() + + btn = wx.Button(self, wx.ID_OK) + btn.SetDefault() + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_CANCEL) + btnsizer.AddButton(btn) + btnsizer.Realize() + + sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + +class Select(wx.combo.ComboCtrl): + def __init__(self, parent, id, size, type): + """ + Custom control to create a ComboBox with a tree control + to display GIS elements within acessible mapsets. + Elements can be selected with mouse. + """ + wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size) + self.tcp = TreeCtrlComboPopup() + self.SetPopupControl(self.tcp) + self.SetPopupExtents(0,100) + self.tcp.GetElementList(type) + + def SetElementList(self, type): + self.tcp.seltree.DeleteAllItems() + self.tcp.GetElementList(type) + +class TreeCtrlComboPopup(wx.combo.ComboPopup): + """ + Create a tree ComboBox for selecting maps and other GIS elements + in accessible mapsets within the current location + """ + + # overridden ComboPopup methods + + def Init(self): + self.value = None + self.curitem = None + + + def Create(self, parent): + self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT + |wx.TR_HAS_BUTTONS + |wx.TR_SINGLE + |wx.TR_LINES_AT_ROOT + |wx.SIMPLE_BORDER + |wx.TR_FULL_ROW_HIGHLIGHT) + self.seltree.Bind(wx.EVT_MOTION, self.OnMotion) + self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded) + self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed) + self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated) + self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected) + + # the following dummy handler are needed to keep tree events from propagating up to + # the parent GIS Manager layer tree + def mapsetExpanded(self, event): + pass + + def mapsetCollapsed(self, event): + pass + + def mapsetActivated(self, event): + pass + + def mapsetSelected(self, event): + pass + # end of dummy events + + def GetControl(self): + return self.seltree + + def GetStringValue(self): + if self.value: + return self.seltree.GetItemText(self.value) + return "" + + def OnPopup(self): + if self.value: + self.seltree.EnsureVisible(self.value) + self.seltree.SelectItem(self.value) + + def SetStringValue(self, value): + # this assumes that item strings are unique... + root = self.seltree.GetRootItem() + if not root: + return + found = self.FindItem(root, value) + if found: + self.value = found + self.seltree.SelectItem(found) + + def GetAdjustedSize(self, minWidth, prefHeight, maxHeight): + return wx.Size(minWidth, min(200, maxHeight)) + + def GetElementList(self, element): + """ + Get list of GIS elements in accessible mapsets and display as tree + with all relevant elements displayed beneath each mapset branch + """ + #set environmental variables + cmdlist = ['g.gisenv', 'get=MAPSET'] + curr_mapset = gcmd.Command(cmdlist).module_stdout.read().strip() + + #mapsets in current location + cmdlist = ['g.mapsets', '-p'] + mapsets = gcmd.Command(cmdlist).module_stdout.read().strip().split(' ') + + # map element types to g.mlist types + elementdict = {'cell':'rast', + 'raster':'rast', + 'rast':'rast', + 'raster files':'rast', + 'grid3':'rast3d', + 'rast3d':'rast3d', + 'raster3D':'rast3d', + 'raster3D files':'rast3d', + 'vector':'vect', + 'vect':'vect', + 'binary vector files':'vect', + 'dig':'oldvect', + 'oldvect':'oldvect', + 'old vector':'oldvect', + 'dig_ascii':'asciivect', + 'asciivect':'asciivect', + 'asciivector':'asciivect', + 'ascii vector files':'asciivect', + 'icons':'icon', + 'icon':'icon', + 'paint icon files':'icon', + 'paint/labels':'labels', + 'labels':'labels', + 'label':'labels', + 'paint label files':'labels', + 'site_lists':'sites', + 'sites':'sites', + 'site list':'sites', + 'site list files':'sites', + 'windows':'region', + 'region':'region', + 'region definition':'region', + 'region definition files':'region', + 'windows3d':'region3d', + 'region3d':'region3d', + 'region3D definition':'region3d', + 'region3D definition files':'region3d', + 'group':'group', + 'imagery group':'group', + 'imagery group files':'group', + '3d.view':'3dview', + '3dview':'3dview', + '3D viewing parameters':'3dview', + '3D view parameters':'3dview'} + + if element not in elementdict: + self.AddItem('Not selectable element') + return + + #Get directory tree nodes + for dir in mapsets: + if dir == curr_mapset: + dir_node = self.AddItem('Mapset: '+dir) + self.seltree.SetItemTextColour(dir_node, wx.Colour(50,50,200)) + try: + cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] + elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') + elem_list.sort() + for elem in elem_list: + if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) + except: + continue + else: + dir_node = self.AddItem('Mapset: '+dir) + self.seltree.SetItemTextColour(dir_node,wx.Colour(50,50,200)) + try: + cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] + elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') + elem_list.sort() + for elem in elem_list: + if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) + except: + continue + + if self.seltree.ItemHasChildren(dir_node): + self.seltree.Expand(dir_node) + + # helpers + def FindItem(self, parentItem, text): + item, cookie = self.seltree.GetFirstChild(parentItem) + while item: + if self.seltree.GetItemText(item) == text: + return item + if self.seltree.ItemHasChildren(item): + item = self.FindItem(item, text) + item, cookie = self.seltree.GetNextChild(parentItem, cookie) + return wx.TreeItemId(); + + + def AddItem(self, value, parent=None): + if not parent: + root = self.seltree.GetRootItem() + if not root: + root = self.seltree.AddRoot("") + parent = root + + item = self.seltree.AppendItem(parent, text=value) + return item + + def OnMotion(self, evt): + # have the selection follow the mouse, like in a real combobox + item, flags = self.seltree.HitTest(evt.GetPosition()) + if item and flags & wx.TREE_HITTEST_ONITEMLABEL: + self.seltree.SelectItem(item) + self.curitem = item + evt.Skip() + + def OnLeftDown(self, evt): + # do the combobox selection + item, flags = self.seltree.HitTest(evt.GetPosition()) + if item and flags & wx.TREE_HITTEST_ONITEMLABEL: + self.curitem = item + + if self.seltree.GetRootItem() == self.seltree.GetItemParent(item): + self.value = None # cannot select mapset item + else: + self.value = item + + self.Dismiss() + + evt.Skip() + + + Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -77,17 +77,17 @@ class Command(Thread): """ - Creates thread, which will observe the command file and see, if there - is new command to be executed + Creates thread which will observe the command file and see, if + there is new command to be executed """ - def __init__ (self,parent,Map): + def __init__ (self,parent, Map): Thread.__init__(self) global cmdfilename self.parent = parent self.map = Map - self.cmdfile = open(cmdfilename,"r") + self.cmdfile = open(cmdfilename, "r") def run(self): """ @@ -1406,8 +1406,6 @@ digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) elif digitToolbar.action == "copyCats": try: - print "#", self.copyCatsList - print "#", self.copyCatsIds digitClass.CopyCats(self.copyCatsList, self.copyCatsIds) del self.copyCatsList Modified: trunk/grassaddons/gui/gui_modules/menuform.py =================================================================== --- trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/menuform.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -81,7 +81,7 @@ sys.path.append(imagepath) import grassenv -import select +import gselect import gcmd try: import subprocess @@ -924,7 +924,7 @@ flag=wx.ADJUST_MINSIZE | wx.TOP | wx.LEFT, border=5) # element selection tree combobox (maps, icons, regions, etc.) if p.get('prompt','') != 'color' and p.get('element', '') != 'file': - selection = select.Select(parent=which_panel, id=wx.ID_ANY, size=(300,-1), + selection = gselect.Select(parent=which_panel, id=wx.ID_ANY, size=(300,-1), type=p.get('element','') ) if p.get('value','') != '': selection.SetValue(p['value']) # parameter previously set Modified: trunk/grassaddons/gui/gui_modules/profile.py =================================================================== --- trunk/grassaddons/gui/gui_modules/profile.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/profile.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -49,7 +49,7 @@ import render import menuform import disp_print -import select +import gselect import gcmd import gui_modules.defaultfont as defaultfont from debug import Debug as Debug @@ -815,7 +815,7 @@ box = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(self, -1, "Select raster 1 (required):") box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) - selection1 = select.Select(self, id=wx.ID_ANY, size=(300,-1),type='cell') + selection1 = gselect.Select(self, id=wx.ID_ANY, size=(300,-1),type='cell') try: selection1.SetValue(self.rast1) except: @@ -826,7 +826,7 @@ box = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(self, -1, "Select raster 2 (optional):") box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) - selection2 = select.Select(self, id=wx.ID_ANY, size=(300,-1),type='cell') + selection2 = gselect.Select(self, id=wx.ID_ANY, size=(300,-1),type='cell') try: selection2.SetValue(self.rast2) except: @@ -838,7 +838,7 @@ box = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(self, -1, "Select raster 3 (optional):") box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) - selection3 = select.Select(self, id=wx.ID_ANY, size=(300,-1),type='cell') + selection3 = gselect.Select(self, id=wx.ID_ANY, size=(300,-1),type='cell') try: selection3.SetValue(self.rast3) except: Modified: trunk/grassaddons/gui/gui_modules/rules.py =================================================================== --- trunk/grassaddons/gui/gui_modules/rules.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/rules.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -20,8 +20,9 @@ import wx import os import sys -import select +import gselect + class RulesText(wx.Dialog): def __init__(self, parent, id=wx.ID_ANY, title="Enter rules", pos=wx.DefaultPosition, size=wx.DefaultSize, @@ -77,8 +78,8 @@ box = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(self, wx.ID_ANY, label2) box.Add(label, 0, wx.ALIGN_RIGHT|wx.ALL, 5) - self.selection = select.Select(self, id=wx.ID_ANY, size=(300,-1), - type=seltype) + self.selection = gselect.Select(self, id=wx.ID_ANY, size=(300,-1), + type=seltype) box.Add(self.selection, 0, wx.ALIGN_RIGHT|wx.ALL, 5) sizer.Add(item=box, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL| Deleted: trunk/grassaddons/gui/gui_modules/select.py =================================================================== --- trunk/grassaddons/gui/gui_modules/select.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/select.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -1,289 +0,0 @@ -""" -MODULE: select - -CLASSES: - * Select - * TreeCrtlComboPopup - -PURPOSE: Custon control that selects GRASS GIS elements - -AUTHORS: The GRASS Development Team. Michael Barton & Martin Landa - -COPYRIGHT: (C) 2007 by the GRASS Development Team - This program is free software under the GNU General Public - License (>=v2). Read the file COPYING that comes with GRASS - for details. -""" - -import os -import sys - -import wx -import wx.combo - -GuiModulePath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") -sys.path.append(GuiModulePath) - -import gcmd - -class SelectDialog(wx.Dialog): - def __init__(self, parent, id=wx.ID_ANY, title='Select GIS element', - pos=wx.DefaultPosition, size=(-1,-1), type='cell', - style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER): - """ - A dialog box for the GIS element selector control so that it can be launched f - rom a button or other control. - """ - - wx.Dialog.__init__(self, parent, id, title, pos, size, style) - - self.selection = '' - - sizer = wx.BoxSizer(wx.VERTICAL) - - box = wx.BoxSizer(wx.HORIZONTAL) - self.selection = Select(self, id=wx.ID_ANY, size=(300,-1),type=type) - box.Add(self.selection, 0, wx.ALIGN_CENTER|wx.ALL, 5) - sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - - line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) - sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) - - btnsizer = wx.StdDialogButtonSizer() - - btn = wx.Button(self, wx.ID_OK) - btn.SetDefault() - btnsizer.AddButton(btn) - - btn = wx.Button(self, wx.ID_CANCEL) - btnsizer.AddButton(btn) - btnsizer.Realize() - - sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) - - self.SetSizer(sizer) - sizer.Fit(self) - -class Select(wx.combo.ComboCtrl): - def __init__(self, parent, id, size, type): - """ - Custom control to create a ComboBox with a tree control - to display GIS elements within acessible mapsets. - Elements can be selected with mouse. - """ - wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size) - self.tcp = TreeCtrlComboPopup() - self.SetPopupControl(self.tcp) - self.SetPopupExtents(0,100) - self.tcp.GetElementList(type) - - def SetElementList(self, type): - self.tcp.seltree.DeleteAllItems() - self.tcp.GetElementList(type) - -class TreeCtrlComboPopup(wx.combo.ComboPopup): - """ - Create a tree ComboBox for selecting maps and other GIS elements - in accessible mapsets within the current location - """ - - # overridden ComboPopup methods - - def Init(self): - self.value = None - self.curitem = None - - - def Create(self, parent): - self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT - |wx.TR_HAS_BUTTONS - |wx.TR_SINGLE - |wx.TR_LINES_AT_ROOT - |wx.SIMPLE_BORDER - |wx.TR_FULL_ROW_HIGHLIGHT) - self.seltree.Bind(wx.EVT_MOTION, self.OnMotion) - self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) - self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded) - self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed) - self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated) - self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected) - - # the following dummy handler are needed to keep tree events from propagating up to - # the parent GIS Manager layer tree - def mapsetExpanded(self, event): - pass - - def mapsetCollapsed(self, event): - pass - - def mapsetActivated(self, event): - pass - - def mapsetSelected(self, event): - pass - # end of dummy events - - def GetControl(self): - return self.seltree - - def GetStringValue(self): - if self.value: - return self.seltree.GetItemText(self.value) - return "" - - def OnPopup(self): - if self.value: - self.seltree.EnsureVisible(self.value) - self.seltree.SelectItem(self.value) - - def SetStringValue(self, value): - # this assumes that item strings are unique... - root = self.seltree.GetRootItem() - if not root: - return - found = self.FindItem(root, value) - if found: - self.value = found - self.seltree.SelectItem(found) - - def GetAdjustedSize(self, minWidth, prefHeight, maxHeight): - return wx.Size(minWidth, min(200, maxHeight)) - - def GetElementList(self, element): - """ - Get list of GIS elements in accessible mapsets and display as tree - with all relevant elements displayed beneath each mapset branch - """ - #set environmental variables - cmdlist = ['g.gisenv', 'get=MAPSET'] - curr_mapset = gcmd.Command(cmdlist).module_stdout.read().strip() - - #mapsets in current location - cmdlist = ['g.mapsets', '-p'] - mapsets = gcmd.Command(cmdlist).module_stdout.read().strip().split(' ') - - # map element types to g.mlist types - elementdict = {'cell':'rast', - 'raster':'rast', - 'rast':'rast', - 'raster files':'rast', - 'grid3':'rast3d', - 'rast3d':'rast3d', - 'raster3D':'rast3d', - 'raster3D files':'rast3d', - 'vector':'vect', - 'vect':'vect', - 'binary vector files':'vect', - 'dig':'oldvect', - 'oldvect':'oldvect', - 'old vector':'oldvect', - 'dig_ascii':'asciivect', - 'asciivect':'asciivect', - 'asciivector':'asciivect', - 'ascii vector files':'asciivect', - 'icons':'icon', - 'icon':'icon', - 'paint icon files':'icon', - 'paint/labels':'labels', - 'labels':'labels', - 'label':'labels', - 'paint label files':'labels', - 'site_lists':'sites', - 'sites':'sites', - 'site list':'sites', - 'site list files':'sites', - 'windows':'region', - 'region':'region', - 'region definition':'region', - 'region definition files':'region', - 'windows3d':'region3d', - 'region3d':'region3d', - 'region3D definition':'region3d', - 'region3D definition files':'region3d', - 'group':'group', - 'imagery group':'group', - 'imagery group files':'group', - '3d.view':'3dview', - '3dview':'3dview', - '3D viewing parameters':'3dview', - '3D view parameters':'3dview'} - - if element not in elementdict: - self.AddItem('Not selectable element') - return - - #Get directory tree nodes - for dir in mapsets: - if dir == curr_mapset: - dir_node = self.AddItem('Mapset: '+dir) - self.seltree.SetItemTextColour(dir_node, wx.Colour(50,50,200)) - try: - cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] - elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') - elem_list.sort() - for elem in elem_list: - if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) - except: - continue - else: - dir_node = self.AddItem('Mapset: '+dir) - self.seltree.SetItemTextColour(dir_node,wx.Colour(50,50,200)) - try: - cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] - elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') - elem_list.sort() - for elem in elem_list: - if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) - except: - continue - - if self.seltree.ItemHasChildren(dir_node): - self.seltree.Expand(dir_node) - - # helpers - def FindItem(self, parentItem, text): - item, cookie = self.seltree.GetFirstChild(parentItem) - while item: - if self.seltree.GetItemText(item) == text: - return item - if self.seltree.ItemHasChildren(item): - item = self.FindItem(item, text) - item, cookie = self.seltree.GetNextChild(parentItem, cookie) - return wx.TreeItemId(); - - - def AddItem(self, value, parent=None): - if not parent: - root = self.seltree.GetRootItem() - if not root: - root = self.seltree.AddRoot("") - parent = root - - item = self.seltree.AppendItem(parent, text=value) - return item - - def OnMotion(self, evt): - # have the selection follow the mouse, like in a real combobox - item, flags = self.seltree.HitTest(evt.GetPosition()) - if item and flags & wx.TREE_HITTEST_ONITEMLABEL: - self.seltree.SelectItem(item) - self.curitem = item - evt.Skip() - - def OnLeftDown(self, evt): - # do the combobox selection - item, flags = self.seltree.HitTest(evt.GetPosition()) - if item and flags & wx.TREE_HITTEST_ONITEMLABEL: - self.curitem = item - - if self.seltree.GetRootItem() == self.seltree.GetItemParent(item): - self.value = None # cannot select mapset item - else: - self.value = item - - self.Dismiss() - - evt.Skip() - - - Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-27 16:45:41 UTC (rev 1161) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-27 19:52:09 UTC (rev 1162) @@ -29,6 +29,8 @@ import sys import string import tempfile +import time +from threading import Thread import wx import wx.lib.customtreectrl as CT @@ -1151,7 +1153,7 @@ grassCmd = gcmd.Command(cmdlist, verbose=3, stdout=GMStdout(self.cmd_output), stderr=GMStderr(self.cmd_output)) - + # deactivate computational region and return to display settings if tmpreg: os.environ["GRASS_REGION"] = tmpreg @@ -1244,10 +1246,11 @@ return self.buffer.fileno() def __del__(self): - self.buffer.flush() - self.buffer.seek(0,0) - for line in self.buffer.readlines(): - self.write(line) + pass + # self.buffer.flush() + # self.buffer.seek(0,0) + # for line in self.buffer.readlines(): + # self.write(line) class GMStderr: """GMConsole standard error output @@ -1264,6 +1267,8 @@ self.gmstc = gmstc self.buffer = tempfile.TemporaryFile(mode="w") + self.timer = GMStcTimer(self.buffer) + def write(self, s): # if self.gmstc.GetParent().IsShown() == False: # self.gmstc.GetParent().Show() @@ -1279,11 +1284,16 @@ return self.buffer.fileno() def __del__(self): - self.buffer.flush() - self.buffer.seek(0,0) - for line in self.buffer.readlines(): - self.write(line) + pass + # self.buffer.flush() + # self.buffer.seek(0,0) + # for line in self.buffer.readlines(): + # self.write(line) + def GetTimer(self): + """Return timer object""" + return self.timer + class GMStc(wx.stc.StyledTextCtrl): """Styled GMConsole @@ -1328,3 +1338,24 @@ self.UsePopUp(True) self.SetSelBackground(True, "#FFFF00") self.SetUseHorizontalScrollBar(True) + +class GMStcTimer(Thread): + """Timer for console output""" + def __init__(self, file): + print "#", file + self.file = file + self.read = False + + def Read(self): + """Check streams""" + self.read = True +# while self.read: +# line = self.file.read().strip() +# if line: +# print "#", line + +# time.sleep(0.1) + + def Stop(self): + """Stop checking streams""" + self.read = False From neteler at grass.itc.it Sun Oct 28 21:35:57 2007 From: neteler at grass.itc.it (neteler@grass.itc.it) Date: Sun Oct 28 21:35:58 2007 Subject: [grass-addons] r1163 - trunk/grassaddons/i.homography Message-ID: <200710282035.l9SKZvee022721@grass.itc.it> Author: neteler Date: 2007-10-28 21:35:54 +0100 (Sun, 28 Oct 2007) New Revision: 1163 Modified: trunk/grassaddons/i.homography/TODO Log: brent() update was already done Modified: trunk/grassaddons/i.homography/TODO =================================================================== --- trunk/grassaddons/i.homography/TODO 2007-10-27 19:52:09 UTC (rev 1162) +++ trunk/grassaddons/i.homography/TODO 2007-10-28 20:35:54 UTC (rev 1163) @@ -4,9 +4,3 @@ TODO Code based on GRASS 5. To be updated to GRASS 6. - -The brent() function in this modules must -be changed to grass63/lib/gmath/brent.c -due to copyright problems. - - From landa at grass.itc.it Mon Oct 29 00:24:08 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Mon Oct 29 00:24:10 2007 Subject: [grass-addons] r1164 - trunk/grassaddons/gui/gui_modules Message-ID: <200710282324.l9SNO8u0024147@grass.itc.it> Author: landa Date: 2007-10-29 00:24:04 +0100 (Mon, 29 Oct 2007) New Revision: 1164 Modified: trunk/grassaddons/gui/gui_modules/gcmd.py trunk/grassaddons/gui/gui_modules/mapdisp.py trunk/grassaddons/gui/gui_modules/utils.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py Log: Basic command prompt improvements (style need to be set up, etc.). GRASS command run in child thread. Modified: trunk/grassaddons/gui/gui_modules/gcmd.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-28 20:35:54 UTC (rev 1163) +++ trunk/grassaddons/gui/gui_modules/gcmd.py 2007-10-28 23:24:04 UTC (rev 1164) @@ -2,8 +2,8 @@ MODULE: gcmd CLASSES: - * EndOfCommand * Command + * RunCommand PURPOSE: GRASS command interface @@ -17,19 +17,19 @@ for details. """ -# use Popen class or os.popen3 method -usePopenClass = True +import os, sys +import time +import fcntl +from threading import Thread -import os, sys import wx # GUI dialogs... -if usePopenClass: - try: - import subprocess - except: - CompatPath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "compat") - sys.path.append(CompatPath) - import subprocess +try: + import subprocess +except: + CompatPath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "compat") + sys.path.append(CompatPath) + import subprocess # debugging & log window GuiModulePath = os.path.join(os.getenv("GISBASE"), "etc", "wx", "gui_modules") @@ -38,30 +38,26 @@ import wxgui_utils from debug import Debug as Debug -class EndOfCommand(Exception): - """ - End of command indicator - """ - def __str__(self): - return "End of command" - class Command: """ - Run (GRASS) command on the background + Run GRASS command Parameters: - cmd - command string (given as list) + cmd - command given as list stdin - standard input stream - verbose - verbose mode [0; 3] - wait - wait for childer execution - dlgMsg - type of error message (None, gui, txt) [only if wait=True] - log - log window or None + verbose - verbose mode [0, 3] + wait - wait for child execution terminated + dlgMsg - type of error message (None, gui, txt), only if wait is True + stdout - redirect standard output or None + stderr - redirect standard error output or None + If stdout/err is redirected, write() method is required for the given classes. + Usage: - cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=True, wait=True) + cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True) if cmd.returncode == None: - print 'RUNNING' + print 'RUNNING?' elif cmd.returncode == 0: print 'SUCCESS' else: @@ -71,13 +67,9 @@ def __init__ (self, cmd, stdin=None, verbose=0, wait=True, dlgMsg='gui', stdout=None, stderr=None): - # - # input - # - self.module_stdin = None - self.cmd = cmd - self.dlgMsg = dlgMsg + self.cmd = cmd + # # set verbosity level # @@ -90,74 +82,37 @@ os.environ["GRASS_VERBOSE"] = str(verbose) if verbosity: os.environ["GRASS_VERBOSE"] = verbosity - # - # GRASS module - # - self.module = None # - # output + # set message formatting # - self.module_stderr = None + message_format = os.getenv("GRASS_MESSAGE_FORMAT") + os.environ["GRASS_MESSAGE_FORMAT"] = "gui" # - # set message formatting + # run command # - message_format = os.getenv("GRASS_MESSAGE_FORMAT") - os.environ["GRASS_MESSAGE_FORMAT"] = "gui" + self.cmdThread = RunCommand(cmd, stdin, + stdout, stderr) # - # run command ... + # start thread # - if not usePopenClass: # do not use Popen class - Debug.msg(4, "Command.__init__(): [popen3] cmd='%s'" % ' '.join(cmd)) + self.cmdThread.start() - (self.module_stdin, self.module_stdout, self.module_stderr) = \ - os.popen3(' '.join(self.cmd)) - else: # Popen class (default) - Debug.msg(4, "Command.__init__(): [Popen] cmd='%s'" % ' '.join(cmd)) + if wait: + self.cmdThread.join() + self.cmdThread.module.wait() + self.returncode = self.cmdThread.module.returncode + else: + self.cmdThread.join(0.1) + self.returncode = None - if stdout is None: - out = subprocess.PIPE - elif stdout == sys.stdout: - out = None - else: - out = stdout - - if stderr is None: - err = subprocess.PIPE - elif stderr == sys.stderr: - err = None - else: - err = stderr - - self.module = subprocess.Popen(self.cmd, - stdin=subprocess.PIPE, - stdout=out, - stderr=err, - close_fds=False) - # set up streams - self.module_stdin = self.module.stdin - self.module_stderr = self.module.stderr - self.module_stdout = self.module.stdout - - if stdin: # read stdin if requested ... - self.module_stdin.write(stdin) - self.module_stdin.close() - - if self.module: - if wait: - self.module.wait() - - if stderr is None: - # list of messages (<- stderr) - # -> [(type, content)] type = (error, warning, message) - self.module_msg = self.__ProcessStdErr() # -> self.module_msg - - self.returncode = self.module.returncode - # failed? - if self.dlgMsg and self.returncode != 0: - if self.dlgMsg == 'gui': # GUI dialog + if self.returncode is not None: + Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" % \ + (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive())) + if dlgMsg and self.returncode != 0: + if dlgMsg == 'gui': # GUI dialog dlg = wx.MessageDialog(None, ("Execution failed: '%s'\n\n" "Details:\n%s") % (' '.join(self.cmd), @@ -168,22 +123,45 @@ else: # otherwise 'txt' print >> sys.stderr, "Execution failed: '%s'" % (' '.join(self.cmd)) print >> sys.stderr, "\nDetails:\n%s" % self.PrintModuleOutput() - else: - self.returncode = None # running ? + Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" % \ + (' '.join(cmd), wait, self.cmdThread.isAlive())) - if self.returncode is not None: - Debug.msg (3, "Command(): cmd='%s', wait=%d, returncode=%d" % \ - (' '.join(self.cmd), wait, self.returncode)) - else: - Debug.msg (3, "Command(): cmd='%s', wait=%d, returncode=?" % \ - (' '.join(self.cmd), wait)) if message_format: os.environ["GRASS_MESSAGE_FORMAT"] = message_format else: os.unsetenv("GRASS_MESSAGE_FORMAT") + + def __ReadOutput(self, stream): + """Read stream and return list of lines + + Note: Remove '\n' from output (TODO: '\r\n' ??) + """ + lineList = [] + + if stream is None: + return lineList + + while True: + line = stream.readline() + if not line: + break + line = line.replace('\n', '').strip() + lineList.append(line) + + return lineList + + def ReadStdOutput(self): + """Read standard output and return list""" + + return self.__ReadOutput(self.cmdThread.module.stdout) + + def ReadErrOutput(self): + """Read standard error output and return list""" + return self.__ReadOutput(self.cmdThread.module.stderr) + def __ProcessStdErr(self): """ Read messages/warnings/errors from stderr @@ -214,40 +192,11 @@ return msg - def __ReadOutput(self, stream): - """Read stream and return list of lines + def PrintModuleOutput(self, error=True, warning=True, message=True): + """Store module errors, warnings, messages to output string""" - Note: Remove '\n' from output (TODO: '\r\n' ??) - """ - lineList = [] - - if stream is None: - return lineList - - while True: - line = stream.readline() - if not line: - break - line = line.replace('\n', '').strip() - lineList.append(line) - - return lineList - - def ReadStdOutput(self): - """Read standard output and return list""" - - return self.__ReadOutput(self.module_stdout) - - def ReadErrOutput(self): - """Read standard error output and return list""" - - return self.__ReadOutput(self.module_stderr) - - def PrintModuleOutput(self, error=True, warning=True, message=True, rest=False): - """Print module errors, warnings, messages...""" - msgString = "" - for type, msg in self.module_msg: + for type, msg in self.__ProcessStdErr(): if type: if (type == 'ERROR' and error) or \ (type == 'WARNING' and warning) or \ @@ -258,6 +207,75 @@ return msgString + +class RunCommand(Thread): + """See Command class""" + def __init__ (self, cmd, stdin=None, + stdout=None, stderr=None): + + Thread.__init__(self) + + self.cmd = cmd + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + + self.module = None + + def run(self): + """Run command""" + self.module = subprocess.Popen(self.cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=False) + + if self.stdin: # read stdin if requested ... + self.module.stdin.write(self.stdin) + self.module.stdin.close() + + if not self.module: + return + + if self.stdout and self.stderr: + # make stdout/stderr non-blocking + stdout_fileno = self.module.stdout.fileno() + stderr_fileno = self.module.stderr.fileno() + + flags = fcntl.fcntl(stdout_fileno, fcntl.F_GETFL) + fcntl.fcntl(stdout_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK) + + flags = fcntl.fcntl(stderr_fileno, fcntl.F_GETFL) + fcntl.fcntl(stderr_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK) + + # wait for the process to end, sucking in stuff until it does end + while self.module.poll() is None: + try: + self.stdout.write(self.module.stdout.read()) + except IOError: + pass + + try: + self.stderr.write(self.module.stderr.read()) + except IOError: + pass + + time.sleep(0.1) + + # get the last output + + try: + self.stdout.write(self.module.stdout.read()) + pass + except IOError: + pass + + try: + self.stderr.write(self.module.stderr.read()) + except IOError: + pass + + # testing ... if __name__ == "__main__": SEP = "-----------------------------------------------------------------------------" Modified: trunk/grassaddons/gui/gui_modules/mapdisp.py =================================================================== --- trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-28 20:35:54 UTC (rev 1163) +++ trunk/grassaddons/gui/gui_modules/mapdisp.py 2007-10-28 23:24:04 UTC (rev 1164) @@ -80,7 +80,7 @@ Creates thread which will observe the command file and see, if there is new command to be executed """ - def __init__ (self,parent, Map): + def __init__ (self, parent, Map): Thread.__init__(self) global cmdfilename Modified: trunk/grassaddons/gui/gui_modules/utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/utils.py 2007-10-28 20:35:54 UTC (rev 1163) +++ trunk/grassaddons/gui/gui_modules/utils.py 2007-10-28 23:24:04 UTC (rev 1164) @@ -29,8 +29,8 @@ """ tempfileCmd = gcmd.Command(["g.tempfile", - "pid=%d" % - os.getpid()]) + "pid=%d" % + os.getpid()]) tempfile = tempfileCmd.ReadStdOutput()[0].strip() Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-28 20:35:54 UTC (rev 1163) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-28 23:24:04 UTC (rev 1164) @@ -29,8 +29,6 @@ import sys import string import tempfile -import time -from threading import Thread import wx import wx.lib.customtreectrl as CT @@ -1044,7 +1042,8 @@ # progress bar self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY, - range=100, pos=(110, 50), size=(-1, 25)) + range=100, pos=(110, 50), size=(-1, 25), + style=wx.GA_HORIZONTAL) # output control layout boxsizer1 = wx.BoxSizer(wx.VERTICAL) @@ -1149,11 +1148,13 @@ os.unsetenv("GRASS_REGION") # process GRASS command with argument - self.cmd_output.AddText('$ %s' % ' '.join(cmdlist)) - grassCmd = gcmd.Command(cmdlist, verbose=3, + self.cmd_output.AddText('$ %s' % ' '.join(cmdlist) + os.linesep) + + grassCmd = gcmd.Command(cmdlist, verbose=3, wait=False, stdout=GMStdout(self.cmd_output), - stderr=GMStderr(self.cmd_output)) - + stderr=GMStderr(self.cmd_output, + self.console_progressbar)) + # deactivate computational region and return to display settings if tmpreg: os.environ["GRASS_REGION"] = tmpreg @@ -1161,9 +1162,6 @@ if grassCmd.returncode != 0: return False - # if oline.find("GRASS_INFO_PERCENT")>-1: - # self.console_progressbar.SetValue(int(oline.split()[1])) - else: # Send any other command to the shell. Send output to # console output window. @@ -1187,7 +1185,7 @@ def ClearHistory(self, event): """Clear history of commands""" - self.cmd_output.Clear() + self.cmd_output.ClearAll() self.console_progressbar.SetValue(0) def SaveHistory(self, event): @@ -1228,7 +1226,6 @@ """ def __init__(self, gmstc): self.gmstc = gmstc - self.buffer = tempfile.TemporaryFile(mode="w") def write(self, s): # if not self.gmstc.GetParent().IsShown(): @@ -1242,16 +1239,6 @@ self.gmstc.StartStyling(p1, 0xff) self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleOutput) - def fileno(self): - return self.buffer.fileno() - - def __del__(self): - pass - # self.buffer.flush() - # self.buffer.seek(0,0) - # for line in self.buffer.readlines(): - # self.write(line) - class GMStderr: """GMConsole standard error output @@ -1263,36 +1250,52 @@ Copyright: (c) 2005-2007 Jean-Michel Fauth Licence: GPL """ - def __init__(self, gmstc): + def __init__(self, gmstc, gmgauge): self.gmstc = gmstc - self.buffer = tempfile.TemporaryFile(mode="w") + self.gmgauge = gmgauge - self.timer = GMStcTimer(self.buffer) - def write(self, s): # if self.gmstc.GetParent().IsShown() == False: # self.gmstc.GetParent().Show() - + s = s.replace('\n', os.linesep) - p1 = self.gmstc.GetCurrentPos() - self.gmstc.AddText(s) - self.gmstc.EnsureCaretVisible() - p2 = self.gmstc.GetCurrentPos() - self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) - def fileno(self): - return self.buffer.fileno() + message = '' + for line in s.split(os.linesep): + if len(line) == 0: + continue - def __del__(self): - pass - # self.buffer.flush() - # self.buffer.seek(0,0) - # for line in self.buffer.readlines(): - # self.write(line) + if 'GRASS_INFO_PERCENT:' in line: + # 'GRASS_INFO_PERCENT: 10' -> value=10 + value = int(line.split(':')[1].strip()) + if value < 100: + self.gmgauge.SetValue(value) + else: + self.gmgauge.SetValue(0) # reset progress bar on '100%' + elif 'GRASS_INFO_MESSAGE' in line: + type = 'message' + message += line.split(':')[1].strip() + elif 'GRASS_INFO_WARNING' in line: + type = 'warning' + message += line.split(':')[1].strip() + elif 'GRASS_INFO_ERROR' in line: + type = 'error' + message += line.split(':')[1].strip() + elif 'GRASS_INFO_END' in line: + message = '' + else: + p1 = self.gmstc.GetCurrentPos() + self.gmstc.AddText(line + os.linesep) + self.gmstc.EnsureCaretVisible() + p2 = self.gmstc.GetCurrentPos() + #self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) - def GetTimer(self): - """Return timer object""" - return self.timer + if message != '': + p1 = self.gmstc.GetCurrentPos() + self.gmstc.AddText(message + os.linesep) + self.gmstc.EnsureCaretVisible() + p2 = self.gmstc.GetCurrentPos() + #self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError) class GMStc(wx.stc.StyledTextCtrl): """Styled GMConsole @@ -1339,23 +1342,3 @@ self.SetSelBackground(True, "#FFFF00") self.SetUseHorizontalScrollBar(True) -class GMStcTimer(Thread): - """Timer for console output""" - def __init__(self, file): - print "#", file - self.file = file - self.read = False - - def Read(self): - """Check streams""" - self.read = True -# while self.read: -# line = self.file.read().strip() -# if line: -# print "#", line - -# time.sleep(0.1) - - def Stop(self): - """Stop checking streams""" - self.read = False From landa at grass.itc.it Mon Oct 29 10:50:30 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Mon Oct 29 10:50:31 2007 Subject: [grass-addons] r1165 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710290950.l9T9oUci006131@grass.itc.it> Author: landa Date: 2007-10-29 10:50:24 +0100 (Mon, 29 Oct 2007) New Revision: 1165 Modified: trunk/grassaddons/gui/gui_modules/gselect.py trunk/grassaddons/gui/wxgui.py Log: Bugfix in command line output handling Modified: trunk/grassaddons/gui/gui_modules/gselect.py =================================================================== --- trunk/grassaddons/gui/gui_modules/gselect.py 2007-10-28 23:24:04 UTC (rev 1164) +++ trunk/grassaddons/gui/gui_modules/gselect.py 2007-10-29 09:50:24 UTC (rev 1165) @@ -156,11 +156,11 @@ """ #set environmental variables cmdlist = ['g.gisenv', 'get=MAPSET'] - curr_mapset = gcmd.Command(cmdlist).module_stdout.read().strip() + curr_mapset = gcmd.Command(cmdlist).ReadStdOutput()[0] #mapsets in current location cmdlist = ['g.mapsets', '-p'] - mapsets = gcmd.Command(cmdlist).module_stdout.read().strip().split(' ') + mapsets = gcmd.Command(cmdlist).ReadStdOutput()[0].split(' ') # map element types to g.mlist types elementdict = {'cell':'rast', @@ -219,7 +219,7 @@ self.seltree.SetItemTextColour(dir_node, wx.Colour(50,50,200)) try: cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] - elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') + elem_list = gcmd.Command(cmdlist).ReadStdOutput() elem_list.sort() for elem in elem_list: if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) @@ -230,7 +230,7 @@ self.seltree.SetItemTextColour(dir_node,wx.Colour(50,50,200)) try: cmdlist = ['g.mlist', 'type=%s' % elementdict[element], 'mapset=%s' % dir] - elem_list = gcmd.Command(cmdlist).module_stdout.read().strip().split('\n') + elem_list = gcmd.Command(cmdlist).ReadStdOutput() elem_list.sort() for elem in elem_list: if elem != '': self.AddItem(elem+'@'+dir, parent=dir_node) Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-28 23:24:04 UTC (rev 1164) +++ trunk/grassaddons/gui/wxgui.py 2007-10-29 09:50:24 UTC (rev 1165) @@ -375,7 +375,10 @@ menuitem = self.menubar.FindItemById(event.GetId()) itemtext = menuitem.GetText() cmd = menucmd[itemtext] - cmdlist = cmd.split(' ') + try: + cmdlist = cmd.split(' ') + except: # already list? + cmdlist = cmd return cmdlist From landa at grass.itc.it Mon Oct 29 15:13:49 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Mon Oct 29 15:13:51 2007 Subject: [grass-addons] r1166 - in trunk/grassaddons/gui: . gui_modules Message-ID: <200710291413.l9TEDnIV009367@grass.itc.it> Author: landa Date: 2007-10-29 15:13:49 +0100 (Mon, 29 Oct 2007) New Revision: 1166 Modified: trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/utils.py trunk/grassaddons/gui/gui_modules/wxgui_utils.py trunk/grassaddons/gui/wxgui.py Log: Minor bugfix: Attribute manager accessible again. Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-29 09:50:24 UTC (rev 1165) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-29 14:13:49 UTC (rev 1166) @@ -96,11 +96,12 @@ i = 0 # FIXME: Maximal number of columns, when the GUI is still usable dbDescribe = gcmd.Command (cmd = ["db.describe", "-c", - "table=%s" % self.parent.tablename, - "driver=%s" % self.parent.driver, - "database=%s" % self.parent.database]) + "table=%s" % self.parent.tablename, + "driver=%s" % self.parent.driver, + "database=%s" % self.parent.database]) - for line in dbDescribe.module_stdout.readlines()[2:]: + for line in dbDescribe.ReadStdOutput()[2:]: + print "#", line colnum, column, type, length = line.strip().split(":") # FIXME: here will be more types if type.lower().find("integer") > -1: @@ -177,7 +178,7 @@ # FIXME: Max. number of rows, while the GUI is still usable i = 0 # read data - for line in vDbSelect.module_stdout.readlines(): + for line in vDbSelect.ReadStdOutput(): attributes = line.strip().split("|") self.itemDataMap[i] = [] @@ -495,16 +496,15 @@ # get list of attribute tables (TODO: open more tables) vDbConnect = gcmd.Command (cmd=["v.db.connect", "-g", "map=%s" % vectmap]) - try: - if vDbConnect.returncode == 0: - (self.layer, self.tablename, self.column, self.database, self.driver) = vDbConnect.module_stdout.readlines()[0].strip().split() - else: - raise - except: + if vDbConnect.returncode == 0: + (self.layer, self.tablename, self.column, self.database, self.driver) = \ + vDbConnect.ReadStdOutput()[0].split(' ') # TODO all layers + else: self.layer = None if not self.layer: - dlg = wx.MessageDialog(parent, _("No attribute table available for vector map <%s>") % vectmap, _("Error"), wx.OK | wx.ICON_ERROR) + dlg = wx.MessageDialog(parent, _("No attribute table linked to vector map <%s>") % vectmap, + _("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return @@ -954,7 +954,7 @@ return False # list of available layers & (table, database, driver) - for line in layerCommand.ReadStdOutput(): + for line in layerCommand.ReadStdOutput()[0]: lineList = line.split(' ') self.layers[int(lineList[0])] = { "table" : lineList[1], "database" : lineList[3], Modified: trunk/grassaddons/gui/gui_modules/utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/utils.py 2007-10-29 09:50:24 UTC (rev 1165) +++ trunk/grassaddons/gui/gui_modules/utils.py 2007-10-29 14:13:49 UTC (rev 1166) @@ -42,13 +42,28 @@ except: return Node -def GetGRASSVariable(var): - """Return GRASS environment variable""" - - gisEnv = gcmd.Command(['g.gisenv']) - - for item in gisEnv.ReadStdOutput(): - if var in item: - return item.split('=')[1].replace("'",'').replace(';','').strip() - - return '' +def GetLayerNameFromCmd(dcmd): + """Get layer name from GRASS command""" + mapname = '' + for item in dcmd: + if 'map=' in item: + mapname = item.split('=')[1] + elif 'red=' in item: + mapname = item.split('=')[1] + elif 'h_map=' in item: + mapname = item.split('=')[1] + elif 'reliefmap' in item: + mapname = item.split('=')[1] + elif 'd.grid' in item: + mapname = 'grid' + elif 'd.geodesic' in item: + mapname = 'geodesic' + elif 'd.rhumbline' in item: + mapname = 'rhumb' + elif 'labels=' in item: + mapname = item.split('=')[1]+' labels' + + if mapname != '': + break + + return mapname Modified: trunk/grassaddons/gui/gui_modules/wxgui_utils.py =================================================================== --- trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-29 09:50:24 UTC (rev 1165) +++ trunk/grassaddons/gui/gui_modules/wxgui_utils.py 2007-10-29 14:13:49 UTC (rev 1166) @@ -45,6 +45,7 @@ import gcmd import grassenv import histogram +import utils from debug import Debug as Debug from icon import Icons as Icons try: @@ -52,18 +53,6 @@ except: from compat import subprocess - def __del__(self): - Debug.msg (3, "Layer.__del__(): type=%s" % \ - self.type) - - def AddMapLayer (self, maplayer): - """Add reference to MapLayer instance""" - self.maplayer = maplayer - - def AddProperties (self, properties): - """Add menuform properties""" - self.properties = properties - class LayerTree(CT.CustomTreeCtrl): """ Creates layer tree structure @@ -469,7 +458,7 @@ if lcmd and len(lcmd) > 1: cmd = lcmd render = True - name = self.GetLayerNameFromCmd(lcmd) + name = utils.GetLayerNameFromCmd(lcmd) else: cmd = [] render = False @@ -871,37 +860,11 @@ # completed drag and drop self.drag = False - def GetLayerNameFromCmd(self, dcmd): - """Get layer name from GRASS command""" - mapname = '' - for item in dcmd: - if 'map=' in item: - mapname = item.split('=')[1] - elif 'red=' in item: - mapname = item.split('=')[1] - elif 'h_map=' in item: - mapname = item.split('=')[1] - elif 'reliefmap' in item: - mapname = item.split('=')[1] - elif 'd.grid' in item: - mapname = 'grid' - elif 'd.geodesic' in item: - mapname = 'geodesic' - elif 'd.rhumbline' in item: - mapname = 'rhumb' - elif 'labels=' in item: - mapname = item.split('=')[1]+' labels' - - if mapname != '': - break - - return mapname - def GetOptData(self, dcmd, layer, params, propwin): """Process layer data""" # set layer text to map name - mapname = self.GetLayerNameFromCmd(dcmd) + mapname = utils.GetLayerNameFromCmd(dcmd) self.SetItemText(layer, mapname) # update layer data Modified: trunk/grassaddons/gui/wxgui.py =================================================================== --- trunk/grassaddons/gui/wxgui.py 2007-10-29 09:50:24 UTC (rev 1165) +++ trunk/grassaddons/gui/wxgui.py 2007-10-29 14:13:49 UTC (rev 1166) @@ -76,7 +76,7 @@ import gui_modules.utils as utils import gui_modules.gcmd as gcmd import gui_modules.georect as georect - +import gui_modules.dbm as dbm from icons.icon import Icons as Icons from gui_modules.debug import Debug as Debug @@ -851,35 +851,36 @@ # available only for vector map layers try: - maptype = self.curr_page.maptree.GetPyData(layer)['maplayer'].type + maptype = self.curr_page.maptree.GetPyData(layer)[0]['maplayer'].type except: maptype = None + if not maptype or maptype != 'vector': - dlg = wx.MessageDialog(self, _("Attribute management is available only for vector map layers"), _("Error"), wx.OK | wx.ICON_ERROR) + dlg = wx.MessageDialog(self, _("Attribute management is available only for vector map layers"), + _("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return - if not self.curr_page.maptree.GetPyData(layer): + if not self.curr_page.maptree.GetPyData(layer)[0]: return - dcmd = self.curr_page.maptree.GetPyData(layer)[0] + dcmd = self.curr_page.maptree.GetPyData(layer)[0]['cmd'] if not dcmd: return - mapname = map = mapset = size = icon = None - + size = icon = None + mapname = utils.GetLayerNameFromCmd(dcmd) + for option in dcmd: - if option.find('map') > -1: - mapname = option.split('=')[1] - elif option.find('size') > -1: + if option.find('size') > -1: size = option.split('=')[1] elif option.find('icon') > -1: icon = option.split('=')[1] pointdata = (icon, size) - from gui_modules import dbm - self.dbmanager = dbm.AttributeManager(parent=self, id=wx.ID_ANY, title="GRASS Attribute Table Manager: %s" % mapname, + self.dbmanager = dbm.AttributeManager(parent=self, id=wx.ID_ANY, + title=_("GRASS Attribute Table Manager: %s") % mapname, size=wx.Size(500,300), vectmap=mapname, pointdata=pointdata) From landa at grass.itc.it Mon Oct 29 23:35:33 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Mon Oct 29 23:35:34 2007 Subject: [grass-addons] r1167 - trunk/grassaddons/gui/gui_modules Message-ID: <200710292235.l9TMZXaE015220@grass.itc.it> Author: landa Date: 2007-10-29 23:35:29 +0100 (Mon, 29 Oct 2007) New Revision: 1167 Modified: trunk/grassaddons/gui/gui_modules/dbm.py trunk/grassaddons/gui/gui_modules/sqlbuilder.py Log: Basic code cleaning (not fully functional) Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-29 14:13:49 UTC (rev 1166) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-29 22:35:29 UTC (rev 1167) @@ -37,6 +37,7 @@ import wx import wx.lib.mixins.listctrl as listmix +import sqlbuilder import grassenv import gcmd from debug import Debug as Debug @@ -45,139 +46,157 @@ """ The log output is redirected to the status bar of the containing frame. """ - def __init__(self,parent): + def __init__(self, parent): self.parent = parent - def write(self,text_string): + def write(self, text_string): + """Update status bar""" self.parent.SetStatusText(text_string.strip()) class VirtualAttributeList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ColumnSorterMixin): """ - The panel you want to test (VirtualAttributeList) + Support virtual attribute list class """ def __init__(self, parent, log, vectmap, pointdata=None): - wx.ListCtrl.__init__( self, parent, -1, style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES) #wx.VIRTUAL + wx.ListCtrl.__init__( self, parent=parent, id=wx.ID_ANY, + style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES) #wx.VIRTUAL - self.log=log + # + # initialize variables + self.log = log + self.vectmap = vectmap + self.parent = parent + self.qlayer = None + self.icon = '' + self.pointsize = '' - self.vectmap = vectmap if not "@" in self.vectmap: self.vectmap = self.vectmap + "@" + grassenv.GetGRASSVariable("MAPSET") self.mapname, self.mapset = self.vectmap.split("@") - self.icon = '' - self.pointsize = '' - if pointdata: - self.icon = pointdata[0] + self.icon = pointdata[0] self.pointsize = pointdata[1] - self.columns = [] - self.selectedCats = [] + self.columns = [] + self.selectedCats = [] self.lastTurnSelectedCats = [] # just temporary, for comparation - self.parent = parent - self.qlayer = None - #adding some attributes (colourful background for each item rows) + # + # add some attributes (colourful background for each item rows) + # self.attr1 = wx.ListItemAttr() self.attr1.SetBackgroundColour("light blue") self.attr2 = wx.ListItemAttr() self.attr2.SetBackgroundColour("white") self.il = wx.ImageList(16, 16) - self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,wx.ART_TOOLBAR,(16,16))) - self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN,wx.ART_TOOLBAR,(16,16))) + self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR, (16,16))) + self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR, (16,16))) self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) - if self.parent.gismgr: # GIS Manager is running? + if self.parent.gismgr: # Layer Manager is running? self.mapdisp = self.parent.gismgr.curr_page.maptree.mapdisplay self.map = self.parent.gismgr.curr_page.maptree.Map + else: + self.mapdisp = self.map = None # building the columns i = 0 # FIXME: Maximal number of columns, when the GUI is still usable - dbDescribe = gcmd.Command (cmd = ["db.describe", "-c", + dbDescribe = gcmd.Command (cmd = ["db.describe", "-c", "--q", "table=%s" % self.parent.tablename, "driver=%s" % self.parent.driver, "database=%s" % self.parent.database]) - for line in dbDescribe.ReadStdOutput()[2:]: - print "#", line + # structure (e.g.) + # + # ncols: 2 + # nrows: 11 + # Column 1: cat:INTEGER:11 + # Column 2: label:CHARACTER:43 + + for line in dbDescribe.ReadStdOutput()[2:]: # skip ncols and nrows colnum, column, type, length = line.strip().split(":") + column.strip() + # FIXME: here will be more types if type.lower().find("integer") > -1: - self.columns.append({"name":column,"type":int}) + self.columns.append({"name": column, "type": int}) elif type.lower().find("double") > -1: - self.columns.append({"name":column,"type":float}) + self.columns.append({"name": column, "type": float}) elif type.lower().find("float") > -1: - self.columns.append({"name":column,"type":float}) + self.columns.append({"name": column, "type": float}) else: - self.columns.append({"name":column,"type":str}) + self.columns.append({"name": column, "type": str}) - self.InsertColumn(i, column) - self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER) + self.InsertColumn(col=i, heading=column) + self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE_USEHEADER) i += 1 if i >= 256: - self.log.write("Can display only 256 columns") + self.log.write(_("Can display only 256 columns")) break - #These two should probably be passed to init more cleanly - #setting the numbers of items = number of elements in the dictionary - self.itemDataMap = {} + # These two should probably be passed to init more cleanly + # setting the numbers of items = number of elements in the dictionary + self.itemDataMap = {} self.itemIndexMap = [] self.LoadData() - #self.SetItemCount(len(self.itemDataMap)) + # self.SetItemCount(len(self.itemDataMap)) - #mixins + # setup mixins listmix.ListCtrlAutoWidthMixin.__init__(self) listmix.ColumnSorterMixin.__init__(self, len(self.columns)) - #sort by genre (column 2), A->Z ascending order (1) - self.SortListItems(0, 1) + # sort by cat by default + self.SortListItems(col=0, ascending=1) # FIXME category column can be different - #events - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self) + # + # events + # + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self) self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self) - self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self) - #self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) - self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self) - #self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) - #self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) - #self.Bind(wx.EVT_LIST_COL_DRAGGING, self.OnColDragging, self.list) - #self.Bind(wx.EVT_LIST_COL_END_DRAG, self.OnColEndDrag, self.list) - #self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self) + # self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) + self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self) + # self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) + # self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) + # self.Bind(wx.EVT_LIST_COL_DRAGGING, self.OnColDragging, self.list) + # self.Bind(wx.EVT_LIST_COL_END_DRAG, self.OnColEndDrag, self.list) + # self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) + # self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + # self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) - #self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) - #self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) - if self.parent.gismgr: - self.mapdisp.MapWindow.Bind(wx.EVT_LEFT_DOWN, self.onMapClick) + self.mapdisp.MapWindow.Bind(wx.EVT_LEFT_DOWN, self.OnMapClick) self.timer = wx.PyTimer(self.RedrawMap) # check each 0.1s self.timer.Start(100) def LoadData(self,where=None): + """Load data into list""" - # prepare command string - cmdv = ["db.select", "-c", - "table=%s" % self.parent.tablename, - "database=%s" % self.parent.database, - "driver=%s" % self.parent.driver] - if where: self.ClearAll() - cmdv = ["db.select", "-c", + cmdv = ["db.select", "-c", "--q", "sql=SELECT * FROM %s WHERE %s" % (self.parent.tablename, where), + "database=%s" % self.parent.database, + "driver=%s" % self.parent.driver] + else: + cmdv = ["db.select", "-c", "--q", + "table=%s" % self.parent.tablename, "database=%s" % self.parent.database, - "driver=%s" % self.parent.driver] + "driver=%s" % self.parent.driver] # run command - vDbSelect = gcmd.Command (cmd=cmdv) + vDbSelect = gcmd.Command(cmd=cmdv) + # + # read data + # # FIXME: Max. number of rows, while the GUI is still usable i = 0 - # read data for line in vDbSelect.ReadStdOutput(): attributes = line.strip().split("|") self.itemDataMap[i] = [] @@ -190,13 +209,13 @@ pass # insert to table - index = self.InsertStringItem(sys.maxint, str(attributes[0])) + index = self.InsertStringItem(index=sys.maxint, label=str(attributes[0])) self.itemDataMap[i].append(attributes[0]) for j in range(len(attributes[1:])): - self.SetStringItem(index, j+1, str(attributes[j+1])) + self.SetStringItem(index=index, col=j+1, label=str(attributes[j+1])) self.itemDataMap[i].append(attributes[j+1]) - self.SetItemData(index, i) + self.SetItemData(item=index, data=i) self.itemIndexMap.append(i) i += 1 @@ -205,28 +224,29 @@ break def OnCloseWindow(self, event): + """Close attreibute manager window""" if self.qlayer: - self.map.delLayer(item='qlayer') + self.map.DeleteLayer(self.qlayer) - def OnColClick(self,event): - self._col = event.GetColumn() + def OnColClick(self, event): + """Column heading clicked""" + # self._col = event.GetColumn() event.Skip() def OnItemSelected(self, event): + """Item selected""" self.currentItem = event.m_itemIndex - #self.log.write('OnItemSelected: "%s", "%s"\n' % + # self.log.write('OnItemSelected: "%s", "%s"\n' % # (self.currentItem, # self.GetItemText(self.currentItem))) - # now the funny part: - # make 1,2,3,4 to 1-4 - self.selectedCats.append(int(self.GetItemText(self.currentItem))) self.selectedCats.sort() event.Skip() def RedrawMap(self): + """Redraw a map""" if self.lastTurnSelectedCats[:] != self.selectedCats[:]: if self.qlayer: self.map.DeleteLayer(self.qlayer) @@ -277,28 +297,30 @@ if self.pointsize: gcmd.append("size=%s" % (self.pointsize)) - self.qlayer = self.map.AddLayer(type="vector", name='qlayer', command=cmd, - l_active=True, l_hidden=True, l_opacity=1, l_render=False) + self.qlayer = self.map.AddLayer(type="vector", name='qlayer', command=cmd, + l_active=True, l_hidden=True, l_opacity=1, l_render=False) self.mapdisp.ReDraw(None) self.lastTurnSelectedCats = self.selectedCats[:] def OnItemActivated(self, event): + """Item activated""" self.currentItem = event.m_itemIndex self.log.write("OnItemActivated: %s\nTopItem: %s\n" % - (self.GetItemText(self.currentItem), self.GetTopItem())) + (self.GetItemText(self.currentItem), self.GetTopItem())) event.Skip() - def getColumnText(self, index, col): + def GetColumnText(self, index, col): + """Return column text""" item = self.GetItem(index, col) return item.GetText() def OnItemDeselected(self, event): + """Item deselected""" #self.log.write("OnItemDeselected: %s" % event.m_itemIndex) self.selectedCats.remove(int(self.GetItemText(event.m_itemIndex))) self.selectedCats.sort() event.Skip() - # --------------------------------------------------- # These methods are callbacks for implementing the # "virtualness" of the list... @@ -312,10 +334,12 @@ # index=self.itemIndexMap[item] # if ( index % 2) == 0: - def OnGetItemAttr(self, item): - index=self.itemIndexMap[item] + # def OnGetItemAttr(self, item): + # """Get item attributes""" + # index=self.itemIndexMap[item] + + # return self.attr2 - return self.attr2 # if ( index % 2) == 0: # return self.attr2 # else: @@ -341,58 +365,59 @@ # self.Refresh() # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetListCtrl(self): + """Get list, required by VirtualAttributeList class""" return self - # stolen from python2.4/site-packages/wx-2.8-gtk2-unicode/wx/lib/mixins/listctrl.py - # def Sorter(self, key1,key2): - # col = self._col - # ascending = self._colSortFlag[col] - # # convert, because the it is allways string - # try: - # item1 = self.columns[col]["type"](self.itemDataMap[key1][col]) - # except: - # item1 = '' - # try: - # item2 = self.columns[col]["type"](self.itemDataMap[key2][col]) - # except: - # item2 = '' + # stolen from python2.4/site-packages/wx-2.8-gtk2-unicode/wx/lib/mixins/listctrl.py + # def Sorter(self, key1,key2): + # col = self._col + # ascending = self._colSortFlag[col] + # # convert, because the it is allways string + # try: + # item1 = self.columns[col]["type"](self.itemDataMap[key1][col]) + # except: + # item1 = '' + # try: + # item2 = self.columns[col]["type"](self.itemDataMap[key2][col]) + # except: + # item2 = '' + + # #--- Internationalization of string sorting with locale module + # if type(item1) == type('') or type(item2) == type(''): + # cmpVal = locale.strcoll(str(item1), str(item2)) + # else: + # cmpVal = cmp(item1, item2) + # #--- + + # # If the items are equal then pick something else to make the sort v ->alue unique + # if cmpVal == 0: + # cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) + + # if ascending: + # return cmpVal + # else: + # return -cmpVal + + # return cmp(self.columns[self.columnNumber]["type"](a), + # self.columns[self.columnNumber]["type"](b)) + + # # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + # def GetSortImages(self): + # return (self.sm_dn, self.sm_up) - # #--- Internationalization of string sorting with locale module - # if type(item1) == type('') or type(item2) == type(''): - # cmpVal = locale.strcoll(str(item1), str(item2)) - # else: - # cmpVal = cmp(item1, item2) - # #--- + # XXX Looks okay to remove this one (was present in the original demo) + # def getColumnText(self, index, col): + # item = self.GetItem(index, col) + # return item.GetText() - # # If the items are equal then pick something else to make the sort v ->alue unique - # if cmpVal == 0: - # cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) - - # if ascending: - # return cmpVal - # else: - # return -cmpVal - - #return cmp(self.columns[self.columnNumber]["type"](a), - # self.columns[self.columnNumber]["type"](b)) - - # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py - def GetSortImages(self): - return (self.sm_dn, self.sm_up) - - # XXX Looks okay to remove this one (was present in the original demo) - # def getColumnText(self, index, col): - # item = self.GetItem(index, col) - # return item.GetText() - - def onMapClick(self, event): + def OnMapClick(self, event): """ Gets coordinates from mouse clicking on display window """ # map coordinates - x, y = self.mapdisp.MapWindow.Pixel2Cell(event.GetPositionTuple()) - #print 'coordinates =',x,y + x, y = self.mapdisp.MapWindow.Pixel2Cell(event.GetPositionTuple()[:]) category = "" for line in os.popen("v.what east_north=%f,%f map=%s" %\ @@ -406,11 +431,11 @@ item = self.GetItem(idx, 0) if item.GetText() == category: #print idx - #self.Select(idx,True) + # self.Select(idx,True) self.EnsureVisible( idx ) self.SetItemState(idx, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) else: - #self.SetItemState(idx, wx.LIST_STATE_DESELECTED, wx.LIST_STATE_DESELECTED) + # self.SetItemState(idx, wx.LIST_STATE_DESELECTED, wx.LIST_STATE_DESELECTED) self.Select(idx,False) @@ -482,19 +507,22 @@ class AttributeManager(wx.Frame): """ - The main window - - This is where you populate the frame with a panel from the demo. - original line in runTest (in the demo source): - win = TestPanel(nb, log) - this is changed to: - self.win=TestPanel(self,log) + GRASS Attribute manager main window """ def __init__(self, parent, id, title, vectmap, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, pointdata=None): + self.vectmap = vectmap + self.parent = parent + self.gismgr = parent + + # status bar log class + log = Log(self) + # get list of attribute tables (TODO: open more tables) - vDbConnect = gcmd.Command (cmd=["v.db.connect", "-g", "map=%s" % vectmap]) + vDbConnect = gcmd.Command (cmd=["v.db.connect", + "-g", + "map=%s" % self.vectmap]) if vDbConnect.returncode == 0: (self.layer, self.tablename, self.column, self.database, self.driver) = \ @@ -503,57 +531,79 @@ self.layer = None if not self.layer: - dlg = wx.MessageDialog(parent, _("No attribute table linked to vector map <%s>") % vectmap, - _("Error"), wx.OK | wx.ICON_ERROR) + dlg = wx.MessageDialog(patent=parent, + message=_("No attribute table linked to vector map <%s>") % vectmap, + caption=_("Error"), style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return wx.Frame.__init__(self, parent, id, title, size=size, style=style) - self.CreateStatusBar(1) + self.CreateStatusBar(number=1) - self.vectmap = vectmap - self.parent = parent - self.gismgr = parent + # set up virtual list + self.win = VirtualAttributeList(parent=self, log=log, vectmap=vectmap, pointdata=pointdata) - log=Log(self) - - # most important part - self.win = VirtualAttributeList(self, log, vectmap=vectmap, pointdata=pointdata) - + # # buttons - self.btn_apply = wx.Button(self, -1, "Apply") + # + self.btnApply = wx.Button(parent=self, id=wx.ID_APPLY) + self.btnQuit = wx.Button(parent=self, id=wx.ID_CANCEL) # self.btn_unselect = wx.Button(self, -1, "Unselect") - self.btn_sqlbuilder = wx.Button(self, -1, "SQL Builder") + self.btnSqlBuilder = wx.Button(parent=self, id=wx.ID_ANY, label=_("SQL Builder")) - # check - # self.check_add_to_selection = wx.CheckBox(self, -1, "Add to selection") + # radiobuttons + self.sqlSimple = wx.RadioButton(parent=self, id=wx.ID_ANY, + label=_("Simple")) + self.sqlAdvanced = wx.RadioButton(parent=self, id=wx.ID_ANY, + label=_("Advanced")) # textarea - self.text_query = wx.TextCtrl(self,-1,"") + self.sqlWhere = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="") + self.sqlStatement = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="") - # label - self.sqlabel=wx.StaticText(self,-1,"SELECT * FROM %s WHERE " % self.tablename) - self.label_query = wx.StaticText(self,-1,"") + # labels + self.sqlLabel = wx.StaticText(parent=self, id=wx.ID_ANY, + label="SELECT * FROM %s WHERE " % self.tablename) + self.label_query = wx.StaticText(parent=self, id=wx.ID_ANY, + label="") - # box - self.sqlbox = wx.StaticBox(self, -1, "SQL Query:") + # boxes + self.sqlBox = wx.StaticBox(parent=self, id=wx.ID_ANY, + label=" %s " % _("SQL Query")) + self.connectionInfoBox = wx.StaticBox(parent=self, id=wx.ID_ANY, + label=" %s " % _("Database connection")) + self.listBox = wx.StaticBox(parent=self, id=wx.ID_ANY, + label=" %s " % _("Attribute data")) - self.btn_sqlbuilder.Bind(wx.EVT_BUTTON, self.OnBuilder) + # bindings + self.btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder) + self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) + # do layer self.__layout() + + self.SetMinSize((640, 480)) + self.Show() + def OnCloseWindow(self, event): + """Cancel button pressed""" + self.win.OnCloseWindow(event) + self.Close() + def OnBuilder(self,event): - import sqlbuilder - self.builder = sqlbuilder.SQLFrame(self,-1,"SQL Builder",self.vectmap) + """SQL Builder button pressed""" + self.builder = sqlbuilder.SQLFrame(parent=self, id=wx.ID_ANY, + title=_("SQL Builder"), + vectmap=self.vectmap) def OnApply(self,event): + """Apply button pressed""" self.win.LoadData(where=self.text_query.GetValue().strip()) - def OnTextEnter(self, event): pass @@ -561,31 +611,92 @@ pass def __layout(self): + """Do layout""" #self.panel = wx.Panel(self,-1, style=wx.SUNKEN_BORDER) - self.label_query.SetMinSize((500,50)) - self.text_query.SetMinSize((500,-1)) + #self.label_query.SetMinSize((500,50)) + self.sqlWhere.SetMinSize((250,-1)) - bsizer = wx.StaticBoxSizer(self.sqlbox, wx.VERTICAL) - bsizer.Add(self.label_query, flag=wx.EXPAND) + pageSizer = wx.BoxSizer(wx.VERTICAL) + # connection info + infoSizer = wx.StaticBoxSizer(self.connectionInfoBox, wx.VERTICAL) + infoFlexSizer = wx.FlexGridSizer (cols=2, hgap=1, vgap=1) + infoFlexSizer.AddGrowableCol(1) - pagesizer= wx.BoxSizer(wx.VERTICAL) - toolsizer1 = wx.BoxSizer(wx.HORIZONTAL) - #toolsizer2 = wx.BoxSizer(wx.HORIZONTAL) + infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, + label="Database:")) + infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, + label="%s" % self.database)) + infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, + label="Driver:")) + infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, + label="%s" % self.driver)) + infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, + label="Table:")) + infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, + label="%s" % self.tablename)) + infoSizer.Add(item=infoFlexSizer, proportion=0, + flag=wx.ALL, + border=1) - toolsizer1.Add(self.sqlabel, flag=wx.ALIGN_CENTER_VERTICAL, - proportion=1) - toolsizer1.Add(self.text_query,flag=wx.SHAPED|wx.GROW, proportion=2,) - toolsizer1.Add(self.btn_sqlbuilder,flag=wx.ALIGN_RIGHT,proportion=0) - toolsizer1.Add(self.btn_apply,flag=wx.ALIGN_RIGHT,proportion=0) + # attribute data + listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL) + listSizer.Add(item=self.win, proportion=1, + flag=wx.EXPAND | wx.ALL, + border=3) - pagesizer.Add(bsizer,flag=wx.EXPAND) - pagesizer.Add(self.win, proportion=1, flag=wx.EXPAND, border=1) - pagesizer.Add(toolsizer1) + # sql query + sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.VERTICAL) + sqlFlexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5) + sqlFlexSizer.AddGrowableCol(1) - self.SetSizer(pagesizer) - pagesizer.Fit(self) + sqlFlexSizer.Add(item=self.sqlSimple, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL) + sqlSimpleSizer.Add(item=self.sqlLabel, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlSimpleSizer.Add(item=self.sqlWhere, + flag=wx.SHAPED | wx.GROW) + sqlFlexSizer.Add(item=sqlSimpleSizer, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlFlexSizer.Add((0,0)) + sqlFlexSizer.Add(item=self.sqlAdvanced, + flag=wx.ALIGN_CENTER_VERTICAL) + sqlFlexSizer.Add(item=self.sqlStatement, + flag=wx.EXPAND) + sqlFlexSizer.Add(item=self.btnSqlBuilder, + flag=wx.ALIGN_RIGHT) + + sqlSizer.Add(item=sqlFlexSizer, + flag=wx.ALL | wx.EXPAND, + border=0) + + # buttons + btnSizer = wx.StdDialogButtonSizer() + btnSizer.AddButton(self.btnQuit) + btnSizer.AddButton(self.btnApply) + btnSizer.Realize() + + pageSizer.Add(item=infoSizer, + flag=wx.EXPAND | wx.ALL, + proportion=0, + border=3) + pageSizer.Add(item=listSizer, + proportion=1, + flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, + border=3) + pageSizer.Add(item=sqlSizer, + proportion=0, + flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, + border=3) + pageSizer.Add(item=btnSizer, + proportion=0, + flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, + border=3) + + self.SetSizer(pageSizer) + pageSizer.Fit(self) self.Layout() class DisplayAttributesDialog(wx.Dialog): @@ -1078,7 +1189,9 @@ #wx.InitAllImageHandlers() app = wx.PySimpleApp() - f = AttributeManager(parent=None, id=wx.ID_ANY, title=_("GRASS Attribute Table Manager"), size=(700,600), vectmap=argv[1]) + f = AttributeManager(parent=None, id=wx.ID_ANY, + title=_("GRASS Attribute Table Manager: vector map <%s>") % argv[1], + size=(700,600), vectmap=argv[1]) app.MainLoop() if __name__ == '__main__': Modified: trunk/grassaddons/gui/gui_modules/sqlbuilder.py =================================================================== --- trunk/grassaddons/gui/gui_modules/sqlbuilder.py 2007-10-29 14:13:49 UTC (rev 1166) +++ trunk/grassaddons/gui/gui_modules/sqlbuilder.py 2007-10-29 22:35:29 UTC (rev 1167) @@ -1,8 +1,23 @@ -#!/usr/bin/env python """ - Usage: - sqlbuilder.py table_name +MODULE: sqlbuilder.py +CLASSES: + * SQLFrame + +PURPOSE: GRASS SQL Builder + + Usage: + sqlbuilder.py table_name + +AUTHOR(S): GRASS Development Team + Original author: Jachym Cepicky + Various updates: Martin Landa + +COPYRIGHT: (C) 2007 by the GRASS Development Team + + This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. """ import wx @@ -10,18 +25,25 @@ import time import grassenv -#import images -#imagepath = images.__path__[0] -#sys.path.append(imagepath) +import gcmd +imagePath = os.path.join( os.getenv("GISBASE"), "etc", "wx") +sys.path.append(imagePath) +import images +imagepath = images.__path__[0] +sys.path.append(imagepath) class SQLFrame(wx.Frame): + """SQL Frame class""" def __init__(self, parent, id, title, vectmap, qtype="select"): - wx.Frame.__init__(self, parent, -1, title) - self.SetTitle("SQL Builder for GRASS GIS - %s " % (qtype.upper())) - self.SetIcon(wx.Icon(os.path.join(imagepath,'grass_sql.png'), wx.BITMAP_TYPE_ANY)) + wx.Frame.__init__(self, parent, id, title) + self.SetTitle(_("GRASS SQL Builder: %s") % (qtype.upper())) + self.SetIcon(wx.Icon(os.path.join(imagepath, + 'grass_sql.png'), + wx.BITMAP_TYPE_ANY)) + # # variables # @@ -198,13 +220,19 @@ self.Show(True) def GetColumns(self): - for line in os.popen("db.columns table=%s" % (self.tablename)): - self.column_names.append(line.strip()) - for line in os.popen("db.describe -c table=%s" % (self.tablename)).readlines()[1:]: - x,name,ctype,length = line.strip().split(":") - self.columns[name] = {'type':ctype} - return + """Get columns""" + dbDescribe = gcmd.Command(['db.describe', + '-c', '--q', + 'table=%s' % self.tablename]) + # skip ncols and nrows lines + for line in dbDescribe.ReadStdOutput()[2:]: + num, name, ctype, length = line.strip().split(":") + name.strip() + #self.columns_names.append(name) + self.columns[name] = {'type' : ctype} + + def GetUniqueValues(self,event,justsample=False): vals = [] try: From landa at grass.itc.it Tue Oct 30 11:27:29 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 30 11:27:31 2007 Subject: [grass-addons] r1168 - trunk/grassaddons/gui/gui_modules Message-ID: <200710301027.l9UARTVo024881@grass.itc.it> Author: landa Date: 2007-10-30 11:27:26 +0100 (Tue, 30 Oct 2007) New Revision: 1168 Modified: trunk/grassaddons/gui/gui_modules/dbm.py Log: Database connection information collapsable Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-29 22:35:29 UTC (rev 1167) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-30 10:27:26 UTC (rev 1168) @@ -59,7 +59,7 @@ """ def __init__(self, parent, log, vectmap, pointdata=None): wx.ListCtrl.__init__( self, parent=parent, id=wx.ID_ANY, - style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES) #wx.VIRTUAL + style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES) # wx.LC_VIRTUAL # # initialize variables @@ -198,6 +198,7 @@ # FIXME: Max. number of rows, while the GUI is still usable i = 0 for line in vDbSelect.ReadStdOutput(): + attributes = line.strip().split("|") self.itemDataMap[i] = [] @@ -334,17 +335,15 @@ # index=self.itemIndexMap[item] # if ( index % 2) == 0: - # def OnGetItemAttr(self, item): - # """Get item attributes""" - # index=self.itemIndexMap[item] + def OnGetItemAttr(self, item): + """Get item attributes""" + index = self.itemIndexMap[item] - # return self.attr2 + if ( index % 2) == 0: + return self.attr2 + else: + return self.attr1 - # if ( index % 2) == 0: - # return self.attr2 - # else: - # return self.attr1 - # --------------------------------------------------- # Matt C, 2006/02/22 # Here's a better SortItems() method -- @@ -572,14 +571,21 @@ # boxes self.sqlBox = wx.StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("SQL Query")) - self.connectionInfoBox = wx.StaticBox(parent=self, id=wx.ID_ANY, - label=" %s " % _("Database connection")) self.listBox = wx.StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Attribute data")) + # collapsible areas + self.infoCollapseLabelExp = _("Click here to show database connection information") + self.infoCollapseLabelCol = _("Click here to hide database connection information") + self.infoCollapse = wx.CollapsiblePane(parent=self, + label=self.infoCollapseLabelExp, + style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE | wx.EXPAND) + self.MakeInfoPaneContent(self.infoCollapse.GetPane()) + # bindings self.btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder) self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) + self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnInfoPaneChanged, self.infoCollapse) # do layer self.__layout() @@ -588,6 +594,53 @@ self.Show() + def OnInfoPaneChanged(self, event): + """Collapse database connection info box""" + + if self.infoCollapse.IsExpanded(): + self.infoCollapse.SetLabel(self.infoCollapseLabelCol) + else: + self.infoCollapse.SetLabel(self.infoCollapseLabelExp) + + # redo layout + self.Layout() + + def MakeInfoPaneContent(self, pane): + """Create database connection information content""" + # connection info + border = wx.BoxSizer(wx.VERTICAL) + + connectionInfoBox = wx.StaticBox(parent=pane, id=wx.ID_ANY, + label=" %s " % _("Database connection")) + infoSizer = wx.StaticBoxSizer(connectionInfoBox, wx.VERTICAL) + infoFlexSizer = wx.FlexGridSizer (cols=2, hgap=1, vgap=1) + infoFlexSizer.AddGrowableCol(1) + + infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, + label="Database:")) + infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, + label="%s" % self.database)) + infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, + label="Driver:")) + infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, + label="%s" % self.driver)) + infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, + label="Table:")) + infoFlexSizer.Add(item=wx.StaticText(parent=pane, id=wx.ID_ANY, + label="%s" % self.tablename)) + + infoSizer.Add(item=infoFlexSizer, + proportion=1, + flag=wx.EXPAND | wx.ALL, + border=3) + + border.Add(item=infoSizer, + proportion=1, + flag=wx.EXPAND | wx.ALL, + border=3) + + pane.SetSizer(border) + def OnCloseWindow(self, event): """Cancel button pressed""" self.win.OnCloseWindow(event) @@ -599,7 +652,6 @@ title=_("SQL Builder"), vectmap=self.vectmap) - def OnApply(self,event): """Apply button pressed""" self.win.LoadData(where=self.text_query.GetValue().strip()) @@ -619,27 +671,6 @@ pageSizer = wx.BoxSizer(wx.VERTICAL) - # connection info - infoSizer = wx.StaticBoxSizer(self.connectionInfoBox, wx.VERTICAL) - infoFlexSizer = wx.FlexGridSizer (cols=2, hgap=1, vgap=1) - infoFlexSizer.AddGrowableCol(1) - - infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, - label="Database:")) - infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, - label="%s" % self.database)) - infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, - label="Driver:")) - infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, - label="%s" % self.driver)) - infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, - label="Table:")) - infoFlexSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, - label="%s" % self.tablename)) - infoSizer.Add(item=infoFlexSizer, proportion=0, - flag=wx.ALL, - border=1) - # attribute data listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL) listSizer.Add(item=self.win, proportion=1, @@ -678,8 +709,8 @@ btnSizer.AddButton(self.btnApply) btnSizer.Realize() - pageSizer.Add(item=infoSizer, - flag=wx.EXPAND | wx.ALL, + pageSizer.Add(item=self.infoCollapse, + flag=wx.ALL | wx.EXPAND, proportion=0, border=3) pageSizer.Add(item=listSizer, From landa at grass.itc.it Tue Oct 30 16:36:37 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 30 16:36:39 2007 Subject: [grass-addons] r1169 - trunk/grassaddons/gui/gui_modules Message-ID: <200710301536.l9UFabh1027985@grass.itc.it> Author: landa Date: 2007-10-30 16:36:36 +0100 (Tue, 30 Oct 2007) New Revision: 1169 Modified: trunk/grassaddons/gui/gui_modules/dbm.py Log: Basic fixes (simple / advanced sql). Need to be fixed: SQL Builder, wx.LC_VIRTUAL Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-30 10:27:26 UTC (rev 1168) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-30 15:36:36 UTC (rev 1169) @@ -59,7 +59,7 @@ """ def __init__(self, parent, log, vectmap, pointdata=None): wx.ListCtrl.__init__( self, parent=parent, id=wx.ID_ANY, - style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES) # wx.LC_VIRTUAL + style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES) # | wx.LC_VIRTUAL) # # initialize variables @@ -101,7 +101,6 @@ self.mapdisp = self.map = None # building the columns - i = 0 # FIXME: Maximal number of columns, when the GUI is still usable dbDescribe = gcmd.Command (cmd = ["db.describe", "-c", "--q", "table=%s" % self.parent.tablename, @@ -114,11 +113,10 @@ # nrows: 11 # Column 1: cat:INTEGER:11 # Column 2: label:CHARACTER:43 - + i = 0 for line in dbDescribe.ReadStdOutput()[2:]: # skip ncols and nrows colnum, column, type, length = line.strip().split(":") column.strip() - # FIXME: here will be more types if type.lower().find("integer") > -1: self.columns.append({"name": column, "type": int}) @@ -129,13 +127,6 @@ else: self.columns.append({"name": column, "type": str}) - self.InsertColumn(col=i, heading=column) - self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE_USEHEADER) - i += 1 - if i >= 256: - self.log.write(_("Can display only 256 columns")) - break - # These two should probably be passed to init more cleanly # setting the numbers of items = number of elements in the dictionary self.itemDataMap = {} @@ -174,21 +165,44 @@ # check each 0.1s self.timer.Start(100) - def LoadData(self,where=None): + def LoadData(self, cols='*', where=''): """Load data into list""" - if where: - self.ClearAll() - cmdv = ["db.select", "-c", "--q", - "sql=SELECT * FROM %s WHERE %s" % (self.parent.tablename, where), - "database=%s" % self.parent.database, - "driver=%s" % self.parent.driver] + self.DeleteAllItems() + + # self.ClearAll() + for i in range(self.GetColumnCount()): + self.DeleteColumn(0) + + i = 0 + if cols != '*': + for column in cols.split(','): + self.InsertColumn(col=i, heading=column) + i += 1 + + if i >= 256: + self.log.write(_("Can display only 256 columns")) + else: + for column in self.columns: + self.InsertColumn(col=i, heading=column["name"]) + i += 1 + + if i >= 256: + self.log.write(_("Can display only 256 columns")) + + if where is '' or where is None: cmdv = ["db.select", "-c", "--q", - "table=%s" % self.parent.tablename, + "sql=SELECT %s FROM %s" % (cols, self.parent.tablename), "database=%s" % self.parent.database, "driver=%s" % self.parent.driver] + else: + cmdv = ["db.select", "-c", "--q", + "sql=SELECT %s FROM %s WHERE %s" % (cols, self.parent.tablename, where), + "database=%s" % self.parent.database, + "driver=%s" % self.parent.driver] + # run command vDbSelect = gcmd.Command(cmd=cmdv) @@ -198,7 +212,6 @@ # FIXME: Max. number of rows, while the GUI is still usable i = 0 for line in vDbSelect.ReadStdOutput(): - attributes = line.strip().split("|") self.itemDataMap[i] = [] @@ -224,8 +237,13 @@ self.log.write(_("Can display only 32000 lines")) break + for i in range(self.GetColumnCount()): + self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE) + if self.GetColumnWidth(col=i) < 20: + self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE_USEHEADER) + def OnCloseWindow(self, event): - """Close attreibute manager window""" + """Close attribute manager window""" if self.qlayer: self.map.DeleteLayer(self.qlayer) @@ -322,94 +340,84 @@ self.selectedCats.sort() event.Skip() - # --------------------------------------------------- - # These methods are callbacks for implementing the - # "virtualness" of the list... + def GetListCtrl(self): + """Returt list""" + return self - # def OnGetItemText(self, item, col): - # index=self.itemIndexMap[item] - # s = self.itemDataMap[index][col] - # return s +# def OnGetItemText(self, item, col): +# """Get item text""" +# index=self.itemIndexMap[item] +# s = self.itemDataMap[index][col] +# return s + +# def OnGetItemImage(self, item): +# """Get item image""" +# return self.OnGetItemAttr(item) - # def OnGetItemImage(self, item): - # index=self.itemIndexMap[item] - # if ( index % 2) == 0: +# def OnGetItemAttr(self, item): +# """Get item attributes""" +# index = self.itemIndexMap[item] + +# if ( index % 2) == 0: +# return self.attr2 +# else: +# return self.attr1 - def OnGetItemAttr(self, item): - """Get item attributes""" - index = self.itemIndexMap[item] +# def SortItems(self, sorter=cmp): +# """Sort items""" +# items = list(self.itemDataMap.keys()) +# for i in range(len(items)): +# items[i] = self.columns[0]["type"](items[i]) # FIXME +# items.sort(self.Sorter) +# items.sort(sorter) +# for i in range(len(items)): +# items[i] = str(items[i]) +# self.itemIndexMap = items - if ( index % 2) == 0: - return self.attr2 - else: - return self.attr1 +# # redraw the list +# self.Refresh() - # --------------------------------------------------- - # Matt C, 2006/02/22 - # Here's a better SortItems() method -- - # the ColumnSorterMixin.__ColumnSorter() method already handles the ascending/descending, - # and it knows to sort on another column if the chosen columns have the same value. +# # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py - # def SortItems(self,sorter=cmp): - # items = list(self.itemDataMap.keys()) - # # for i in range(len(items)): - # # items[i] = self.columns[self.columnNumber]["type"](items[i]) - # items.sort(self.Sorter) - # #items.sort(sorter) - # # for i in range(len(items)): - # # items[i] = str(items[i]) - # self.itemIndexMap = items - # # redraw the list - # self.Refresh() - - # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py - - def GetListCtrl(self): - """Get list, required by VirtualAttributeList class""" - return self - - # stolen from python2.4/site-packages/wx-2.8-gtk2-unicode/wx/lib/mixins/listctrl.py - # def Sorter(self, key1,key2): - # col = self._col - # ascending = self._colSortFlag[col] - # # convert, because the it is allways string - # try: - # item1 = self.columns[col]["type"](self.itemDataMap[key1][col]) - # except: - # item1 = '' - # try: - # item2 = self.columns[col]["type"](self.itemDataMap[key2][col]) - # except: - # item2 = '' +# def Sorter(self, key1, key2): +# col = self._col +# ascending = self._colSortFlag[col] +# # convert, because the it is allways string +# try: +# item1 = self.columns[col]["type"](self.itemDataMap[key1][col]) +# except: +# item1 = '' +# try: +# item2 = self.columns[col]["type"](self.itemDataMap[key2][col]) +# except: +# item2 = '' - # #--- Internationalization of string sorting with locale module - # if type(item1) == type('') or type(item2) == type(''): - # cmpVal = locale.strcoll(str(item1), str(item2)) - # else: - # cmpVal = cmp(item1, item2) - # #--- +# # Internationalization of string sorting with locale module +# if type(item1) == type('') or type(item2) == type(''): +# cmpVal = locale.strcoll(str(item1), str(item2)) +# else: +# cmpVal = cmp(item1, item2) - # # If the items are equal then pick something else to make the sort v ->alue unique - # if cmpVal == 0: - # cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) +# # If the items are equal then pick something else to make the sort v ->alue unique +# if cmpVal == 0: +# cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) + +# if ascending: +# return cmpVal +# else: +# return -cmpVal - # if ascending: - # return cmpVal - # else: - # return -cmpVal +# return cmp(self.columns[0]["type"](item1), # FIXME +# self.columns[0]["type"](item2)) - # return cmp(self.columns[self.columnNumber]["type"](a), - # self.columns[self.columnNumber]["type"](b)) - - # # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py - # def GetSortImages(self): - # return (self.sm_dn, self.sm_up) +# def GetSortImages(self): +# return (self.sm_dn, self.sm_up) - # XXX Looks okay to remove this one (was present in the original demo) - # def getColumnText(self, index, col): - # item = self.GetItem(index, col) - # return item.GetText() +# def getColumnText(self, index, col): +# """Get column heading""" +# item = self.GetItem(index, col) +# return item.GetText() def OnMapClick(self, event): """ @@ -559,12 +567,15 @@ label=_("Advanced")) # textarea - self.sqlWhere = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="") - self.sqlStatement = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="") + self.sqlWhere = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", + style=wx.TE_PROCESS_ENTER) + self.sqlStatement = wx.TextCtrl(parent=self, id=wx.ID_ANY, + value="SELECT * FROM %s" % self.tablename, + style=wx.TE_PROCESS_ENTER) # labels self.sqlLabel = wx.StaticText(parent=self, id=wx.ID_ANY, - label="SELECT * FROM %s WHERE " % self.tablename) + label="SELECT * FROM %s WHERE " % self.tablename) self.label_query = wx.StaticText(parent=self, id=wx.ID_ANY, label="") @@ -584,16 +595,86 @@ # bindings self.btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder) + self.btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement) self.btnQuit.Bind(wx.EVT_BUTTON, self.OnCloseWindow) self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnInfoPaneChanged, self.infoCollapse) + self.sqlSimple.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql) + self.sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql) + self.sqlWhere.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement) + self.sqlStatement.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement) # do layer self.__layout() + self.OnChangeSql(None) + self.SetMinSize((640, 480)) self.Show() + def OnChangeSql(self, event): + """Switch simple/advanced sql statement""" + if self.sqlSimple.GetValue(): + self.sqlWhere.Enable(True) + self.sqlStatement.Enable(False) + self.btnSqlBuilder.Enable(False) + else: + self.sqlWhere.Enable(False) + self.sqlStatement.Enable(True) + self.btnSqlBuilder.Enable(True) + + def OnApplySqlStatement(self, event): + """Apply simple/advanced sql statement""" + if self.sqlSimple.GetValue(): + # simple sql statement + if len(self.sqlWhere.GetValue().strip()) > 0: + self.win.LoadData(where=self.sqlWhere.GetValue().strip()) + else: + self.win.LoadData() + else: + # advanced sql statement + valid, cols, where = self.ValidateSelectStatement(self.sqlStatement.GetValue().strip()) + + Debug.msg(4, "AttributeManager.OnApplySqlStatament(): valid=%s, cols=%s, where=%s" % + (valid, cols, where)) + + if valid is True: + self.win.LoadData(cols=cols, where=where) + + def ValidateSelectStatement(self, statement): + """Validate Select SQL statement + + TODO: check list of columns and where statement + + Return True if valid, False if not + Return list of columns (or '*' for all columns) + Return where statement + """ + + if statement[0:7].lower() != 'select ': + return (False, '', '') + + cols = '' + index = 7 + for c in statement[index:]: + if c == ' ': + break + cols += c + index += 1 + + tablelen = len(self.tablename) + + if statement[index+1:index+6].lower() != 'from ' or \ + statement[index+6:index+6+tablelen] != '%s' % (self.tablename): + return (False, '', '') + + if len(statement[index+7+tablelen:]) > 0: + where = statement[index+7+tablelen:] + else: + where = '' + + return (True, cols, where) + def OnInfoPaneChanged(self, event): """Collapse database connection info box""" @@ -651,11 +732,6 @@ self.builder = sqlbuilder.SQLFrame(parent=self, id=wx.ID_ANY, title=_("SQL Builder"), vectmap=self.vectmap) - - def OnApply(self,event): - """Apply button pressed""" - self.win.LoadData(where=self.text_query.GetValue().strip()) - def OnTextEnter(self, event): pass From landa at grass.itc.it Tue Oct 30 20:57:13 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 30 20:57:16 2007 Subject: [grass-addons] r1170 - trunk/grassaddons/gui/gui_modules Message-ID: <200710301957.l9UJvDbK031464@grass.itc.it> Author: landa Date: 2007-10-30 20:57:03 +0100 (Tue, 30 Oct 2007) New Revision: 1170 Modified: trunk/grassaddons/gui/gui_modules/dbm.py Log: Bugfix + minor cleaning. Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-30 15:36:36 UTC (rev 1169) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-30 19:57:03 UTC (rev 1170) @@ -148,8 +148,8 @@ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self) self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self) + # self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self) # self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) - self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self) # self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) # self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) # self.Bind(wx.EVT_LIST_COL_DRAGGING, self.OnColDragging, self.list) @@ -247,23 +247,21 @@ if self.qlayer: self.map.DeleteLayer(self.qlayer) - def OnColClick(self, event): - """Column heading clicked""" - # self._col = event.GetColumn() - event.Skip() - def OnItemSelected(self, event): """Item selected""" - self.currentItem = event.m_itemIndex - # self.log.write('OnItemSelected: "%s", "%s"\n' % - # (self.currentItem, - # self.GetItemText(self.currentItem))) + self.selectedCats.append(int(self.GetItemText(event.m_itemIndex))) + self.selectedCats.sort() - self.selectedCats.append(int(self.GetItemText(self.currentItem))) + event.Skip() + + def OnItemDeselected(self, event): + """Item deselected""" + self.selectedCats.remove(int(self.GetItemText(event.m_itemIndex))) self.selectedCats.sort() event.Skip() + def RedrawMap(self): """Redraw a map""" if self.lastTurnSelectedCats[:] != self.selectedCats[:]: @@ -333,13 +331,6 @@ item = self.GetItem(index, col) return item.GetText() - def OnItemDeselected(self, event): - """Item deselected""" - #self.log.write("OnItemDeselected: %s" % event.m_itemIndex) - self.selectedCats.remove(int(self.GetItemText(event.m_itemIndex))) - self.selectedCats.sort() - event.Skip() - def GetListCtrl(self): """Returt list""" return self @@ -1122,7 +1113,7 @@ delimiter = wx.StaticText(parent=panel, id=wx.ID_ANY, label=":") colValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value=value, - size=(250, -1)) # TODO: validator + size=(-1, -1)) # TODO: validator colValue.SetName(name) self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue) @@ -1145,6 +1136,8 @@ panel.SetSizer(border) # for each layer END + self.Layout() + return True class VectorAttributeInfo: @@ -1172,7 +1165,7 @@ return False # list of available layers & (table, database, driver) - for line in layerCommand.ReadStdOutput()[0]: + for line in layerCommand.ReadStdOutput(): lineList = line.split(' ') self.layers[int(lineList[0])] = { "table" : lineList[1], "database" : lineList[3], From landa at grass.itc.it Tue Oct 30 23:14:31 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Tue Oct 30 23:14:32 2007 Subject: [grass-addons] r1171 - trunk/grassaddons/gui/display_driver Message-ID: <200710302214.l9UMEVOS000436@grass.itc.it> Author: landa Date: 2007-10-30 23:14:17 +0100 (Tue, 30 Oct 2007) New Revision: 1171 Modified: trunk/grassaddons/gui/display_driver/pseudodc.cpp trunk/grassaddons/gui/display_driver/pseudodc.h Log: Upgraded to 2.8.6.1 (both file need to be removed in the future) Modified: trunk/grassaddons/gui/display_driver/pseudodc.cpp =================================================================== --- trunk/grassaddons/gui/display_driver/pseudodc.cpp 2007-10-30 19:57:03 UTC (rev 1170) +++ trunk/grassaddons/gui/display_driver/pseudodc.cpp 2007-10-30 22:14:17 UTC (rev 1171) @@ -4,7 +4,7 @@ // Author: Paul Lanier // Modified by: // Created: 05/25/06 -// RCS-ID: $Id: pseudodc.cpp 42187 2006-10-21 01:22:11Z RD $ +// RCS-ID: $Id: pseudodc.cpp 49047 2007-10-05 18:08:39Z RD $ // Copyright: (c) wxWidgets team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -303,8 +303,10 @@ void wxPseudoDC::RemoveAll(void) { m_objectlist.Clear(); + m_objectIndex.clear(); m_currId = -1; - m_lastObjNode = NULL; + m_lastObject = NULL; + } // ---------------------------------------------------------------------------- @@ -323,37 +325,30 @@ } // ---------------------------------------------------------------------------- -// FindObjNode - find and return an object node by id. If node doesn't exist +// FindObject - find and return an object node by id. If node doesn't exist // and create is true then create one and return it. Otherwise // return NULL. // ---------------------------------------------------------------------------- -pdcObjectList::Node *wxPseudoDC::FindObjNode(int id, bool create) +pdcObject *wxPseudoDC::FindObject(int id, bool create) { // see if last operation was for same id - if (m_lastObjNode && m_lastObjNode->GetData()->GetId() == id) - return m_lastObjNode; - // if not then search for it - pdcObjectList::Node *pt = m_objectlist.GetFirst(); - while (pt) - { - if (pt->GetData()->GetId() == id) - { - - // cache this node for future operations - m_lastObjNode = pt; - return pt; + //~ if (m_lastObject && m_lastObject->GetId() == id) + //~ return m_lastObject; + // if not then search for it + pdcObjectHash::iterator lookup = m_objectIndex.find(id); + if (lookup == m_objectIndex.end()) {//not found + if (create) { + m_lastObject = new pdcObject(id); + m_objectlist.Append(m_lastObject); + pdcObjectHash::value_type insert(id, m_lastObject); + m_objectIndex.insert(insert); + return m_lastObject; + } else { + return NULL; } - pt = pt->GetNext(); + } else { //found + return lookup->second; } - // if create then create and return a new node - if (create) - { - // cache this node for future operations - m_lastObjNode = m_objectlist.Append(new pdcObject(id)); - return m_lastObjNode; - } - // otherwise just return NULL - return NULL; } // ---------------------------------------------------------------------------- @@ -361,8 +356,8 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::AddToList(pdcOp *newOp) { - pdcObjectList::Node *pt = FindObjNode(m_currId, true); - pt->GetData()->AddOp(newOp); + pdcObject *obj = FindObject(m_currId, true); + obj->AddOp(newOp); } // ---------------------------------------------------------------------------- @@ -370,8 +365,8 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::ClearId(int id) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt) pt->GetData()->Clear(); + pdcObject *obj = FindObject(id); + if (obj) obj->Clear(); } // ---------------------------------------------------------------------------- @@ -379,13 +374,14 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::RemoveId(int id) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt) + pdcObject *obj = FindObject(id); + if (obj) { - if (m_lastObjNode == pt) - m_lastObjNode = NULL; - m_objectlist.DeleteNode(pt); + if (m_lastObject == obj) + m_lastObject = obj; + m_objectlist.DeleteObject(obj); } + m_objectIndex.erase(id); } // ---------------------------------------------------------------------------- @@ -393,8 +389,8 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::SetIdBounds(int id, wxRect& rect) { - pdcObjectList::Node *pt = FindObjNode(id, true); - pt->GetData()->SetBounds(rect); + pdcObject *obj = FindObject(id, true); + obj->SetBounds(rect); } // ---------------------------------------------------------------------------- @@ -402,9 +398,9 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::GetIdBounds(int id, wxRect& rect) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt && pt->GetData()->IsBounded()) - rect = pt->GetData()->GetBounds(); + pdcObject *obj = FindObject(id); + if (obj && obj->IsBounded()) + rect = obj->GetBounds(); else rect.x = rect.y = rect.width = rect.height = 0; } @@ -414,8 +410,8 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::TranslateId(int id, wxCoord dx, wxCoord dy) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt) pt->GetData()->Translate(dx,dy); + pdcObject *obj = FindObject(id); + if (obj) obj->Translate(dx,dy); } // ---------------------------------------------------------------------------- @@ -423,8 +419,8 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::DrawIdToDC(int id, wxDC *dc) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt) pt->GetData()->DrawToDC(dc); + pdcObject *obj = FindObject(id); + if (obj) obj->DrawToDC(dc); } // ---------------------------------------------------------------------------- @@ -432,8 +428,8 @@ // ---------------------------------------------------------------------------- void wxPseudoDC::SetIdGreyedOut(int id, bool greyout) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt) pt->GetData()->SetGreyedOut(greyout); + pdcObject *obj = FindObject(id); + if (obj) obj->SetGreyedOut(greyout); } // ---------------------------------------------------------------------------- @@ -441,8 +437,8 @@ // ---------------------------------------------------------------------------- bool wxPseudoDC::GetIdGreyedOut(int id) { - pdcObjectList::Node *pt = FindObjNode(id); - if (pt) return pt->GetData()->GetGreyedOut(); + pdcObject *obj = FindObject(id); + if (obj) return obj->GetGreyedOut(); else return false; } @@ -635,3 +631,4 @@ pt = pt->GetNext(); } } + Modified: trunk/grassaddons/gui/display_driver/pseudodc.h =================================================================== --- trunk/grassaddons/gui/display_driver/pseudodc.h 2007-10-30 19:57:03 UTC (rev 1170) +++ trunk/grassaddons/gui/display_driver/pseudodc.h 2007-10-30 22:14:17 UTC (rev 1171) @@ -4,7 +4,7 @@ // Author: Paul Lanier // Modified by: // Created: 05/25/06 -// RCS-ID: $Id: pseudodc.h,v 1.5 2006/10/11 04:01:29 RD Exp $ +// RCS-ID: $Id: pseudodc.h 49047 2007-10-05 18:08:39Z RD $ // Copyright: (c) wxWidgets team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -552,7 +552,16 @@ class pdcObjectList; WX_DECLARE_LIST(pdcObject, pdcObjectList); +//Declare a hashmap that maps from ids to nodes in the object list. +WX_DECLARE_HASH_MAP( + int, + pdcObject *, + wxIntegerHash, + wxIntegerEqual, + pdcObjectHash +); + // ---------------------------------------------------------------------------- // wxPseudoDC class // ---------------------------------------------------------------------------- @@ -566,7 +575,7 @@ { public: wxPseudoDC() - {m_currId=-1; m_lastObjNode=NULL; m_objectlist.DeleteContents(true);} + {m_currId=-1; m_lastObject=NULL; m_objectlist.DeleteContents(true);m_objectIndex.clear();} ~wxPseudoDC(); // ------------------------------------------------------------------------ // List managment methods @@ -800,14 +809,16 @@ // ------------------------------------------------------------------------ // protected helper methods void AddToList(pdcOp *newOp); - pdcObjectList::Node *FindObjNode(int id, bool create=false); + pdcObject *FindObject(int id, bool create=false); // ------------------------------------------------------------------------ // Data members // int m_currId; // id to use for operations done on the PseudoDC - pdcObjectList::Node *m_lastObjNode; // used to find last used object quickly + pdcObject *m_lastObject; // used to find last used object quickly pdcObjectList m_objectlist; // list of objects + pdcObjectHash m_objectIndex; //id->object lookup index + }; #endif From landa at grass.itc.it Wed Oct 31 09:03:39 2007 From: landa at grass.itc.it (landa@grass.itc.it) Date: Wed Oct 31 09:04:04 2007 Subject: [grass-addons] r1172 - trunk/grassaddons/gui/gui_modules Message-ID: <200710310803.l9V83dqT007289@grass.itc.it> Author: landa Date: 2007-10-31 09:01:57 +0100 (Wed, 31 Oct 2007) New Revision: 1172 Modified: trunk/grassaddons/gui/gui_modules/dbm.py Log: Virtual list re-enabled Modified: trunk/grassaddons/gui/gui_modules/dbm.py =================================================================== --- trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-30 22:14:17 UTC (rev 1171) +++ trunk/grassaddons/gui/gui_modules/dbm.py 2007-10-31 08:01:57 UTC (rev 1172) @@ -59,7 +59,7 @@ """ def __init__(self, parent, log, vectmap, pointdata=None): wx.ListCtrl.__init__( self, parent=parent, id=wx.ID_ANY, - style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES) # | wx.LC_VIRTUAL) + style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.LC_VIRTUAL) # # initialize variables @@ -119,13 +119,13 @@ column.strip() # FIXME: here will be more types if type.lower().find("integer") > -1: - self.columns.append({"name": column, "type": int}) + self.columns.append({"name": column, "type": int, "length" : int(length)}) elif type.lower().find("double") > -1: - self.columns.append({"name": column, "type": float}) + self.columns.append({"name": column, "type": float, "length" : int(length)}) elif type.lower().find("float") > -1: - self.columns.append({"name": column, "type": float}) + self.columns.append({"name": column, "type": float, "length" : int(length)}) else: - self.columns.append({"name": column, "type": str}) + self.columns.append({"name": column, "type": str, "length" : int(length)}) # These two should probably be passed to init more cleanly # setting the numbers of items = number of elements in the dictionary @@ -148,7 +148,7 @@ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self) self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self) - # self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self) + self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick, self) # sorting # self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) # self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) # self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) @@ -202,7 +202,6 @@ "database=%s" % self.parent.database, "driver=%s" % self.parent.driver] - # run command vDbSelect = gcmd.Command(cmd=cmdv) @@ -237,10 +236,10 @@ self.log.write(_("Can display only 32000 lines")) break + self.SetItemCount(i) + for i in range(self.GetColumnCount()): - self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE) - if self.GetColumnWidth(col=i) < 20: - self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE_USEHEADER) + self.SetColumnWidth(col=i, width=self.columns[i]['length'] * 6) # FIXME def OnCloseWindow(self, event): """Close attribute manager window""" @@ -255,13 +254,99 @@ event.Skip() def OnItemDeselected(self, event): + """Item deselected""" self.selectedCats.remove(int(self.GetItemText(event.m_itemIndex))) self.selectedCats.sort() event.Skip() + def OnItemActivated(self, event): + """Item activated""" + self.currentItem = event.m_itemIndex + self.log.write("OnItemActivated: %s\nTopItem: %s\n" % + (self.GetItemText(self.currentItem), self.GetTopItem())) + event.Skip() + def GetColumnText(self, index, col): + """Return column text""" + item = self.GetItem(index, col) + return item.GetText() + + def GetListCtrl(self): + """Returt list""" + return self + + def OnGetItemText(self, item, col): + """Get item text""" + index = self.itemIndexMap[item] + s = self.itemDataMap[index][col] + return s + + def OnGetItemAttr(self, item): + """Get item attributes""" + index = self.itemIndexMap[item] + + if ( index % 2) == 0: + return self.attr2 + else: + return self.attr1 + + def OnColumnClick(self, event): + """Column heading clicked -> sorting""" + self._col = event.GetColumn() + event.Skip() + + def SortItems(self, sorter=cmp): + """Sort items""" + items = list(self.itemDataMap.keys()) + # for i in range(len(items)): + # items[i] = self.columns[0]["type"](items[i]) # FIXME + items.sort(self.Sorter) + # for i in range(len(items)): + # items[i] = str(items[i]) + self.itemIndexMap = items + + # redraw the list + self.Refresh() + + def Sorter(self, key1, key2): + col = self._col + ascending = self._colSortFlag[col] + # convert always string + try: + item1 = self.columns[col]["type"](self.itemDataMap[key1][col]) + except: + item1 = '' + try: + item2 = self.columns[col]["type"](self.itemDataMap[key2][col]) + except: + item2 = '' + + if type(item1) == type('') or type(item2) == type(''): + cmpVal = locale.strcoll(str(item1), str(item2)) + else: + cmpVal = cmp(item1, item2) + + + # If the items are equal then pick something else to make the sort v ->alue unique + if cmpVal == 0: + cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) + + if ascending: + return cmpVal + else: + return -cmpVal + + def GetSortImages(self): + """Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py""" + return (self.sm_dn, self.sm_up) + + def getColumnText(self, index, col): + """Get column/item""" + item = self.GetItem(index, col) + return item.GetText() + def RedrawMap(self): """Redraw a map""" if self.lastTurnSelectedCats[:] != self.selectedCats[:]: @@ -319,97 +404,6 @@ self.mapdisp.ReDraw(None) self.lastTurnSelectedCats = self.selectedCats[:] - def OnItemActivated(self, event): - """Item activated""" - self.currentItem = event.m_itemIndex - self.log.write("OnItemActivated: %s\nTopItem: %s\n" % - (self.GetItemText(self.currentItem), self.GetTopItem())) - event.Skip() - - def GetColumnText(self, index, col): - """Return column text""" - item = self.GetItem(index, col) - return item.GetText() - - def GetListCtrl(self): - """Returt list""" - return self - -# def OnGetItemText(self, item, col): -# """Get item text""" -# index=self.itemIndexMap[item] -# s = self.itemDataMap[index][col] -# return s - -# def OnGetItemImage(self, item): -# """Get item image""" -# return self.OnGetItemAttr(item) - -# def OnGetItemAttr(self, item): -# """Get item attributes""" -# index = self.itemIndexMap[item] - -# if ( index % 2) == 0: -# return self.attr2 -# else: -# return self.attr1 - -# def SortItems(self, sorter=cmp): -# """Sort items""" -# items = list(self.itemDataMap.keys()) -# for i in range(len(items)): -# items[i] = self.columns[0]["type"](items[i]) # FIXME -# items.sort(self.Sorter) -# items.sort(sorter) -# for i in range(len(items)): -# items[i] = str(items[i]) -# self.itemIndexMap = items - -# # redraw the list -# self.Refresh() - -# # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py - - -# def Sorter(self, key1, key2): -# col = self._col -# ascending = self._colSortFlag[col] -# # convert, because the it is allways string -# try: -# item1 = self.columns[col]["type"](self.itemDataMap[key1][col]) -# except: -# item1 = '' -# try: -# item2 = self.columns[col]["type"](self.itemDataMap[key2][col]) -# except: -# item2 = '' - -# # Internationalization of string sorting with locale module -# if type(item1) == type('') or type(item2) == type(''): -# cmpVal = locale.strcoll(str(item1), str(item2)) -# else: -# cmpVal = cmp(item1, item2) - -# # If the items are equal then pick something else to make the sort v ->alue unique -# if cmpVal == 0: -# cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) - -# if ascending: -# return cmpVal -# else: -# return -cmpVal - -# return cmp(self.columns[0]["type"](item1), # FIXME -# self.columns[0]["type"](item2)) - -# def GetSortImages(self): -# return (self.sm_dn, self.sm_up) - -# def getColumnText(self, index, col): -# """Get column heading""" -# item = self.GetItem(index, col) -# return item.GetText() - def OnMapClick(self, event): """ Gets coordinates from mouse clicking on display window