"""
.. module:: surveying_util.py
:platform: Linux/Windows
:synopsis: Utility module for Land Surveying Plug-in for QGIS
GPL v2.0 license
Copyright (C) 2014- DgiKom Kft. http://digikom.hu
.. moduleauthor::Zoltan Siki <siki@agt.bme.hu>
"""
from qgis.core import *
import re
from base_classes import *
# debugging
from PyQt4.QtCore import pyqtRemoveInputHook
import pdb
def get_namelist(pattern):
"""
[docs] Find layers matching name with the pattern
:param pattern: regexp pattern for layer name
:return list of matching names or None
"""
w = []
layermap = QgsMapLayerRegistry.instance().mapLayers()
for name, layer in layermap.iteritems():
if layer.type() == QGis.Point and re.search(pattern, layer.name()):
w.append(layer.name())
if len(w):
return w
return None
def get_coordlist():
"""
[docs] Find the coordinate list point shape in the actual project
:return layer name or None
"""
return get_namelist('^coord_')
def get_fblist():
"""
[docs] Find the fieldbook tables in the actual project
:return layer name or None
"""
return get_namelist('^fb_')
def get_layer_by_name(name):
"""
[docs] Look for a layer object by name
:param name: name of the layer
:return layer object
"""
layermap = QgsMapLayerRegistry.instance().mapLayers()
for n, layer in layermap.iteritems():
if layer.name() == name:
if layer.isValid():
return layer
else:
return None
return None
def get_fieldlist(vlayer):
"""
[docs] Create a list of fields
:param vlayer: vector layer
:return list of fields
"""
vprovider = vlayer.dataProvider()
allAttrs = vprovider.attributeIndexes()
vprovider.select(allAttrs)
myFields = vprovider.fields()
return myFields
def get_fieldnames(vlayer):
"""
[docs] Create a list from column names of a vector layer
:paramter vlayer: vector layer
:return sorted list of field names
"""
fieldmap = get_fieldlist(vlayer)
fieldlist = []
for name, field in fieldmap.iteritems():
if not field.name() in fieldlist:
fieldlist.append(unicode(field.name()))
return sorted(fieldlist)
def get_coord(p, clist=None):
"""
[docs] Get the coordinates of a point
:param p: point number
:param clist: coordinate list to search for (str), optional
:return Point object with coordinates
"""
if clist is None:
coord_lists = get_coordlist()
else:
coord_lists = [clist]
if coord_lists is None:
return None
for coord_list in coord_lists:
lay = get_layer_by_name(coord_list)
if lay is None:
continue
for feat in lay.getFeatures():
if feat['point_id'] == p:
#return Point(p, feat['e'], feat['n'], feat['z'], feat['pc'], feat['pt'])
pp = Point(p)
if type(feat['e']) is float and type(feat['n']) is float:
pp.e = feat['e']
pp.n = feat['n']
if type(feat['z']) is float:
pp.z = feat['z']
if type(feat['pc']) is str:
p.pc = feat['pc']
if type(feat['pt']) is str:
p.pt = feat['pt']
return pp
return None
def get_known(dimension=2, clist=None):
"""
[docs] Get list of known points
:param dimension: 1/2/3 point dimension, default: 2
:param clist: single coordinate list to search, default None (all lists)
:returns list of point ids
"""
plist = []
if clist is None:
coord_lists = get_coordlist()
else:
coord_lists = [clist]
if coord_lists is None:
return None
for coord_list in coord_lists:
lay = get_layer_by_name(coord_list)
if lay is None:
continue
for feat in lay.getFeatures():
if (dimension == 1 and type(feat['z']) is float) or \
(dimension == 2 and type(feat['e']) is float and type(feat['n']) is float) or \
(dimension == 3 and type(feat['e']) is float and type(feat['n']) is float and type(feat['z']) is float):
if not feat['point_id'] in plist:
plist.append(feat['point_id'])
if len(plist):
return sorted(plist)
return None
def get_measured(dimension=2):
"""
[docs] Get list of unknown points
:param dimension: 1/2/3 point dimension
:returns list of point ids
"""
plist = []
found = []
fb_list = get_fblist()
if fb_list is None:
return None
for fb in fb_list:
lay = get_layer_by_name(fb)
if lay is None:
continue
for feat in lay.getFeatures():
pid = feat['point_id']
p = get_coord(pid)
if (p is None) or \
(dimension == 1 and p.z is None) or \
(dimension == 2 and (p.e is None or p.n is None)) or \
(dimension == 3 and (p.e is None or p.n is None or p.z is None)):
coord = False
else:
coord = True
if not pid in found:
plist.append([pid, coord])
found.append(pid)
if len(plist):
return sorted(plist)
return None
def get_unknown(dimension=2):
"""
[docs] Get list of measured points
:param dimension: 1/2/3 point dimension
:returns list of [point ids, True/False], second element marks
if point have coordinates of dimension
"""
plist = []
fb_list = get_fblist()
if fb_list is None:
return None
for fb in fb_list:
lay = get_layer_by_name(fb)
if lay is None:
continue
for feat in lay.getFeatures():
pid = feat['point_id']
p = get_coord(pid)
if (p is None) or \
(dimension == 1 and p.z is None) or \
(dimension == 2 and (p.e is None or p.n is None)) or \
(dimension == 3 and (p.e is None or p.n is None or p.z is None)):
if not pid in plist:
plist.append(pid)
if len(plist):
return sorted(plist)
return None
def get_stations(known=False, oriented=False):
"""
[docs] Get list of stations from fieldbooks
:param known: If True only known points get into list.
:param oriented: If True only oriented stations get into list.
:returns list of station [[point_id fieldbook_name id] ...]
"""
slist = []
fb_list = get_fblist()
if fb_list is None:
return None
if known:
known_list = get_known()
for fb in fb_list:
lay = get_layer_by_name(fb)
if lay is None:
continue
for feat in lay.getFeatures():
if feat['station'] == "station":
pid = feat['point_id']
if known and known_list is not None and not pid in known_list:
# skip unknown points
continue
if oriented and type(feat['hz']) is not float:
continue
fid = feat['id']
act = [pid, fb, fid]
if not act in slist:
slist.append(act)
if len(slist):
return sorted(slist)
return None
def get_targets(point_id, fieldbook, fid, known=False, polar=False):
"""
[docs] collect observation data from one station
:param point_id: station number/name (str)
:param fieldbook: name of fieldbook (str)
:param fid: id in fieldbook (int)
:param known: If True only known points get into list.
:return list of target points [[point_id fieldbook_name id] ...]
"""
obs = []
found = False
lay = get_layer_by_name(fieldbook)
if lay is None:
return None
if known:
known_list = get_known()
for feat in lay.getFeatures():
if feat['id'] == fid and feat['station'] == 'station' and feat['point_id'] == point_id:
found = True
continue
elif feat['station'] == 'station' and found:
# next station reached
found = False
break
elif found:
pid = feat['point_id']
fid = feat['id']
if known and known_list is not None and not pid in known_list:
# skip unknown points
continue
if polar and (type(feat['hz']) is not float or type(feat['sd']) is not float):
continue
o = [pid, fieldbook, fid]
obs.append(o)
if len(obs):
return sorted(obs)
return None
def get_station(point_id, fieldbook, fid):
"""
[docs] Create a Station instance from a fildbook row and from the coord table.
:param point_id: station number/name (str)
:param fieldbook: name of fieldbook (str)
:param fid: id in fieldbook (int)
:return station (Station)
"""
p = ScPoint(point_id)
o = get_fieldbookrow(point_id, fieldbook, fid)
return Station(p,o)
def get_target(point_id, fieldbook, fid):
"""
[docs] Create a PolarObservation instance of a target point from a fieldbook row.
:param point_id: point number/name (str)
:param fieldbook: name of fieldbook (str)
:param fid: id in fieldbook (int)
:return observation on the point (PolarObservation)
"""
return get_fieldbookrow(point_id, fieldbook, fid)
def get_fieldbookrow(point_id, fieldbook, fid):
"""
[docs] Reads a fieldbook row and put into a PolarObservation object.
:param point_id: point number/name (str)
:param fieldbook: name of fieldbook (str)
:param fid: id in fieldbook (int)
:return observation to the point or a station (PolarObservation)
"""
lay = get_layer_by_name(fieldbook)
if lay is None:
return None
for feat in lay.getFeatures():
if feat['id'] == fid and feat['point_id'] == point_id:
if type(feat['sd']) is float:
if type(feat['v']) is not float:
dist = Distance(feat['sd'],"HD")
elif feat['v']==0.0: # ???
dist = Distance(feat['sd'],"VD")
else:
dist = Distance(feat['sd'],"SD")
else:
dist = None
o = PolarObservation(feat['point_id'],
('station' if feat['station'] == 'station' else None),
(Angle(feat['hz'],"GON") if type(feat['hz']) is float else None),
(Angle(feat['v'],"GON") if type(feat['v']) is float else None),
dist,
(feat['th'] if type(feat['th']) is float else None),
(feat['pc'] if type(feat['pc']) is float else None))
break
return o
def set_orientationangle(point_id, fieldbook, fid, angle):
"""
[docs] Sets the orientation angle(hz) of the given station in the given fieldbook.
:param point_id: point number/name (str)
:param fieldbook: name of fieldbook (str)
:param fid: id in fieldbook (int)
:param angle: orientation angle (float)
"""
lay = get_layer_by_name(fieldbook)
if lay is None:
return False
for feat in lay.getFeatures():
if feat['id'] == fid and feat['point_id'] == point_id:
fid = feat.id()
attrs = {feat.fieldNameIndex('hz') : angle}
lay.dataProvider().changeAttributeValues({ fid : attrs })
return
class ScPoint(Point):
"""
[docs] Extended point class to store table position
"""
def __init__(self, p, coo=None):
"""
:param p: Point object (Point) or a point_id (String)
:param coo: name of the table where point is/to be store (String)
it is None if a new point to add
"""
if isinstance(p, Point):
super(ScPoint, self).__init__(p.id, p.e, p.n, p.z, p.pc, p.pt)
elif isinstance(p, str) or isinstance(p, unicode):
super(ScPoint, self).__init__(p)
self.get_coord()
else:
super(ScPoint, self).__init__("@")
self.coo = coo
def get_coord(self):
"""
[docs] Get the coordinates of the point from coord table and
update coordinate fields
"""
p = get_coord(self.id)
if p is None:
self.e = None
self.n = None
self.z = None
self.pc = None
self.pt = None
self.coo = None
else:
self.e = p.e
self.n = p.n
self.z = p.z
self.pc = p.pc
self.pt = p.pt
# TODO get_coord should return a tuple (p coo)
#self.coo = coord_list
return
def store_coord(self, dimension=3, clist=None):
"""
[docs] Update coordinates in coord table, insert new point if
coo is None or point not found
:param dimension: 1/2/3D coordinates to store (int)
:param clist: name of layer to add (str)
"""
if clist is None:
if self.coo is None:
# new point to add to the first table
cl = get_coordlist()
if cl is None:
return False
self.coo = cl[0]
else:
self.coo = clist
# e, n coordinates must be given (geometry)
if self.e is None or self.n is None:
# TODO error report
return
lay = get_layer_by_name(self.coo)
if lay is None:
return False
for feat in lay.getFeatures():
if feat['point_id'] == self.id:
# set feature geometry and attributes
#pyqtRemoveInputHook()
#pdb.set_trace()
fid = feat.id()
attrs = {feat.fieldNameIndex('point_id') : self.id}
if dimension in [2, 3]:
attrs[feat.fieldNameIndex('e')] = self.e
attrs[feat.fieldNameIndex('n')] = self.n
if dimension in [1, 3]:
attrs[feat.fieldNameIndex('z')] = self.z
attrs[feat.fieldNameIndex('pc')] = self.pc
attrs[feat.fieldNameIndex('pt')] = self.pt
lay.dataProvider().changeAttributeValues({ fid : attrs })
# feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(self.e, self.n)))
lay.dataProvider().changeGeometryValues({ fid : QgsGeometry.fromPoint(QgsPoint(self.e, self.n)) })
# TODO refresh canvas
return True
# add new point
feat = QgsFeature()
#feat.setFields(lay.pendingFields(), True)
#feat.setFields(lay.dataProvider().fields(), True)
fields = lay.dataProvider().fields()
feat.setFields(fields, True)
#pyqtRemoveInputHook()
#pdb.set_trace()
feat.setAttribute(feat.fieldNameIndex('point_id'), self.id)
if dimension in [2, 3]:
feat.setAttribute(feat.fieldNameIndex('e'), self.e)
feat.setAttribute(feat.fieldNameIndex('n'), self.n)
if dimension in [1, 3]:
feat.setAttribute(feat.fieldNameIndex('z'), self.z)
feat.setAttribute(feat.fieldNameIndex('pc'), self.pc)
feat.setAttribute(feat.fieldNameIndex('pt'), self.pt)
feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(self.e, self.n)))
lay.dataProvider().addFeatures([feat])
# TODO refresh canvas
def set_coord(self, p):
"""
[docs] Set the coordinates
:param p: Point
"""
self.point_id = p.id
self.e = p.e
self.n = p.n
self.z = p.z
self.pc = p.pc
self.pt = p.pt