[GRASS-SVN] r57817 - grass/trunk/gui/wxpython/vdigit
svn_grass at osgeo.org
svn_grass at osgeo.org
Mon Sep 23 07:06:11 PDT 2013
Author: turek
Date: 2013-09-23 07:06:11 -0700 (Mon, 23 Sep 2013)
New Revision: 57817
Modified:
grass/trunk/gui/wxpython/vdigit/toolbars.py
grass/trunk/gui/wxpython/vdigit/wxdigit.py
Log:
vdigit: signals used by scatter plot
Modified: grass/trunk/gui/wxpython/vdigit/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/toolbars.py 2013-09-23 03:59:28 UTC (rev 57816)
+++ grass/trunk/gui/wxpython/vdigit/toolbars.py 2013-09-23 14:06:11 UTC (rev 57817)
@@ -17,6 +17,7 @@
import wx
from grass.script import core as grass
+from grass.pydispatch.signal import Signal
from gui_core.toolbars import BaseToolbar, BaseIcons
from gui_core.dialogs import CreateNewVector
@@ -42,6 +43,8 @@
self.digit = None
self._giface = giface
+ self.editingStarted = Signal("VDigitToolbar.editingStarted")
+
# currently selected map layer for editing (reference to MapLayer instance)
self.mapLayer = None
# list of vector layers from Layer Manager (only in the current mapset)
@@ -860,6 +863,7 @@
alpha = int(opacity * 255)
self.digit.GetDisplay().UpdateSettings(alpha = alpha)
+ self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
return True
def StopEditing(self):
Modified: grass/trunk/gui/wxpython/vdigit/wxdigit.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/wxdigit.py 2013-09-23 03:59:28 UTC (rev 57816)
+++ grass/trunk/gui/wxpython/vdigit/wxdigit.py 2013-09-23 14:06:11 UTC (rev 57817)
@@ -17,7 +17,7 @@
(and NumPy would be an excellent candidate for acceleration via
e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
-(C) 2007-2011 by the GRASS Development Team
+(C) 2007-2011, 2013 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.
@@ -27,17 +27,19 @@
import grass.script.core as grass
-from core.gcmd import GError
-from core.debug import Debug
-from core.settings import UserSettings
+from grass.pydispatch.signal import Signal
+
+from core.gcmd import GError
+from core.debug import Debug
+from core.settings import UserSettings
from core.utils import _
from vdigit.wxdisplay import DisplayDriver, GetLastError
try:
- from grass.lib.gis import *
+ from grass.lib.gis import *
from grass.lib.vector import *
- from grass.lib.vedit import *
- from grass.lib.dbmi import *
+ from grass.lib.vedit import *
+ from grass.lib.dbmi import *
except ImportError:
pass
@@ -176,7 +178,40 @@
if self.poMapInfo:
self.InitCats()
+
+ self.emit_signals = False
+
+ # signals which describes features changes during digitization,
+ # activate them using EmitSignals method
+
+ # currently implemented for functionality used by wx.iclass (for scatter plot)
+ # signals parameter description:
+ # old_bboxs - list of bboxes of boundary features, which covers changed areas
+ # it is bbox of old state (before edit)
+ # old_areas_cats - list of area categories of boundary features of old state (before edit)
+ # same position in both lists corresponds to same feature
+
+ # new_bboxs = list of bboxes of created features / after edit
+ # new_areas_cats list of areas cats of created features / after edit
+ # same position in both lists corresponds to same features
+
+ # for description of items in bbox and area_cats lists see return value of _getaAreaBboxCats
+
+ # TODO currently it is not possible to identify corresponded features
+ # in old and new lists (requires changed to vector updated format)
+ # TODO return feature type
+
+ #TODO handle errors?
+ self.featureAdded = Signal('IVDigit.featureAdded')
+ self.areasDeleted = Signal('IVDigit.areasDeleted')
+ self.vertexMoved = Signal('IVDigit.vertexMoved')
+ self.vertexAdded = Signal('IVDigit.vertexAdded')
+ self.vertexRemoved = Signal('IVDigit.vertexRemoved')
+ self.featuresDeleted = Signal('IVDigit.featuresDeleted')
+ self.featuresMoved = Signal('IVDigit.featuresMoved')
+ self.lineEdited = Signal('IVDigit.lineEdited')
+
def __del__(self):
Debug.msg(1, "IVDigit.__del__()")
Vect_destroy_line_struct(self.poPoints)
@@ -188,7 +223,12 @@
Vect_close(self.poBgMapInfo)
self.poBgMapInfo = self.popoBgMapInfo = None
del self.bgMapInfo
-
+
+ def EmitSignals(self, emit):
+ """!Activate/deactivate signals which describes features changes during digitization.
+ """
+ self.emit_signals = emit
+
def CloseBackgroundMap(self):
"""!Close background vector map"""
if not self.poBgMapInfo:
@@ -394,7 +434,6 @@
@return tuple (number of added features, feature ids)
"""
-
layer = self._getNewFeaturesLayer()
cat = self._getNewFeaturesCat()
@@ -419,10 +458,15 @@
return (-1, None)
self.toolbar.EnableUndo()
-
- return self._addFeature(vtype, points, layer, cat,
- self._getSnapMode(), self._display.GetThreshold())
-
+
+ ret = self._addFeature(vtype, points, layer, cat,
+ self._getSnapMode(), self._display.GetThreshold())
+ if ret[0] > -1 and self.emit_signals:
+ self.featureAdded.emit(new_bboxs=[self._createBbox(points)],
+ new_areas_cats=[[{layer : [cat]}, None]])
+
+ return ret
+
def DeleteSelectedLines(self):
"""!Delete selected features
@@ -434,16 +478,27 @@
# collect categories for deleting if requested
deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
catDict = dict()
+
+ old_bboxs = []
+ old_areas_cats = []
if deleteRec:
for i in self._display.selected['ids']:
+
if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
self._error.ReadLine(i)
- cats = self.poCats.contents
- for j in range(cats.n_cats):
- if cats.field[j] not in catDict.keys():
- catDict[cats.field[j]] = list()
- catDict[cats.field[j]].append(cats.cat[j])
+ if self.emit_signals:
+ ret = self._getLineAreaBboxCats(i)
+ if ret:
+ old_bboxs += ret[0]
+ old_areas_cats += ret[1]
+
+ # catDict was not used -> put into comment
+ #cats = self.poCats.contents
+ #for j in range(cats.n_cats):
+ # if cats.field[j] not in catDict.keys():
+ # catDict[cats.field[j]] = list()
+ # catDict[cats.field[j]].append(cats.cat[j])
poList = self._display.GetSelectedIList()
nlines = Vedit_delete_lines(self.poMapInfo, poList)
@@ -456,7 +511,11 @@
self._deleteRecords(catDict)
self._addChangeset()
self.toolbar.EnableUndo()
-
+
+ if self.emit_signals:
+ self.featuresDeleted.emit(old_bboxs=old_bboxs,
+ old_areas_cats=old_areas_cats)
+
return nlines
def _deleteRecords(self, cats):
@@ -512,22 +571,220 @@
@return number of deleted
"""
+ if len(self._display.selected['ids']) < 1:
+ return 0
+
poList = self._display.GetSelectedIList()
cList = poList.contents
nareas = 0
+ old_bboxs = []
+ old_areas_cats = []
+
for i in range(cList.n_values):
+
if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
continue
-
+
+ if self.emit_signals:
+ area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
+ if area > 0:
+ bbox, cats = self._getaAreaBboxCats(area)
+ old_bboxs += bbox
+ old_areas_cats += cats
+
nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
if nareas > 0:
self._addChangeset()
self.toolbar.EnableUndo()
+ if self.emit_signals:
+ self.areasDeleted.emit(old_bboxs=old_bboxs,
+ old_areas_cats=old_areas_cats)
+
+ return nareas
+
+ def _getLineAreaBboxCats(self, ln_id):
+ """!Helper function
+
+ @param id of feature
+ @return None if the feature does not exists
+ @return list of @see _getaAreaBboxCats
+ """
+ ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
+
+ if ltype == GV_CENTROID:
+ #TODO centroid opttimization, can be edited also its area -> it will appear two times in new_ lists
+ return self._getCentroidAreaBboxCats(ln_id)
+ else:
+ return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)]
+
+
+ def _getCentroidAreaBboxCats(self, centroid):
+ """!Helper function
+
+ @param id of an centroid
+ @return None if area does not exists
+ @return see return of _getaAreaBboxCats
+ """
+ if not Vect_line_alive(self.poMapInfo, centroid):
+ return None
+
+ area = Vect_get_centroid_area(self.poMapInfo, centroid)
+ if area > 0:
+ return self._getaAreaBboxCats(area)
+ else:
+ return None
+
+ def _getaAreaBboxCats(self, area):
+ """!Helper function
+
+ @param area area id
+ @return list of categories @see _getLineAreasCategories and
+ list of bboxes @see _getBbox of area boundary features
+ """
+ po_b_list = Vect_new_list()
+ Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
+ b_list = po_b_list.contents
+
+ geoms = []
+ areas_cats = []
+
+ if b_list.n_values > 0:
+ for i_line in range(b_list.n_values):
+
+ line = b_list.value[i_line];
+
+ geoms.append(self._getBbox(abs(line)))
+ areas_cats.append(self._getLineAreasCategories(abs(line)))
- return nareas
+ Vect_destroy_list(po_b_list);
+
+ return geoms, areas_cats
+
+ def _getLineAreasCategories(self, ln_id):
+ """!Helper function
+
+ @param line_id id of boundary feature
+ @return categories of areas on the left, right side of the feature
+ @return format: [[{layer : [cat]}, None]] means:
+ area to the left (list of layers which has cats list as values),
+ area to the right (no area there in this case (None))
+ @return [] the feature is not boundary or does not exists
+ """
+ if not Vect_line_alive (self.poMapInfo, ln_id):
+ return []
+
+ ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
+ if ltype != GV_BOUNDARY:
+ return []
+
+ cats = [None, None]
+
+ left = c_int()
+ right = c_int()
+
+ if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
+ areas = [left.value, right.value]
+
+ for i, a in enumerate(areas):
+ if a > 0:
+ centroid = Vect_get_area_centroid(self.poMapInfo, a)
+ if centroid <= 0:
+ continue
+ c = self._getCategories(centroid)
+ if c:
+ cats[i] = c
+
+ return cats
+
+ def _getCategories(self, ln_id):
+ """!Helper function
+
+ @param line_id id of feature
+ @return list of the feature categories [{layer : cats}, next layer...]
+ @return None feature does not exist
+ """
+ if not Vect_line_alive (self.poMapInfo, ln_id):
+ return none
+
+ poCats = Vect_new_cats_struct()
+ if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
+ Vect_destroy_cats_struct(poCats)
+ return None
+
+ cCats = poCats.contents
+
+ cats = {}
+ for j in range(cCats.n_cats):
+ if cats.has_key(cCats.field[j]):
+ cats[cCats.field[j]].append(cCats.cat[j])
+ else:
+ cats[cCats.field[j]] = [cCats.cat[j]]
+ Vect_destroy_cats_struct(poCats)
+ return cats
+
+ def _getBbox(self, ln_id):
+ """!Helper function
+
+ @param line_id id of line feature
+ @return bbox bounding box of the feature
+ @return None feature does not exist
+ """
+ if not Vect_line_alive (self.poMapInfo, ln_id):
+ return None
+
+ poPoints = Vect_new_line_struct()
+ if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
+ Vect_destroy_line_struct(poPoints)
+ return []
+
+ geom = self._convertGeom(poPoints)
+ bbox = self._createBbox(geom)
+ Vect_destroy_line_struct(poPoints)
+ return bbox
+
+ def _createBbox(self, points):
+ """!Helper function
+
+ @param points list of points [(x, y), ...] to be bbox created for
+ @return bbox bounding box of points {'maxx':, 'maxy':, 'minx':, 'miny'}
+ """
+ bbox = {}
+ for pt in points:
+ if not bbox.has_key('maxy'):
+ bbox['maxy'] = pt[1]
+ bbox['miny'] = pt[1]
+ bbox['maxx'] = pt[0]
+ bbox['minx'] = pt[0]
+ continue
+
+ if bbox['maxy'] < pt[1]:
+ bbox['maxy'] = pt[1]
+ elif bbox['miny'] > pt[1]:
+ bbox['miny'] = pt[1]
+
+ if bbox['maxx'] < pt[0]:
+ bbox['maxx'] = pt[0]
+ elif bbox['minx'] > pt[0]:
+ bbox['minx'] = pt[0]
+ return bbox
+
+ def _convertGeom(self, poPoints):
+ """!Helper function
+ convert geom from ctypes line_pts to python list
+
+ @return coords in python list [(x, y),...]
+ """
+ Points = poPoints.contents
+
+ pts_geom = []
+ for j in range(Points.n_points):
+ pts_geom.append((Points.x[j], Points.y[j]))
+
+ return pts_geom
+
def MoveSelectedLines(self, move):
"""!Move selected features
@@ -536,16 +793,45 @@
if not self._checkMap():
return -1
+ nsel = len(self._display.selected['ids'])
+ if nsel < 1:
+ return -1
+
thresh = self._display.GetThreshold()
snap = self._getSnapMode()
poList = self._display.GetSelectedIList()
+
+ if self.emit_signals:
+ old_bboxs = []
+ old_areas_cats = []
+ for sel_id in self._display.selected['ids']:
+ ret = self._getLineAreaBboxCats(sel_id)
+ if ret:
+ old_bboxs += ret[0]
+ old_areas_cats += ret[1]
+
+ Vect_set_updated(self.poMapInfo, 1)
+ n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
+
nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
poList,
move[0], move[1], 0,
snap, thresh)
+
Vect_destroy_list(poList)
-
+
+ if nlines > 0 and self.emit_signals:
+ new_bboxs = []
+ new_areas_cats = []
+ n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
+ for i in range(n_up_lines_old, n_up_lines):
+ new_id = Vect_get_updated_line(self.poMapInfo, i)
+ ret = self._getLineAreaBboxCats(new_id)
+ if ret:
+ new_bboxs += ret[0]
+ new_areas_cats += ret[1]
+
if nlines > 0 and self._settings['breakLines']:
for i in range(1, nlines):
self._breakLineAtIntersection(nlines + i, None, changeset)
@@ -553,7 +839,13 @@
if nlines > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-
+
+ if self.emit_signals:
+ self.featuresMoved.emit(new_bboxs=new_bboxs,
+ old_bboxs=old_bboxs,
+ old_areas_cats=old_areas_cats,
+ new_areas_cats=new_areas_cats)
+
return nlines
def MoveSelectedVertex(self, point, move):
@@ -571,12 +863,21 @@
if len(self._display.selected['ids']) != 1:
return -1
-
+
+ # move only first found vertex in bbox
+ poList = self._display.GetSelectedIList()
+
+ if self.emit_signals:
+ cList = poList.contents
+ old_bboxs = [self._getBbox(cList.value[0])]
+ old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
+
+ Vect_set_updated(self.poMapInfo, 1)
+ n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
+
Vect_reset_line(self.poPoints)
Vect_append_point(self.poPoints, point[0], point[1], 0.0)
-
- # move only first found vertex in bbox
- poList = self._display.GetSelectedIList()
+
moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
poList, self.poPoints,
self._display.GetThreshold(type = 'selectThresh'),
@@ -584,7 +885,17 @@
move[0], move[1], 0.0,
1, self._getSnapMode())
Vect_destroy_list(poList)
-
+
+ if moved > 0 and self.emit_signals:
+ n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
+
+ new_bboxs = []
+ new_areas_cats = []
+ for i in range(n_up_lines_old, n_up_lines):
+ new_id = Vect_get_updated_line(self.poMapInfo, i)
+ new_bboxs.append(self._getBbox(new_id))
+ new_areas_cats.append(self._getLineAreasCategories(new_id))
+
if moved > 0 and self._settings['breakLines']:
self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
None)
@@ -592,7 +903,13 @@
if moved > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-
+
+ if self.emit_signals:
+ self.vertexMoved.emit(new_bboxs=new_bboxs,
+ new_areas_cats=new_areas_cats,
+ old_areas_cats=old_areas_cats,
+ old_bboxs=old_bboxs)
+
return moved
def AddVertex(self, coords):
@@ -681,6 +998,10 @@
self._error.ReadLine(line)
return -1
+ if self.emit_signals:
+ old_bboxs = [self._getBbox(line)]
+ old_areas_cats = [self._getLineAreasCategories(line)]
+
# build feature geometry
Vect_reset_line(self.poPoints)
for p in coords:
@@ -696,6 +1017,9 @@
newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
self.poPoints, self.poCats)
+ if newline > 0 and self.emit_signals:
+ new_geom = [self._getBbox(newline)]
+ new_areas_cats = [self._getLineAreasCategories(newline)]
if newline > 0 and self._settings['breakLines']:
self._breakLineAtIntersection(newline, None)
@@ -703,7 +1027,13 @@
if newline > 0:
self._addChangeset()
self.toolbar.EnableUndo()
-
+
+ if self.emit_signals:
+ self.lineEdited.emit(old_bboxs=old_bboxs,
+ old_areas_cats=old_areas_cats,
+ new_bboxs=new_bboxs,
+ new_areas_cats=new_areas_cats)
+
return newline
def FlipLine(self):
@@ -1514,6 +1844,16 @@
return 0
poList = self._display.GetSelectedIList()
+
+ if self.emit_signals:
+ cList = poList.contents
+
+ old_bboxs = [self._getBbox(cList.value[0])]
+ old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
+
+ Vect_set_updated(self.poMapInfo, 1)
+ n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
+
Vect_reset_line(self.poPoints)
Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
@@ -1525,15 +1865,35 @@
else:
ret = Vedit_remove_vertex(self.poMapInfo, poList,
self.poPoints, thresh)
+
Vect_destroy_list(poList)
+
+ if ret > 0 and self.emit_signals:
+ new_bboxs = []
+ new_areas_cats = []
+
+ n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
+ for i in range(n_up_lines_old, n_up_lines):
+ new_id = Vect_get_updated_line(self.poMapInfo, i)
+ new_areas_cats.append(self._getLineAreasCategories(new_id))
+ new_bboxs.append(self._getBbox(new_id))
if not add and ret > 0 and self._settings['breakLines']:
self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
None)
-
+
if ret > 0:
self._addChangeset()
-
+
+ if ret > 0 and self.emit_signals:
+ if add:
+ self.vertexAdded.emit(old_bboxs=old_bboxs, new_bboxs=new_bboxs)
+ else:
+ self.vertexRemoved.emit(old_bboxs=old_bboxs,
+ new_bboxs=new_bboxs,
+ old_areas_cats=old_areas_cats,
+ new_areas_cats=new_areas_cats)
+
return 1
def GetLineCats(self, line):
More information about the grass-commit
mailing list