2 @package modules::mcalc_builder
4 @brief Map calculator, GUI wrapper for r.mapcalc
7 - mcalc_builder::MapCalcFrame
9 (C) 2008, 2011 by the GRASS Development Team
11 This program is free software under the GNU General Public License
12 (>=v2). Read the file COPYING that comes with GRASS for details.
14 @author Michael Barton, Arizona State University
15 @author Martin Landa <landa.martin gmail.com>
16 @author Tim Michelsen (load/save expression)
23 if __name__ ==
"__main__":
24 sys.path.append(os.path.join(os.getenv(
'GISBASE'),
'etc',
'wxpython'))
25 from core
import globalvar
36 """!Mapcalc Frame class. Calculator-style window to create and run
37 r(3).mapcalc statements.
39 def __init__(self, parent, cmd, id = wx.ID_ANY,
40 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, **kwargs):
43 self.
log = self.parent.GetLogWindow()
50 if self.
cmd ==
'r.mapcalc':
52 title = _(
'GRASS GIS Raster Map Calculator')
53 if self.
cmd ==
'r3.mapcalc':
55 title = _(
'GRASS GIS 3D Raster Map Calculator')
57 wx.Frame.__init__(self, parent, id = id, title = title, **kwargs)
58 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
60 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
61 self.CreateStatusBar()
72 'atan(x,y)':
'atan( , )',
74 'double(x)':
'double()',
75 'eval([x,y,...,]z)':
'eval()',
77 'exp(x,y)':
'exp( , )',
79 'graph(x,x1,y1[x2,y2..])':
'graph( , , )',
82 'if(x,a,b)':
'if( , , )',
83 'if(x,a,b,c)':
'if( , , , )',
85 'isnull(x)':
'isnull()',
87 'log(x,b)':
'log( , )',
88 'max(x,y[,z...])':
'max( , )',
89 'median(x,y[,z...])':
'median( , )',
90 'min(x,y[,z...])':
'min( , )',
91 'mode(x,y[,z...])':
'mode( , )',
93 'pow(x,y)':
'pow( , )',
94 'rand(a,b)':
'rand( , )',
99 'xor(x,y)':
'xor( , )',
122 label=
" %s " % _(
'Operators'))
124 label=
" %s " % _(
'Operands'))
126 label=
" %s " % _(
'Expression'))
133 self.
btn_run = wx.Button(parent = self.
panel, id = wx.ID_ANY, label = _(
"&Run"))
134 self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
135 self.btn_run.SetDefault()
138 self.btn_save.SetToolTipString(_(
'Save expression to file'))
141 self.btn_load.SetToolTipString(_(
'Load expression from file'))
144 self.
btn[
'pow'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"^")
145 self.
btn[
'pow'].SetToolTipString(_(
'exponent'))
146 self.
btn[
'div'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"/")
147 self.
btn[
'div'].SetToolTipString(_(
'divide'))
148 self.
btn[
'add'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"+")
149 self.
btn[
'add'].SetToolTipString(_(
'add'))
150 self.
btn[
'minus'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"-")
151 self.
btn[
'minus'].SetToolTipString(_(
'subtract'))
152 self.
btn[
'mod'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"%")
153 self.
btn[
'mod'].SetToolTipString(_(
'modulus'))
154 self.
btn[
'mult'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"*")
155 self.
btn[
'mult'].SetToolTipString(_(
'multiply'))
157 self.
btn[
'parenl'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"(")
158 self.
btn[
'parenr'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
")")
159 self.
btn[
'lshift'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"<<")
160 self.
btn[
'lshift'].SetToolTipString(_(
'left shift'))
161 self.
btn[
'rshift'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">>")
162 self.
btn[
'rshift'].SetToolTipString(_(
'right shift'))
163 self.
btn[
'rshiftu'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">>>")
164 self.
btn[
'rshiftu'].SetToolTipString(_(
'right shift (unsigned)'))
165 self.
btn[
'gt'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">")
166 self.
btn[
'gt'].SetToolTipString(_(
'greater than'))
167 self.
btn[
'gteq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">=")
168 self.
btn[
'gteq'].SetToolTipString(_(
'greater than or equal to'))
169 self.
btn[
'lt'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"<")
170 self.
btn[
'lt'].SetToolTipString(_(
'less than'))
171 self.
btn[
'lteq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"<=")
172 self.
btn[
'lteq'].SetToolTipString(_(
'less than or equal to'))
173 self.
btn[
'eq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"==")
174 self.
btn[
'eq'].SetToolTipString(_(
'equal to'))
175 self.
btn[
'noteq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"!=")
176 self.
btn[
'noteq'].SetToolTipString(_(
'not equal to'))
178 self.
btn[
'compl'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"~")
179 self.
btn[
'compl'].SetToolTipString(_(
'one\'s complement'))
180 self.
btn[
'not'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"!")
181 self.
btn[
'not'].SetToolTipString(_(
'NOT'))
182 self.
btn[
'andbit'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
'&&')
183 self.
btn[
'andbit'].SetToolTipString(_(
'bitwise AND'))
184 self.
btn[
'orbit'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"|")
185 self.
btn[
'orbit'].SetToolTipString(_(
'bitwise OR'))
186 self.
btn[
'and'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"&&&&")
187 self.
btn[
'and'].SetToolTipString(_(
'logical AND'))
188 self.
btn[
'andnull'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"&&&&&&")
189 self.
btn[
'andnull'].SetToolTipString(_(
'logical AND (ignores NULLs)'))
190 self.
btn[
'or'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"||")
191 self.
btn[
'or'].SetToolTipString(_(
'logical OR'))
192 self.
btn[
'ornull'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"|||")
193 self.
btn[
'ornull'].SetToolTipString(_(
'logical OR (ignores NULLs)'))
194 self.
btn[
'cond'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"a ? b : c")
195 self.
btn[
'cond'].SetToolTipString(_(
'conditional'))
201 style = wx.TE_MULTILINE)
202 wx.CallAfter(self.text_mcalc.SetFocus)
208 self.newmaplabel.SetLabel(_(
'Name for new 3D raster map to create'))
210 self.newmaplabel.SetLabel(_(
'Name for new raster map to create'))
211 self.
newmaptxt = wx.TextCtrl(parent = self.
panel, id = wx.ID_ANY, size=(250, -1))
214 self.mapsellabel.SetLabel(_(
'Insert existing 3D raster map'))
216 self.mapsellabel.SetLabel(_(
'Insert existing raster map'))
218 type = element, multiple =
False)
220 label = _(
'Insert mapcalc function'))
222 size = (250, -1), choices = sorted(self.funct_dict.keys()),
223 style = wx.CB_DROPDOWN |
224 wx.CB_READONLY | wx.TE_PROCESS_ENTER)
227 label=_(
'Add created raster map into layer tree'), style = wx.NO_BORDER)
228 self.addbox.SetValue(UserSettings.Get(group=
'cmd', key=
'addNewLayer', subkey=
'enabled'))
229 if not self.
parent or self.parent.GetName() !=
'LayerManager':
235 for btn
in self.btn.keys():
236 self.
btn[btn].Bind(wx.EVT_BUTTON, self.
AddMark)
238 self.btn_close.Bind(wx.EVT_BUTTON, self.
OnClose)
239 self.btn_clear.Bind(wx.EVT_BUTTON, self.
OnClear)
240 self.btn_run.Bind(wx.EVT_BUTTON, self.
OnMCalcRun)
241 self.btn_help.Bind(wx.EVT_BUTTON, self.
OnHelp)
247 self.function.Bind(wx.EVT_TEXT_ENTER, self.
OnSelect)
253 self.SetMinSize(self.GetBestSize())
255 def _return_funct(self,event):
256 i = event.GetString()
260 sizer = wx.BoxSizer(wx.VERTICAL)
262 controlSizer = wx.BoxSizer(wx.HORIZONTAL)
263 operatorSizer = wx.StaticBoxSizer(self.
operatorBox, wx.HORIZONTAL)
265 buttonSizer1 = wx.GridBagSizer(5, 1)
266 buttonSizer1.Add(item = self.
btn[
'add'], pos = (0,0))
267 buttonSizer1.Add(item = self.
btn[
'minus'], pos = (0,1))
268 buttonSizer1.Add(item = self.
btn[
'mod'], pos = (5,0))
269 buttonSizer1.Add(item = self.
btn[
'mult'], pos = (1,0))
270 buttonSizer1.Add(item = self.
btn[
'div'], pos = (1,1))
271 buttonSizer1.Add(item = self.
btn[
'pow'], pos = (5,1))
272 buttonSizer1.Add(item = self.
btn[
'gt'], pos = (2,0))
273 buttonSizer1.Add(item = self.
btn[
'gteq'], pos = (2,1))
274 buttonSizer1.Add(item = self.
btn[
'eq'], pos = (4,0))
275 buttonSizer1.Add(item = self.
btn[
'lt'], pos = (3,0))
276 buttonSizer1.Add(item = self.
btn[
'lteq'], pos = (3,1))
277 buttonSizer1.Add(item = self.
btn[
'noteq'], pos = (4,1))
279 buttonSizer2 = wx.GridBagSizer(5, 1)
280 buttonSizer2.Add(item = self.
btn[
'and'], pos = (0,0))
281 buttonSizer2.Add(item = self.
btn[
'andbit'], pos = (1,0))
282 buttonSizer2.Add(item = self.
btn[
'andnull'], pos = (2,0))
283 buttonSizer2.Add(item = self.
btn[
'or'], pos = (0,1))
284 buttonSizer2.Add(item = self.
btn[
'orbit'], pos = (1,1))
285 buttonSizer2.Add(item = self.
btn[
'ornull'], pos = (2,1))
286 buttonSizer2.Add(item = self.
btn[
'lshift'], pos = (3,0))
287 buttonSizer2.Add(item = self.
btn[
'rshift'], pos = (3,1))
288 buttonSizer2.Add(item = self.
btn[
'rshiftu'], pos = (4,0))
289 buttonSizer2.Add(item = self.
btn[
'cond'], pos = (5,0))
290 buttonSizer2.Add(item = self.
btn[
'compl'], pos = (5,1))
291 buttonSizer2.Add(item = self.
btn[
'not'], pos = (4,1))
293 operandSizer = wx.StaticBoxSizer(self.
operandBox, wx.HORIZONTAL)
294 buttonSizer3 = wx.GridBagSizer(7, 1)
295 buttonSizer3.Add(item = self.
newmaplabel, pos = (0,0),
296 span = (1, 2), flag = wx.ALIGN_CENTER)
297 buttonSizer3.Add(item = self.
newmaptxt, pos = (1,0),
299 buttonSizer3.Add(item = self.
functlabel, pos = (2,0),
300 span = (1,2), flag = wx.ALIGN_CENTER)
301 buttonSizer3.Add(item = self.
function, pos = (3,0),
303 buttonSizer3.Add(item = self.
mapsellabel, pos = (4,0),
304 span = (1,2), flag = wx.ALIGN_CENTER)
305 buttonSizer3.Add(item = self.
mapselect, pos = (5,0),
307 threebutton = wx.GridBagSizer(1, 2)
308 threebutton.Add(item = self.
btn[
'parenl'], pos = (0,0),
309 span = (1,1), flag = wx.ALIGN_LEFT)
310 threebutton.Add(item = self.
btn[
'parenr'], pos = (0,1),
311 span = (1,1), flag = wx.ALIGN_CENTER)
312 threebutton.Add(item = self.
btn_clear, pos = (0,2),
313 span = (1,1), flag = wx.ALIGN_RIGHT)
314 buttonSizer3.Add(item = threebutton, pos = (6,0),
315 span = (1,1), flag = wx.ALIGN_CENTER)
317 buttonSizer4 = wx.BoxSizer(wx.HORIZONTAL)
318 buttonSizer4.AddSpacer(10)
319 buttonSizer4.Add(item = self.
btn_load,
320 flag = wx.ALL, border = 5)
321 buttonSizer4.Add(item = self.
btn_save,
322 flag = wx.ALL, border = 5)
323 buttonSizer4.AddSpacer(30)
324 buttonSizer4.Add(item = self.
btn_help,
325 flag = wx.ALL, border = 5)
326 buttonSizer4.Add(item = self.
btn_run,
327 flag = wx.ALL, border = 5)
329 flag = wx.ALL, border = 5)
331 operatorSizer.Add(item = buttonSizer1, proportion = 0,
332 flag = wx.ALL | wx.EXPAND, border = 5)
333 operatorSizer.Add(item = buttonSizer2, proportion = 0,
334 flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND, border = 5)
336 operandSizer.Add(item = buttonSizer3, proportion = 0,
337 flag = wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
339 controlSizer.Add(item = operatorSizer, proportion = 1,
340 flag = wx.RIGHT | wx.EXPAND, border = 5)
341 controlSizer.Add(item = operandSizer, proportion = 0,
344 expressSizer = wx.StaticBoxSizer(self.
expressBox, wx.HORIZONTAL)
345 expressSizer.Add(item = self.
text_mcalc, proportion = 1,
348 sizer.Add(item = controlSizer, proportion = 0,
349 flag = wx.EXPAND | wx.ALL,
351 sizer.Add(item = expressSizer, proportion = 1,
352 flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
354 sizer.Add(item = buttonSizer4, proportion = 0,
355 flag = wx.ALIGN_RIGHT | wx.ALL, border = 3)
356 if self.addbox.IsShown():
357 sizer.Add(item = self.
addbox, proportion = 0,
358 flag = wx.LEFT | wx.RIGHT,
361 self.panel.SetAutoLayout(
True)
362 self.panel.SetSizer(sizer)
363 sizer.Fit(self.
panel)
368 """!Sends operators to insertion method
370 if event.GetId() == self.
btn[
'compl'].GetId(): mark =
"~"
371 elif event.GetId() == self.
btn[
'not'].GetId(): mark =
"!"
372 elif event.GetId() == self.
btn[
'pow'].GetId(): mark =
"^"
373 elif event.GetId() == self.
btn[
'div'].GetId(): mark =
"/"
374 elif event.GetId() == self.
btn[
'add'].GetId(): mark =
"+"
375 elif event.GetId() == self.
btn[
'minus'].GetId(): mark =
"-"
376 elif event.GetId() == self.
btn[
'mod'].GetId(): mark =
"%"
377 elif event.GetId() == self.
btn[
'mult'].GetId(): mark =
"*"
378 elif event.GetId() == self.
btn[
'lshift'].GetId(): mark =
"<<"
379 elif event.GetId() == self.
btn[
'rshift'].GetId(): mark =
">>"
380 elif event.GetId() == self.
btn[
'rshiftu'].GetId(): mark =
">>>"
381 elif event.GetId() == self.
btn[
'gt'].GetId(): mark =
">"
382 elif event.GetId() == self.
btn[
'gteq'].GetId(): mark =
">="
383 elif event.GetId() == self.
btn[
'lt'].GetId(): mark =
"<"
384 elif event.GetId() == self.
btn[
'lteq'].GetId(): mark =
"<="
385 elif event.GetId() == self.
btn[
'eq'].GetId(): mark =
"=="
386 elif event.GetId() == self.
btn[
'noteq'].GetId(): mark =
"!="
387 elif event.GetId() == self.
btn[
'andbit'].GetId(): mark =
"&"
388 elif event.GetId() == self.
btn[
'orbit'].GetId(): mark =
"|"
389 elif event.GetId() == self.
btn[
'or'].GetId(): mark =
"||"
390 elif event.GetId() == self.
btn[
'ornull'].GetId(): mark =
"|||"
391 elif event.GetId() == self.
btn[
'and'].GetId(): mark =
"&&"
392 elif event.GetId() == self.
btn[
'andnull'].GetId(): mark =
"&&&"
393 elif event.GetId() == self.
btn[
'cond'].GetId(): mark =
" ? : "
394 elif event.GetId() == self.
btn[
'parenl'].GetId(): mark =
"("
395 elif event.GetId() == self.
btn[
'parenr'].GetId(): mark =
")"
399 """!Checks if user is typing or the event was emited by map selection.
400 Prevents from changing focus.
402 item = event.GetString()
403 if not (abs(len(item) - len(self.
lastMapName)) == 1
and \
409 """!Gets raster map or function selection and send it to
412 Checks for characters which can be in raster map name but
413 the raster map name must be then quoted.
415 item = event.GetString().strip()
417 item =
'"' + item +
'"'
421 """!Update statusbar text"""
422 expr = self.text_mcalc.GetValue().strip().replace(
"\n",
" ")
426 self.SetStatusText(
"%s '%s = %s'" % (cmd, self.newmaptxt.GetValue(),
430 def _addSomething(self, what):
431 """!Inserts operators, map names, and functions into text area
433 self.text_mcalc.SetFocus()
434 mcalcstr = self.text_mcalc.GetValue()
435 position = self.text_mcalc.GetInsertionPoint()
437 newmcalcstr = mcalcstr[:position]
441 if newmcalcstr[-1] !=
' ':
447 newmcalcstr += what +
' ' + mcalcstr[position:]
449 self.text_mcalc.SetValue(newmcalcstr)
451 match = re.search(pattern=
"\(.*\)", string=what)
453 position_offset += match.start() + 1
455 position_offset += len(what)
457 self.text_mcalc.SetInsertionPoint(position + position_offset)
458 self.text_mcalc.Update()
461 """!Builds and runs r.mapcalc statement
463 name = self.newmaptxt.GetValue().strip()
465 GError(parent = self,
466 message = _(
"You must enter the name of "
467 "a new raster map to create."))
470 if not (name[0] ==
'"' and name[-1] ==
'"')
and any((char
in name)
for char
in self.
charactersToQuote):
471 name =
'"' + name +
'"'
473 expr = self.text_mcalc.GetValue().strip().replace(
"\n",
" ")
475 GError(parent = self,
476 message = _(
"You must enter an expression "
477 "to create a new raster map."))
481 cmd = [self.
cmd, str(
'%s = %s' % (name, expr))]
482 self.log.RunCmd(cmd, onDone = self.
OnDone)
489 """!Add create map to the layer tree"""
490 if not self.addbox.IsChecked():
492 name = self.newmaptxt.GetValue().strip(
' "') +
'@' + grass.gisenv()[
'MAPSET']
498 mapTree = self.parent.GetLayerTree()
499 if not mapTree.GetMap().GetListOfLayers(l_name = name):
500 mapTree.AddLayer(ltype = ltype,
502 lcmd = [lcmd,
'map=%s' % name],
505 display = self.parent.GetLayerTree().GetMapDisplay()
506 if display
and display.IsAutoRendered():
507 display.GetWindow().UpdateMap(render =
True)
510 """!Saves expression to file
512 mctxt = self.newmaptxt.GetValue() +
' = ' + self.text_mcalc.GetValue() + os.linesep
515 dlg = wx.FileDialog(parent = self,
516 message = _(
"Choose a file name to save the expression"),
517 wildcard = _(
"Expression file (*)|*"),
518 style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
519 if dlg.ShowModal() == wx.ID_OK:
526 fobj = open(path,
'w')
534 """!Load expression from file
536 dlg = wx.FileDialog(parent = self,
537 message = _(
"Choose a file name to load the expression"),
538 wildcard = _(
"Expression file (*)|*"),
540 if dlg.ShowModal() == wx.ID_OK:
547 fobj = open(path,
'r')
553 result, exp = mctxt.split(
'=', 1)
558 self.newmaptxt.SetValue(result.strip())
559 self.text_mcalc.SetValue(exp.strip())
560 self.text_mcalc.SetFocus()
561 self.text_mcalc.SetInsertionPointEnd()
568 self.text_mcalc.SetValue(
'')
571 """!Launches r.mapcalc help
579 if __name__ ==
"__main__":
581 gettext.install(
'grasswxpy', os.path.join(os.getenv(
"GISBASE"),
'locale'), unicode =
True)
def AddMark(self, event)
Sends operators to insertion method.
def OnUpdateStatusBar(self, event)
Update statusbar text.
def OnClose(self, event)
Close window.
def OnSelectTextEvt(self, event)
Checks if user is typing or the event was emited by map selection.
def OnLoadExpression(self, event)
Load expression from file.
def OnHelp(self, event)
Launches r.mapcalc help.
def __init__(self, parent, cmd, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER, kwargs)
Custom control that selects elements.
def _return_funct(self, event)
def OnDone(self, cmd, returncode)
Add create map to the layer tree.
def OnClear(self, event)
Clears text area.
def OnSaveExpression(self, event)
Saves expression to file.
def _addSomething(self, what)
Inserts operators, map names, and functions into text area.
def RunCommand(prog, flags="", overwrite=False, quiet=False, verbose=False, parent=None, read=False, stdin=None, getErrorMsg=False, kwargs)
Run GRASS command.
def OnSelect(self, event)
Gets raster map or function selection and send it to insertion method.
def OnMCalcRun(self, event)
Builds and runs r.mapcalc statement.