def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput zone_layer = self.inputs[0].value zone_field = self.inputs[1].value fp_layer = self.inputs[2].value # merge with zone to get assignment tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) analyzer = QgsOverlayAnalyzer() try: analyzer.intersection(fp_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile_verify(tmp_join_file, tmp_join,[zone_field]) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) fields = { 0 : QgsField(self._lon_field, QVariant.Double), 1 : QgsField(self._lat_field, QVariant.Double), 2 : QgsField(zone_field, QVariant.String), } zone_idx = layer_field_index(tmp_join_layer, zone_field) fp_layername = 'fpc_%s' % get_unique_filename() fp_file = '%s%s.shp' % (self._tmp_dir, fp_layername) try: writer = QgsVectorFileWriter(fp_file, "utf-8", fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(tmp_join_layer): centroid = _f.geometry().centroid().asPoint() lon = centroid.x() lat = centroid.y() zone_str = str(_f.attributeMap()[zone_idx].toString()).upper() f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(lon)) f.addAttribute(1, QVariant(lat)) f.addAttribute(2, QVariant(zone_str)) writer.addFeature(f) del writer except Exception as err: logAPICall.log(err, logAPICall.ERROR) remove_shapefile(fp_file) raise OperatorError("error creating joined grid: %s" % err, self.__class__) # load shapefile as layer fp_layer = load_shapefile(fp_file, fp_layername) if not fp_layer: raise OperatorError('Error loading footprint centroid file' % (fp_file), self.__class__) # clean up del tmp_join_layer remove_shapefile(tmp_join_file) self.outputs[0].value = fp_layer self.outputs[1].value = fp_file
def test_AddAttribute(self): feat = QgsFeature() feat.addAttribute(1, "text") myCount = len(feat.attributeMap()) myExpectedCount = 1 myMessage = '\nExpected: %s\nGot: %s' % (myExpectedCount, myCount) assert myCount == myExpectedCount, myMessage
def _write_grid_shapefile(self, path, x_min, y_min, x_max, y_max, x_off, y_off): x_off = self._x_off y_off = self._y_off x_min = floor(x_min / x_off) * x_off x_max = ceil(x_max / x_off) * x_off y_min = floor(y_min / y_off) * y_off y_max = ceil(y_max / y_off) * y_off xtotal = int((x_max - x_min) / x_off) ytotal = int((y_max - y_min) / y_off) logAPICall.log( 'x_min %f x_max %f y_min %f y_max %f x_off %f y_off %f xtotal %d, ytotal %d' % (x_min, x_max, y_min, y_max, x_off, y_off, xtotal, ytotal), logAPICall.DEBUG_L2) writer = QgsVectorFileWriter(path, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() for x in range(xtotal): for y in range(ytotal): lon = x_min + (x * x_off) + (x_off / 2.0) lat = y_min + (y * y_off) + (y_off / 2.0) f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(lon)) f.addAttribute(1, QVariant(lat)) writer.addFeature(f) del writer
def saveIntersectionResult(self, report, intersectedPoint): # save the intersection result (point) and its report # check first while True: if not self.settings.value("advancedIntersectionWritePoint"): break # if we do not place any point, skip layerid = self.settings.value("advancedIntersectionLayer") message = QCoreApplication.translate("IntersectIt", "To place the intersection solution," " you must select a layer in the settings.") status, intLayer = self.checkLayerExists(layerid, message) if status == 2: continue if status == 3: return if self.settings.value("advancedIntersectionWriteReport"): reportField = self.settings.value("reportField") message = QCoreApplication.translate("IntersectIt", "To save the intersection report, please select a field for it.") status = self.checkFieldExists(intLayer, reportField, message) if status == 2: continue if status == 3: return break # save the intersection results if self.settings.value("advancedIntersectionWritePoint"): f = QgsFeature() f.setGeometry(QgsGeometry().fromPoint(intersectedPoint)) if self.settings.value("advancedIntersectionWriteReport"): irep = intLayer.dataProvider().fieldNameIndex(reportField) f.addAttribute(irep, report) intLayer.dataProvider().addFeatures([f]) intLayer.updateExtents() self.mapCanvas.refresh()
def _create_grid(self, grid_name, grid_file, x_min, y_min, x_max, y_max, x_off, y_off): x_off2, y_off2 = x_off / 2.0, y_off / 2.0 x_min = floor(x_min / x_off) * x_off x_max = ceil(x_max / x_off) * x_off y_min = floor(y_min / y_off) * y_off y_max = ceil(y_max / y_off) * y_off xtotal = int((x_max - x_min) / x_off) + 1 ytotal = int((y_max - y_min) / y_off) + 1 logAPICall.log( "x_min %f x_max %f y_min %f y_max %f x_off %f y_off %f xtotal %d, ytotal %d" % (x_min, x_max, y_min, y_max, x_off, y_off, xtotal, ytotal), logAPICall.DEBUG_L2, ) fields = {0: QgsField("GRID_GID", QVariant.String)} writer = QgsVectorFileWriter(grid_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for x in range(xtotal): for y in range(ytotal): lon = x_min + (x * x_off) + (x_off2) lat = y_min + (y * y_off) + (y_off2) # out_geom = QgsGeometry.fromRect(QgsRectangle(lon-x_off2, lat-y_off2, # lon+x_off2, lat+y_off2)) f.setGeometry(self._outputGeometryFromLatLon(lat, lon)) f.addAttribute(0, QVariant(latlon_to_grid(lat, lon))) writer.addFeature(f) del writer return load_shapefile(grid_file, grid_name)
def _write_grid_shapefile(self, path, x_min, y_min, x_max, y_max, x_off, y_off): x_off = self._x_off y_off = self._y_off x_min = floor(x_min / x_off) * x_off x_max = ceil(x_max / x_off) * x_off y_min = floor(y_min / y_off) * y_off y_max = ceil(y_max / y_off) * y_off xtotal = int((x_max - x_min) / x_off) ytotal = int((y_max - y_min) / y_off) logAPICall.log('x_min %f x_max %f y_min %f y_max %f x_off %f y_off %f xtotal %d, ytotal %d' % (x_min, x_max, y_min, y_max, x_off, y_off, xtotal, ytotal), logAPICall.DEBUG_L2) writer = QgsVectorFileWriter(path, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() for x in range(xtotal): for y in range(ytotal): lon = x_min + (x * x_off) + (x_off/2.0) lat = y_min + (y * y_off) + (y_off/2.0) f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(lon)) f.addAttribute(1, QVariant(lat)) writer.addFeature(f) del writer
def _create_grid(self, grid_name, grid_file, x_min, y_min, x_max, y_max, x_off, y_off): x_off2, y_off2 = x_off / 2.0, y_off / 2.0 x_min = floor(x_min / x_off) * x_off x_max = ceil(x_max / x_off) * x_off y_min = floor(y_min / y_off) * y_off y_max = ceil(y_max / y_off) * y_off xtotal = int((x_max - x_min) / x_off)+1 ytotal = int((y_max - y_min) / y_off)+1 logAPICall.log('x_min %f x_max %f y_min %f y_max %f x_off %f y_off %f xtotal %d, ytotal %d' % (x_min, x_max, y_min, y_max, x_off, y_off, xtotal, ytotal), logAPICall.DEBUG_L2) fields = { 0 : QgsField('GRID_GID', QVariant.String), } writer = QgsVectorFileWriter(grid_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for x in range(xtotal): for y in range(ytotal): lon = x_min + (x * x_off) + (x_off2) lat = y_min + (y * y_off) + (y_off2) #out_geom = QgsGeometry.fromRect(QgsRectangle(lon-x_off2, lat-y_off2, # lon+x_off2, lat+y_off2)) f.setGeometry(self._outputGeometryFromLatLon(lat, lon)) f.addAttribute(0, QVariant(latlon_to_grid(lat, lon))) writer.addFeature(f) del writer return load_shapefile(grid_file, grid_name)
def test_CreateFeature(self): feat = QgsFeature() feat.addAttribute(1, "text") feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(123,456))) myId = feat.id() myExpectedId = 0 myMessage = '\nExpected: %s\nGot: %s' % (myExpectedId, myId) assert myId == myExpectedId, myMessage
def test_CreateFeature(self): feat = QgsFeature() feat.addAttribute(1, "text") feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(123, 456))) myId = feat.id() myExpectedId = 0 myMessage = '\nExpected: %s\nGot: %s' % (myExpectedId, myId) assert myId == myExpectedId, myMessage
def test_ChangeAttribute(self): feat = QgsFeature() feat.addAttribute(1, "text") feat.changeAttribute(1, "changed") myChangedAttribute = feat.attributeMap()[1].toString() myExpectedAttribute = "changed" myMessage = '\nExpected: %s\nGot: %s' % (myExpectedAttribute, myChangedAttribute) assert myChangedAttribute == myExpectedAttribute, myMessage
def do_operation(self): """ perform export operation """ # input/output data checking already done during property set input_file = self.inputs[0].value output_file = self.inputs[1].value output_dbf = '%s_attr.dbf' % output_file[:-3] try: exp_layer = load_shapefile(input_file, 'exposure_%s' % get_unique_filename()) # store id of distinct features total_features = exp_layer.dataProvider().featureCount() if total_features > MAX_FEATURES_IN_MEMORY: # use bsddb to store id in case number of features is too large tmp_db_file = '%sdb_%s.db' % (self._tmp_dir, get_unique_filename()) db = bsddb.btopen(tmp_db_file, 'c') use_db = True else: # in memory dictionary, should be much faster, but could fail # if memory is limited db = {} use_db = False # get field index for GID gid_idx = layer_field_index(exp_layer, GID_FIELD_NAME) fields = { 0: QgsField(GID_FIELD_NAME, QVariant.Int), } writer = QgsVectorFileWriter(output_file, "utf-8", fields, exp_layer.dataProvider().geometryType(), exp_layer.crs(), "ESRI Shapefile") out_feature = QgsFeature() for feature in layer_features(exp_layer): gid = str(feature.attributeMap()[gid_idx].toString()) # only write out once if not db.has_key(gid): db[gid]= '1' # bsddb only accepts string out_feature.addAttribute(0, gid) out_feature.setGeometry(feature.geometry()) writer.addFeature(out_feature) # clean up del writer if use_db: db.close() os.remove(tmp_db_file) # copy associated attribute file copy_shapefile(input_file, output_dbf, extensions=['.dbf']) except Exception as err: raise OperatorError("error creating shapefile: %s" % err, self.__class__)
def addGeomToMemoryLayer(self, the_geom, origin=0, delete_when_done=False): """TO DO: Add doc string""" foi_type = self.foi_type.lower() print "got foi_type" if self.mem_layer_obj.featureCount() > 0: if origin == 1: # is added by identify operation pass else: print self.mem_layer_obj.featureCount() print "there exists a feature, kill it!" self.mem_layer_obj.select() print "Feature count selcted for deletion:" print self.mem_layer_obj.selectedFeatureCount() self.mem_layer_obj.deleteSelectedFeatures() #self.mem_layer_obj.deleteFeature(0) self.mem_layer_obj.commitChanges() self.mem_layer_obj.triggerRepaint() ml_dp = self.mem_layer_obj.dataProvider() print "got DP" uuid_gid = QtCore.QUuid().createUuid().toString() print "got uuid" fet = QgsFeature() print "got feature with id" fet.setGeometry(the_geom) print "set geometry" fet.addAttribute(0, uuid_gid) print "set attr " ml_dp.addFeatures([fet]) self.mem_layer_obj.commitChanges() print "added layers" #self.mem_layer_obj.updateFeatureAttributes(fet) #self.mem_layer_obj.updateFeatureGeometry(fet) self.mem_layer_obj.updateExtents() print "updated extents" #self.mem_layer_obj.drawFeature(fet) self.mem_layer_obj.triggerRepaint() print "trp" return fet.id()
def saveIntersectionResult(self, report, intersectedPoint): # save the intersection result (point) and its report # check first while True: if not self.settings.value("advancedIntersectionWritePoint"): break # if we do not place any point, skip layerid = self.settings.value("advancedIntersectionLayer") message = QCoreApplication.translate( "IntersectIt", "To place the intersection solution," " you must select a layer in the settings.") status, intLayer = self.checkLayerExists(layerid, message) if status == 2: continue if status == 3: return if self.settings.value("advancedIntersectionWriteReport"): reportField = self.settings.value("reportField") message = QCoreApplication.translate( "IntersectIt", "To save the intersection report, please select a field for it." ) status = self.checkFieldExists(intLayer, reportField, message) if status == 2: continue if status == 3: return break # save the intersection results if self.settings.value("advancedIntersectionWritePoint"): f = QgsFeature() f.setGeometry(QgsGeometry().fromPoint(intersectedPoint)) if self.settings.value("advancedIntersectionWriteReport"): irep = intLayer.dataProvider().fieldNameIndex(reportField) f.addAttribute(irep, report) intLayer.dataProvider().addFeatures([f]) intLayer.updateExtents() self.mapCanvas.refresh()
def createFeature(self, geom): # pydevd.settrace() layer = self.canvas.currentLayer() provider = layer.dataProvider() f = QgsFeature() # if (geom.validateGeometry()): if (geom.isGeosValid()): f.setGeometry(geom) else: reply = QMessageBox.question(self.iface.mainWindow(), 'Feature not valid', "The geometry of the feature you just added isn't valid. Do you want to use it anyway?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: f.setGeometry(geom) else: return False ## Add attributefields to feature. fields = layer.pendingFields() try: # API-Break 1.8 vs. 2.0 handling attr = f.initAttributes(len(fields)) for i in range(len(fields)): f.setAttribute(i, provider.defaultValue(i)) except AttributeError: # <=1.8 ## Add attributefields to feature. for i in fields: f.addAttribute(i, provider.defaultValue(i)) layer.beginEditCommand("Feature added") layer.addFeature(f) layer.endEditCommand() self.canvas.refresh()
def insertShapeFileValues(layer, attributes, values, coords): # get the geometry type # todo: not working yet. attribute ids must match those from table. # use createShapeFileFullLayer instead res = False if layer: geom_type = layer.geometryType() provider = layer.dataProvider() caps = provider.capabilities() if caps & QgsVectorDataProvider.AddFeatures: # add features by iterating the values features = [] for val in values: feat = QgsFeature() # add geometry try: if geom_type in (0, 3): feat.setGeometry( QgsGeometry.fromPoint([QgsPoint(float(val[coords[0]]), float(val[coords[1]]))])) elif geom_type in (1, 4): feat.setGeometry( QgsGeometry.fromPolyline([QgsPoint(float(val[coords[0]]), float(val[coords[1]])), QgsPoint(float(val[coords[2]]), float(val[coords[3]]))])) except: pass # add attributes for i, x in enumerate(val): feat.addAttribute(i, x) features.append(feat) res, outFeats = provider.addFeatures(features) layer.updateFields() else: res = False else: res = False return res
def _loadSurvey(self, csvpath, shapefilepath): # load data data = csv.reader(open(csvpath, "r"), delimiter=",", quotechar='"') # skip header, there is probably a better way to accomplish this data.next() writer = QgsVectorFileWriter(shapefilepath, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for row in data: lon = float(row[0]) lat = float(row[1]) f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) gid += 1 f.addAttribute(0, QVariant(gid)) f.addAttribute(1, QVariant(lon)) f.addAttribute(2, QVariant(lat)) f.addAttribute(3, QVariant(row[2])) writer.addFeature(f) del writer, f
def _loadSurvey(self, csvpath, shapefilepath): # load data data = csv.reader(open(csvpath, 'r'), delimiter=',', quotechar='"') # skip header, there is probably a better way to accomplish this data.next() writer = QgsVectorFileWriter(shapefilepath, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for row in data: lon = float(row[0]) lat = float(row[1]) f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) gid += 1 f.addAttribute(0, QVariant(gid)) f.addAttribute(1, QVariant(lon)) f.addAttribute(2, QVariant(lat)) f.addAttribute(3, QVariant(row[2])) writer.addFeature(f) del writer, f
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput zone_layer = self.inputs[0].value zone_field = self.inputs[1].value zone_count_field = self.inputs[2].value fp_layer = self.inputs[3].value # merge with zone tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) analyzer = QgsOverlayAnalyzer() try: analyzer.intersection(fp_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # count footprint in each zone gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME + "_") area_idx = layer_field_index(tmp_join_layer, AREA_FIELD_NAME) ht_idx = layer_field_index(tmp_join_layer, HT_FIELD_NAME) stats = {} for _feature in layer_features(tmp_join_layer): gid = _feature.attributeMap()[gid_idx].toString() if ht_idx > 0: ht = _feature.attributeMap()[ht_idx].toDouble()[0] else: ht = 0 # if height is not defined, it is set to 0 # this will cause the system to ignore area generate without having to # remove the field area = _feature.attributeMap()[area_idx].toDouble()[0] * ht # if not stats.has_key(gid): stats[gid] = (1, area) else: stat = stats[gid] stats[gid] = (stat[0] + 1, stat[1] + area) output_layername = 'zone_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: fields = { 0: QgsField(GID_FIELD_NAME, QVariant.Int), 1: QgsField(zone_field, QVariant.String), 2: QgsField(CNT_FIELD_NAME, QVariant.Int), 3: QgsField(AREA_FIELD_NAME, QVariant.Int), } writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(zone_layer): # write to file f.setGeometry(_f.geometry()) f.addAttribute(0, _f.attributeMap()[0]) f.addAttribute(1, _f.attributeMap()[1]) # retrieve count from statistic try: gid = _f.attributeMap()[0].toString() stat = stats[gid] bldg_count = stat[0] area = stat[1] except: bldg_count, area = 0, 0 f.addAttribute(2, QVariant(bldg_count)) f.addAttribute(3, QVariant(area)) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating zone: %s" % err, self.__class__) # clean up del tmp_join_layer remove_shapefile(tmp_join_file) # store data in output output_layer = load_shapefile(output_file, output_layername) if not output_layer: raise OperatorError( 'Error loading footprint centroid file' % (output_file), self.__class__) self.outputs[0].value = output_layer self.outputs[1].value = output_file
def do_operation(self): """ perform create mappin """ # validate inputs popgrid_layer = self.inputs[0].value zone_layer = self.inputs[1].value zone_field = self.inputs[2].value pop_to_bldg = float(self.inputs[3].value) # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(popgrid_layer) self._test_layer_field_exists(popgrid_layer, CNT_FIELD_NAME) self._test_layer_loaded(zone_layer) self._test_layer_field_exists(zone_layer, zone_field) # count_field is not required # if count field is not defined, then generate building count from footprints # local variables analyzer = QgsOverlayAnalyzer() # intersect grids and zones to obtain polygons with # - population and zone_id # - apply ratio to population to obtain building count tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) try: # do intersection analyzer.intersection(popgrid_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # generate grid with building counts fields = { 0 : QgsField(GID_FIELD_NAME, QVariant.String), 1 : QgsField(zone_field, QVariant.String), 2 : QgsField(CNT_FIELD_NAME, QVariant.Double), } output_layername = 'grid_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() pop_idx = layer_field_index(tmp_join_layer, CNT_FIELD_NAME) zone_idx = layer_field_index(tmp_join_layer, zone_field) for _f in layer_features(tmp_join_layer): pop_count = _f.attributeMap()[pop_idx].toDouble()[0] zone = _f.attributeMap()[zone_idx].toString() # 1. get geometry geom = _f.geometry() # 2. get original centroid point and project is required centroid = geom.centroid().asPoint() grid_gid = latlon_to_grid(centroid.y(), centroid.x()) f.setGeometry(self._outputGeometryFromGridId(grid_gid)) f.addAttribute(0, grid_gid) f.addAttribute(1, zone) f.addAttribute(2, pop_count / pop_to_bldg) writer.addFeature(f) del writer # clean up del tmp_join_layer remove_shapefile(tmp_join_file) # store data in output self._load_output(output_file, output_layername)
def do_operation(self): # validate inputs zone_layer = self.inputs[0].value zone_field = self.inputs[1].value count_field = self.inputs[2].value area_field = self.inputs[3].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(zone_layer) self._test_layer_field_exists(zone_layer, GID_FIELD_NAME) self._test_layer_field_exists(zone_layer, zone_field) self._test_layer_field_exists(zone_layer, count_field) # local variables analyzer = QgsOverlayAnalyzer() area_idx = ToGrid.STAT_AREA_IDX #cnt_idx = ToGrid.STAT_COUNT_IDX # 1. find building count and total area for each zone zone_names, zone_stat= {}, {} try: self._create_zone_statistics(zone_layer, zone_field, count_field, zone_stat, zone_names) except Exception as err: raise OperatorError(str(err), self.__class__) # 2. create grids around extent of zone tmp_grid1 = 'grid_' + get_unique_filename() tmp_grid1_file = self._tmp_dir + tmp_grid1 + '.shp' try: extent = zone_layer.extent() [x_min, y_min, x_max, y_max] = [extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum()] tmp_grid_lyr1 = self._create_grid(tmp_grid1, tmp_grid1_file, \ x_min, y_min, x_max, y_max, \ DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE) except Exception as err: raise OperatorError(str(err), self.__class__) # 3. intersect grids and zones to obtain polygons with # - grid_id and zone_id # - ratio of grid covered by zone (polygon area / zone area) # apply ratio to zone building count to obtain count assigned to polygon tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) try: # do intersection analyzer.intersection(tmp_grid_lyr1, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # do tally zone_gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME) grid_gid_idx = layer_field_index(tmp_join_layer, "GRID_GID") bldg_cnt_idx = layer_field_index(tmp_join_layer, count_field) bldg_area_idx = layer_field_index(tmp_join_layer, area_field) mercator_transform = QgsCoordinateTransform(tmp_join_layer.crs(), self.mercator_crs) fields = { 0 : QgsField(GID_FIELD_NAME, QVariant.String), 1 : QgsField(zone_field, QVariant.String), 2 : QgsField(CNT_FIELD_NAME, QVariant.Double), 3 : QgsField(AREA_FIELD_NAME, QVariant.Double), } output_layername = 'grid_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(tmp_join_layer): # get area of polygon geom = _f.geometry() geom.transform(mercator_transform) area = geom.area() # generate all stats of interest zone_gid = _f.attributeMap()[zone_gid_idx].toString() grid_gid = _f.attributeMap()[grid_gid_idx].toString() stat = zone_stat[zone_gid] # calculate count/area as proportion of total zone area bldg_cnt = _f.attributeMap()[bldg_cnt_idx].toDouble()[0] * (area/stat[area_idx]) if bldg_area_idx> 0: bldg_area = _f.attributeMap()[bldg_area_idx].toDouble()[0] * (area/stat[area_idx]) else: bldg_area = 0 # create output record f.setGeometry(self._outputGeometryFromGridId(grid_gid)) f.addAttribute(0, grid_gid) f.addAttribute(1, zone_names[QString(zone_gid)]) f.addAttribute(2, bldg_cnt) f.addAttribute(3, bldg_area) writer.addFeature(f) del writer # clean up del tmp_grid_lyr1 del tmp_join_layer remove_shapefile(tmp_grid1_file) remove_shapefile(tmp_join_file) # store data in output self._load_output(output_file, output_layername)
def do_operation(self): """ perform create mappin """ # validate inputs popgrid_layer = self.inputs[0].value zone_layer = self.inputs[1].value zone_field = self.inputs[2].value pop_to_bldg = float(self.inputs[3].value) # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(popgrid_layer) self._test_layer_field_exists(popgrid_layer, CNT_FIELD_NAME) self._test_layer_loaded(zone_layer) self._test_layer_field_exists(zone_layer, zone_field) # count_field is not required # if count field is not defined, then generate building count from footprints # local variables analyzer = QgsOverlayAnalyzer() # intersect grids and zones to obtain polygons with # - population and zone_id # - apply ratio to population to obtain building count tmp_join = "joined_%s" % get_unique_filename() tmp_join_file = "%s%s.shp" % (self._tmp_dir, tmp_join) try: # do intersection analyzer.intersection(popgrid_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # generate grid with building counts fields = { 0: QgsField(GID_FIELD_NAME, QVariant.String), 1: QgsField(zone_field, QVariant.String), 2: QgsField(CNT_FIELD_NAME, QVariant.Double), } output_layername = "grid_%s" % get_unique_filename() output_file = "%s%s.shp" % (self._tmp_dir, output_layername) writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() pop_idx = layer_field_index(tmp_join_layer, CNT_FIELD_NAME) zone_idx = layer_field_index(tmp_join_layer, zone_field) for _f in layer_features(tmp_join_layer): pop_count = _f.attributeMap()[pop_idx].toDouble()[0] zone = _f.attributeMap()[zone_idx].toString() # 1. get geometry geom = _f.geometry() # 2. get original centroid point and project is required centroid = geom.centroid().asPoint() grid_gid = latlon_to_grid(centroid.y(), centroid.x()) f.setGeometry(self._outputGeometryFromGridId(grid_gid)) f.addAttribute(0, grid_gid) f.addAttribute(1, zone) f.addAttribute(2, pop_count / pop_to_bldg) writer.addFeature(f) del writer # clean up del tmp_join_layer remove_shapefile(tmp_join_file) # store data in output self._load_output(output_file, output_layername)
def do_operation(self): # validate inputs zone_layer = self.inputs[0].value zone_field = self.inputs[1].value count_field = self.inputs[2].value area_field = self.inputs[3].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(zone_layer) self._test_layer_field_exists(zone_layer, GID_FIELD_NAME) self._test_layer_field_exists(zone_layer, zone_field) self._test_layer_field_exists(zone_layer, count_field) # local variables analyzer = QgsOverlayAnalyzer() area_idx = ToGrid.STAT_AREA_IDX # cnt_idx = ToGrid.STAT_COUNT_IDX # 1. find building count and total area for each zone zone_names, zone_stat = {}, {} try: self._create_zone_statistics(zone_layer, zone_field, count_field, zone_stat, zone_names) except Exception as err: raise OperatorError(str(err), self.__class__) # 2. create grids around extent of zone tmp_grid1 = "grid_" + get_unique_filename() tmp_grid1_file = self._tmp_dir + tmp_grid1 + ".shp" try: extent = zone_layer.extent() [x_min, y_min, x_max, y_max] = [extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum()] tmp_grid_lyr1 = self._create_grid( tmp_grid1, tmp_grid1_file, x_min, y_min, x_max, y_max, DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE ) except Exception as err: raise OperatorError(str(err), self.__class__) # 3. intersect grids and zones to obtain polygons with # - grid_id and zone_id # - ratio of grid covered by zone (polygon area / zone area) # apply ratio to zone building count to obtain count assigned to polygon tmp_join = "joined_%s" % get_unique_filename() tmp_join_file = "%s%s.shp" % (self._tmp_dir, tmp_join) try: # do intersection analyzer.intersection(tmp_grid_lyr1, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # do tally zone_gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME) grid_gid_idx = layer_field_index(tmp_join_layer, "GRID_GID") bldg_cnt_idx = layer_field_index(tmp_join_layer, count_field) bldg_area_idx = layer_field_index(tmp_join_layer, area_field) mercator_transform = QgsCoordinateTransform(tmp_join_layer.crs(), self.mercator_crs) fields = { 0: QgsField(GID_FIELD_NAME, QVariant.String), 1: QgsField(zone_field, QVariant.String), 2: QgsField(CNT_FIELD_NAME, QVariant.Double), 3: QgsField(AREA_FIELD_NAME, QVariant.Double), } output_layername = "grid_%s" % get_unique_filename() output_file = "%s%s.shp" % (self._tmp_dir, output_layername) writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(tmp_join_layer): # get area of polygon geom = _f.geometry() geom.transform(mercator_transform) area = geom.area() # generate all stats of interest zone_gid = _f.attributeMap()[zone_gid_idx].toString() grid_gid = _f.attributeMap()[grid_gid_idx].toString() stat = zone_stat[zone_gid] # calculate count/area as proportion of total zone area bldg_cnt = _f.attributeMap()[bldg_cnt_idx].toDouble()[0] * (area / stat[area_idx]) if bldg_area_idx > 0: bldg_area = _f.attributeMap()[bldg_area_idx].toDouble()[0] * (area / stat[area_idx]) else: bldg_area = 0 # create output record f.setGeometry(self._outputGeometryFromGridId(grid_gid)) f.addAttribute(0, grid_gid) f.addAttribute(1, zone_names[QString(zone_gid)]) f.addAttribute(2, bldg_cnt) f.addAttribute(3, bldg_area) writer.addFeature(f) del writer # clean up del tmp_grid_lyr1 del tmp_join_layer remove_shapefile(tmp_grid1_file) remove_shapefile(tmp_join_file) # store data in output self._load_output(output_file, output_layername)
def do_operation(self): """ perform footprint load operation """ # input/output data checking already done during property set # load and verify infile = self.inputs[0].value tmp_fp_layername = 'fp_%s' % get_unique_filename() tmp_fp_layer = load_shapefile(infile, tmp_fp_layername) if not tmp_fp_layer: raise OperatorError('Error loading footprint file' % (infile), self.__class__) if self._fp_ht_field is not None: ht_idx = layer_field_index(tmp_fp_layer, self._fp_ht_field) else: ht_idx = -1 logAPICall.log( 'tmp_fp_layer.crs().epsg() %s ' % tmp_fp_layer.crs().epsg(), logAPICall.DEBUG) if tmp_fp_layer.crs().epsg() != self._crs.epsg(): transform = QgsCoordinateTransform(tmp_fp_layer.crs(), self._crs) transform_required = True else: transform_required = False mercator_crs = QgsCoordinateReferenceSystem() #mercator_crs.createFromProj4("+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs") mercator_crs.createFromEpsg(3395) mercator_transform = QgsCoordinateTransform(tmp_fp_layer.crs(), mercator_crs) # output grid fields = { 0: QgsField(GID_FIELD_NAME, QVariant.Int), 1: QgsField(LON_FIELD_NAME, QVariant.Double), 2: QgsField(LAT_FIELD_NAME, QVariant.Double), 3: QgsField(AREA_FIELD_NAME, QVariant.Double), 4: QgsField(HT_FIELD_NAME, QVariant.Int), } output_file = '%sfpc_%s.shp' % (self._tmp_dir, get_unique_filename()) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for _f in layer_features(tmp_fp_layer): # NOTE: geom.transform does projection in place to underlying # C object, for some reason, multiple projection does not # work correctly. following is a work-around # 1. get geometry geom = _f.geometry() # 2. get original centroid point and project is required centroid = geom.centroid().asPoint() if transform_required: t_centroid = transform.transform(centroid) else: t_centroid = centroid # 3. project into mercator and get area in m2 geom.transform(mercator_transform) area = geom.area() # write to file gid += 1 f.setGeometry(QgsGeometry.fromPoint(t_centroid)) f.addAttribute(0, QVariant(gid)) f.addAttribute(1, QVariant(t_centroid.x())) f.addAttribute(2, QVariant(t_centroid.y())) f.addAttribute(3, QVariant(area)) if ht_idx != -1: f.addAttribute(4, _f.attributeMap()[ht_idx]) else: f.addAttribute(4, QVariant(0)) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating footprint centroids: %s" % err, self.__class__) fp_layer = load_shapefile(output_file, tmp_fp_layername) if not fp_layer: raise OperatorError( 'Error loading footprint centroid file' % (output_file), self.__class__) # clean up del tmp_fp_layer # store data in output self.outputs[0].value = fp_layer self.outputs[1].value = output_file
def do_operation(self): """ perform apply mapping scheme operation """ # input/output data checking already done during property set src_layer = self.inputs[0].value zone_field = self.inputs[1].value count_field = self.inputs[2].value ms = self.inputs[3].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(src_layer) self._test_layer_field_exists(src_layer, zone_field) self._test_layer_field_exists(src_layer, count_field) # loop through all zones and assign mapping scheme # outputs exposure_layername = 'exp_%s' % get_unique_filename() exposure_file = '%sexp_%s.shp' % (self._tmp_dir, exposure_layername) # loop through all input features provider = src_layer.dataProvider() if provider is None: raise OperatorError("input layer not correctly loaded", self.__class__) zone_idx = layer_field_index(src_layer, zone_field) if zone_idx == -1: raise OperatorError( "field %s not found in input layer" % zone_field, self.__class__) count_idx = layer_field_index(src_layer, count_field) if count_idx == -1: raise OperatorError( "field %s not found in input layer" % count_field, self.__class__) gid_idx = layer_field_index(src_layer, GID_FIELD_NAME) if gid_idx == -1: raise OperatorError( "field %s not found in input layer" % GID_FIELD_NAME, self.__class__) area_idx = layer_field_index(src_layer, AREA_FIELD_NAME) provider.select(provider.attributeIndexes(), provider.extent()) provider.rewind() try: writer = QgsVectorFileWriter(exposure_file, "utf-8", self._fields, provider.geometryType(), self._crs, "ESRI Shapefile") out_feature = QgsFeature() gid = 0 for in_feature in layer_features(src_layer): geom = in_feature.geometry() centroid = geom.centroid().asPoint() gid = in_feature.attributeMap()[gid_idx] zone_str = str(in_feature.attributeMap()[zone_idx].toString()) count = in_feature.attributeMap()[count_idx].toDouble()[0] if area_idx > 0: area = in_feature.attributeMap()[area_idx].toDouble()[0] else: area = 0 count = int(count + 0.5) if count == 0: continue stats = ms.get_assignment_by_name(zone_str) # use default stats if missing if stats is None: raise Exception("no mapping scheme found for zone %s" % zone_str) for _sample in stats.get_samples(count, self._extrapolationOption): # write out if there are structures assigned _type = _sample[0] _cnt = _sample[1] if area > 0: # use area provided by footprint/zone if defined _size = area * (float(_sample[1]) / count) if _sample[3] > 0 and _sample[2] > 0: _cost = (_sample[3] / _sample[2]) * area else: _cost = 0 else: # use mapping scheme generic area otherwise _size = _sample[2] _cost = _sample[3] if _cnt > 0: out_feature.setGeometry(geom) #out_feature.addAttribute(0, QVariant(gid)) out_feature.addAttribute(0, gid) out_feature.addAttribute(1, QVariant(centroid.x())) out_feature.addAttribute(2, QVariant(centroid.y())) out_feature.addAttribute(3, QVariant(_type)) out_feature.addAttribute(4, QVariant(zone_str)) out_feature.addAttribute(5, QVariant(_cnt)) out_feature.addAttribute(6, QVariant(_size)) out_feature.addAttribute(7, QVariant(_cost)) writer.addFeature(out_feature) del writer, out_feature except Exception as err: remove_shapefile(exposure_file) raise OperatorError("error creating exposure file: %s" % err, self.__class__) del src_layer # load shapefile as layer exposure_layer = load_shapefile(exposure_file, exposure_layername) if not exposure_layer: raise OperatorError( 'Error loading exposure file' % (exposure_file), self.__class__) # store data in output self.outputs[0].value = exposure_layer self.outputs[1].value = exposure_file
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput svy_layer = self.inputs[0].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(svy_layer) total_features = svy_layer.dataProvider().featureCount() if total_features > MAX_FEATURES_IN_MEMORY: # use bsddb to store temporary lat/lon tmp_db_file = '%sdb_%s.db' % (self._tmp_dir, get_unique_filename()) db = bsddb.btopen(tmp_db_file, 'c') else: db = {} # tally statistics for each grid_id/building type combination tax_idx = layer_field_index(svy_layer, TAX_FIELD_NAME) for f in layer_features(svy_layer): geom = f.geometry() centroid = geom.centroid().asPoint() grid_id = latlon_to_grid(centroid.y(), centroid.x()) tax_str = str(f.attributeMap()[tax_idx].toString()) key = '%s %s' % (tax_str, grid_id) if db.has_key(key): db[key] = str(int(db[key]) + 1) # value as string required by bsddb else: db[key] = '1' # value as string required by bsddb # loop through all zones and assign mapping scheme # outputs exposure_layername = 'exp_%s' % get_unique_filename() exposure_file = '%s%s.shp' % (self._tmp_dir, exposure_layername) try: writer = QgsVectorFileWriter(exposure_file, "utf-8", self._fields, self._outputGeometryType(), self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for key, val in db.iteritems(): (tax_str, grid_id) = key.split(' ') lon, lat = grid_to_latlon(int(grid_id)) f.setGeometry(self._outputGeometryFromGridId(grid_id)) f.addAttribute(0, QVariant(grid_id)) f.addAttribute(1, QVariant(lon)) f.addAttribute(2, QVariant(lat)) f.addAttribute(3, QVariant(tax_str)) f.addAttribute(4, QVariant('')) f.addAttribute(5, QVariant(val)) writer.addFeature(f) gid += 1 del writer, f except Exception as err: remove_shapefile(exposure_file) raise OperatorError("error creating exposure file: %s" % err, self.__class__) # load shapefile as layer exposure_layer = load_shapefile(exposure_file, exposure_layername) if not exposure_layer: raise OperatorError( 'Error loading exposure file %s' % (exposure_file), self.__class__) # store data in output self.outputs[0].value = exposure_layer self.outputs[1].value = exposure_file
def do_operation(self): """ perform footprint load operation """ # input/output data checking already done during property set # load and verify infile = self.inputs[0].value tmp_fp_layername = 'fp_%s' % get_unique_filename() tmp_fp_layer = load_shapefile(infile, tmp_fp_layername) if not tmp_fp_layer: raise OperatorError('Error loading footprint file' % (infile), self.__class__) if self._fp_ht_field is not None: ht_idx = layer_field_index(tmp_fp_layer, self._fp_ht_field) else: ht_idx = -1 logAPICall.log('tmp_fp_layer.crs().epsg() %s ' % tmp_fp_layer.crs().epsg(), logAPICall.DEBUG) if tmp_fp_layer.crs().epsg() != self._crs.epsg(): transform = QgsCoordinateTransform(tmp_fp_layer.crs(), self._crs) transform_required = True else: transform_required = False mercator_crs = QgsCoordinateReferenceSystem() #mercator_crs.createFromProj4("+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs") mercator_crs.createFromEpsg(3395) mercator_transform = QgsCoordinateTransform(tmp_fp_layer.crs(), mercator_crs) # output grid fields = { 0 : QgsField(GID_FIELD_NAME, QVariant.Int), 1 : QgsField(LON_FIELD_NAME, QVariant.Double), 2 : QgsField(LAT_FIELD_NAME, QVariant.Double), 3 : QgsField(AREA_FIELD_NAME, QVariant.Double), 4 : QgsField(HT_FIELD_NAME, QVariant.Int), } output_file = '%sfpc_%s.shp' % (self._tmp_dir, get_unique_filename()) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for _f in layer_features(tmp_fp_layer): # NOTE: geom.transform does projection in place to underlying # C object, for some reason, multiple projection does not # work correctly. following is a work-around # 1. get geometry geom = _f.geometry() # 2. get original centroid point and project is required centroid = geom.centroid().asPoint() if transform_required: t_centroid = transform.transform(centroid) else: t_centroid = centroid # 3. project into mercator and get area in m2 geom.transform(mercator_transform) area = geom.area() # write to file gid += 1 f.setGeometry(QgsGeometry.fromPoint(t_centroid)) f.addAttribute(0, QVariant(gid)) f.addAttribute(1, QVariant(t_centroid.x())) f.addAttribute(2, QVariant(t_centroid.y())) f.addAttribute(3, QVariant(area)) if ht_idx != -1: f.addAttribute(4, _f.attributeMap()[ht_idx]) else: f.addAttribute(4, QVariant(0)) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating footprint centroids: %s" % err, self.__class__) fp_layer = load_shapefile(output_file, tmp_fp_layername) if not fp_layer: raise OperatorError('Error loading footprint centroid file' % (output_file), self.__class__) # clean up del tmp_fp_layer # store data in output self.outputs[0].value = fp_layer self.outputs[1].value = output_file
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput zone_layer = self.inputs[0].value zone_field = self.inputs[1].value popgrid_layer = self.inputs[2].value pop_to_bldg = float(self.inputs[3].value) # merge with zone tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) analyzer = QgsOverlayAnalyzer() try: analyzer.intersection(popgrid_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # count footprint in each zone stats = {} _gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME + "_") _cnt_idx = layer_field_index(tmp_join_layer, CNT_FIELD_NAME) for _f in layer_features(tmp_join_layer): # retrieve count from statistic _gid = _f.attributeMap()[_gid_idx].toString() _count = _f.attributeMap()[_cnt_idx].toString() if stats.has_key(_gid): stats[_gid] += float(_count) / pop_to_bldg else: stats[_gid] = float(_count) / pop_to_bldg output_layername = 'zone_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: fields = { 0: QgsField(GID_FIELD_NAME, QVariant.Int), 1: QgsField(zone_field, QVariant.String), 2: QgsField(CNT_FIELD_NAME, QVariant.Int), } writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(zone_layer): # write to file f.setGeometry(_f.geometry()) f.addAttribute(0, _f.attributeMap()[0]) f.addAttribute(1, _f.attributeMap()[1]) # retrieve count from statistic try: gid = _f.attributeMap()[0].toString() bldg_count = stats[gid] except: bldg_count = 0 f.addAttribute(2, QVariant(bldg_count)) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating zone: %s" % err, self.__class__) # clean up del tmp_join_layer remove_shapefile(tmp_join_file) # store data in output output_layer = load_shapefile(output_file, output_layername) if not output_layer: raise OperatorError( 'Error loading footprint centroid file' % (output_file), self.__class__) self.outputs[0].value = output_layer self.outputs[1].value = output_file
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput zone_layer = self.inputs[0].value zone_field = self.inputs[1].value popgrid_layer = self.inputs[2].value pop_to_bldg = float(self.inputs[3].value) # merge with zone tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) analyzer = QgsOverlayAnalyzer() try: analyzer.intersection(popgrid_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # count footprint in each zone stats = {} _gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME + "_") _cnt_idx = layer_field_index(tmp_join_layer, CNT_FIELD_NAME) for _f in layer_features(tmp_join_layer): # retrieve count from statistic _gid = _f.attributeMap()[_gid_idx].toString() _count = _f.attributeMap()[_cnt_idx].toString() if stats.has_key(_gid): stats[_gid]+=float(_count) / pop_to_bldg else: stats[_gid]=float(_count) / pop_to_bldg output_layername = 'zone_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: fields ={ 0 : QgsField(GID_FIELD_NAME, QVariant.Int), 1 : QgsField(zone_field, QVariant.String), 2 : QgsField(CNT_FIELD_NAME, QVariant.Int), } writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(zone_layer): # write to file f.setGeometry(_f.geometry()) f.addAttribute(0, _f.attributeMap()[0]) f.addAttribute(1, _f.attributeMap()[1]) # retrieve count from statistic try: gid = _f.attributeMap()[0].toString() bldg_count = stats[gid] except: bldg_count = 0 f.addAttribute(2, QVariant(bldg_count)) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating zone: %s" % err, self.__class__) # clean up del tmp_join_layer remove_shapefile(tmp_join_file) # store data in output output_layer = load_shapefile(output_file, output_layername) if not output_layer: raise OperatorError('Error loading footprint centroid file' % (output_file), self.__class__) self.outputs[0].value = output_layer self.outputs[1].value = output_file
def _buildSurveyLayer(self, data, shapefilepath): writer = QgsVectorFileWriter(shapefilepath, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() for row in data: obj_uid = str(row[0]) lon = self._tofloat(row[1]) lat = self._tofloat(row[2]) sample_grp = str(row[3]) plan_area = self._tofloat(row[4]) rep_cost = self._tofloat(row[5]) tax_string = self._make_gem_taxstring(row[6:]) ht = self._get_height(row[6:]) f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(obj_uid)) f.addAttribute(1, QVariant(lon)) f.addAttribute(2, QVariant(lat)) f.addAttribute(3, QVariant(tax_string)) f.addAttribute(4, QVariant(sample_grp)) f.addAttribute(5, QVariant(plan_area)) f.addAttribute(6, QVariant(ht)) f.addAttribute(7, QVariant(rep_cost)) writer.addFeature(f) del writer, f
def do_operation(self): """ perform footprint load operation """ # input/output data checking already done during property set # load and verify popgrid_file = self.inputs[0].value pop_field = self.inputs[1].value popgrid_layername = 'zone_%s' % get_unique_filename() try: tmp_popgrid_layer = load_shapefile_verify(popgrid_file, popgrid_layername, [pop_field]) except AssertionError as err: raise OperatorError(str(err), self.__class__) logAPICall.log('tmp_fp_layer.crs().epsg() %s ' % tmp_popgrid_layer.crs().epsg(), logAPICall.DEBUG) if tmp_popgrid_layer.crs().epsg() != self._crs.epsg(): transform = QgsCoordinateTransform(tmp_popgrid_layer.crs(), self._crs) transform_required = True else: transform_required = False # output grid fields = { 0 : QgsField(GID_FIELD_NAME, QVariant.Int), 1 : QgsField(CNT_FIELD_NAME, QVariant.Double), } pop_idx = layer_field_index(tmp_popgrid_layer, pop_field) output_file = '%spop_grid_%s.shp' % (self._tmp_dir, get_unique_filename()) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for _f in layer_features(tmp_popgrid_layer): # NOTE: geom.transform does projection in place to underlying C object # 1. get geometry geom = _f.geometry() # 2. change project if required if transform_required: geom = transform.transform(geom) # 3. write to file gid += 1 f.setGeometry(geom) f.addAttribute(0, QVariant(gid)) f.addAttribute(1, _f.attributeMap()[pop_idx]) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating footprint centroids: %s" % err, self.__class__) popgrid_layername = 'popgrid_%s' % get_unique_filename() popgrid_layer = load_shapefile(output_file, popgrid_layername) if not popgrid_layer: raise OperatorError('Error loading footprint centroid file' % (output_file), self.__class__) # clean up del tmp_popgrid_layer # store data in output self.outputs[0].value = popgrid_layer self.outputs[1].value = output_file
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput zone_layer = self.inputs[0].value zone_field = self.inputs[1].value zone_count_field = self.inputs[2].value fp_layer = self.inputs[3].value # merge with zone tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) analyzer = QgsOverlayAnalyzer() try: analyzer.intersection(fp_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # count footprint in each zone gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME + "_") area_idx = layer_field_index(tmp_join_layer, AREA_FIELD_NAME) ht_idx = layer_field_index(tmp_join_layer, HT_FIELD_NAME) stats = {} for _feature in layer_features(tmp_join_layer): gid = _feature.attributeMap()[gid_idx].toString() if ht_idx > 0: ht = _feature.attributeMap()[ht_idx].toDouble()[0] else: ht = 0 # if height is not defined, it is set to 0 # this will cause the system to ignore area generate without having to # remove the field area = _feature.attributeMap()[area_idx].toDouble()[0] * ht # if not stats.has_key(gid): stats[gid] = (1, area) else: stat = stats[gid] stats[gid] = (stat[0]+1, stat[1]+area) output_layername = 'zone_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: fields ={ 0 : QgsField(GID_FIELD_NAME, QVariant.Int), 1 : QgsField(zone_field, QVariant.String), 2 : QgsField(CNT_FIELD_NAME, QVariant.Int), 3 : QgsField(AREA_FIELD_NAME, QVariant.Int), } writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(zone_layer): # write to file f.setGeometry(_f.geometry()) f.addAttribute(0, _f.attributeMap()[0]) f.addAttribute(1, _f.attributeMap()[1]) # retrieve count from statistic try: gid = _f.attributeMap()[0].toString() stat = stats[gid] bldg_count = stat[0] area = stat[1] except: bldg_count, area = 0, 0 f.addAttribute(2, QVariant(bldg_count)) f.addAttribute(3, QVariant(area)) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating zone: %s" % err, self.__class__) # clean up del tmp_join_layer remove_shapefile(tmp_join_file) # store data in output output_layer = load_shapefile(output_file, output_layername) if not output_layer: raise OperatorError('Error loading footprint centroid file' % (output_file), self.__class__) self.outputs[0].value = output_layer self.outputs[1].value = output_file
@logAPICall def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput svy_layer = self.inputs[0].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(svy_layer) total_features = svy_layer.dataProvider().featureCount() if total_features > MAX_FEATURES_IN_MEMORY: # use bsddb to store temporary lat/lon tmp_db_file = '%sdb_%s.db' % (self._tmp_dir, get_unique_filename()) db = bsddb.btopen(tmp_db_file, 'c') else: db = {} # tally statistics for each grid_id/building type combination tax_idx = layer_field_index(svy_layer, TAX_FIELD_NAME) for f in layer_features(svy_layer): geom = f.geometry() centroid = geom.centroid().asPoint() grid_id = latlon_to_grid(centroid.y(), centroid.x()) tax_str = str(f.attributeMap()[tax_idx].toString()) key = '%s %s' % (tax_str, grid_id) if db.has_key(key): db[key] = str(int(db[key]) + 1) # value as string required by bsddb else: db[key] = '1' # value as string required by bsddb # loop through all zones and assign mapping scheme # outputs exposure_layername = 'exp_%s' % get_unique_filename() exposure_file = '%s%s.shp' % (self._tmp_dir, exposure_layername) try: writer = QgsVectorFileWriter(exposure_file, "utf-8", self._fields, self._outputGeometryType(), self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for key, val in db.iteritems(): (tax_str, grid_id) = key.split(' ') lon, lat = grid_to_latlon(int(grid_id)) f.setGeometry(self._outputGeometryFromGridId(grid_id)) f.addAttribute(0, QVariant(grid_id)) f.addAttribute(1, QVariant(lon)) f.addAttribute(2, QVariant(lat)) f.addAttribute(3, QVariant(tax_str)) f.addAttribute(4, QVariant('')) f.addAttribute(5, QVariant(val)) writer.addFeature(f) gid += 1 del writer, f except Exception as err: remove_shapefile(exposure_file) raise OperatorError("error creating exposure file: %s" % err, self.__class__) # load shapefile as layer exposure_layer = load_shapefile(exposure_file, exposure_layername) if not exposure_layer: raise OperatorError('Error loading exposure file %s' % (exposure_file), self.__class__) # store data in output self.outputs[0].value = exposure_layer
def do_operation(self): """ perform create mapping scheme operation """ # validate inputs fp_layer = self.inputs[0].value zone_layer = self.inputs[1].value zone_field = self.inputs[2].value count_field = self.inputs[3].value area_field = self.inputs[4].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(fp_layer) self._test_layer_loaded(zone_layer) self._test_layer_field_exists(zone_layer, GID_FIELD_NAME) self._test_layer_field_exists(zone_layer, zone_field) # count_field is not required # if count field is not defined, then generate building count from footprints # area_field is not required # local variables analyzer = QgsOverlayAnalyzer() area_idx = ToGrid.STAT_AREA_IDX cnt_idx = ToGrid.STAT_COUNT_IDX zone_names, zone_stat, zone_stat2, zone_totals = {}, {}, {}, {} # 1. find building count and total area for each zone # project geometry into mercator and get area in m2 mercator_crs = QgsCoordinateReferenceSystem() mercator_crs.createFromEpsg(3395) mercator_transform = QgsCoordinateTransform(zone_layer.crs(), mercator_crs) try: # use zone geometry area self._create_zone_statistics(zone_layer, zone_field, count_field, zone_stat, zone_names) except Exception as err: raise OperatorError(str(err), self.__class__) # 2. create grids around extent of zone tmp_grid1 = "grid_" + get_unique_filename() tmp_grid1_file = self._tmp_dir + tmp_grid1 + ".shp" extent = zone_layer.extent() [x_min, y_min, x_max, y_max] = [extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum()] tmp_grid_lyr1 = self._create_grid( tmp_grid1, tmp_grid1_file, x_min, y_min, x_max, y_max, DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE ) # tally total building area if there is defined bldg_area_idx = layer_field_index(zone_layer, area_field) zone_area = {} zone_has_area = False if bldg_area_idx > 0: zone_has_area = True zone_gid_idx = layer_field_index(zone_layer, GID_FIELD_NAME) for _f in layer_features(zone_layer): gid = _f.attributeMap()[zone_gid_idx].toString() area = _f.attributeMap()[bldg_area_idx].toDouble()[0] if zone_area.has_key(gid): zone_area[gid] = str(float(zone_area[gid])) + area else: zone_area[gid] = area # 3. intersect grids and zones to obtain polygons with # - grid_id and zone_id # - ratio of grid covered by zone (polygon area / zone area) # apply ratio to zone building count to obtain count assigned to polygon tmp_join = "joined_%s" % get_unique_filename() tmp_join_file = "%s%s.shp" % (self._tmp_dir, tmp_join) try: # do intersection analyzer.intersection(tmp_grid_lyr1, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # do tally zone_gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME) grid_gid_idx = layer_field_index(tmp_join_layer, "GRID_GID") bldg_cnt_idx = layer_field_index(tmp_join_layer, count_field) for _f in layer_features(tmp_join_layer): geom = _f.geometry() geom.transform(mercator_transform) area = geom.area() # generate all stats of interest zone_gid = _f.attributeMap()[zone_gid_idx].toString() grid_gid = _f.attributeMap()[grid_gid_idx].toString() stat = zone_stat[zone_gid] # calculate count/area as proportion of total zone area area_ratio = area / stat[area_idx] if bldg_cnt_idx > 0: bldg_cnt = _f.attributeMap()[bldg_cnt_idx].toDouble()[0] * area_ratio else: bldg_cnt = 0 if zone_has_area: area = zone_area[zone_gid] * area_ratio else: area = stat[area_idx] * area_ratio self._update_stat(zone_stat2, "%s|%s" % (grid_gid, zone_gid), bldg_cnt, area) # 4. find total buildings in each zone based on footprint # - simply join the files and tally count and total area tmp_join1 = "joined_%s" % get_unique_filename() tmp_join1_file = "%s%s.shp" % (self._tmp_dir, tmp_join1) try: # do intersection analyzer.intersection(fp_layer, tmp_join_layer, tmp_join1_file) tmp_join1_layer = load_shapefile(tmp_join1_file, tmp_join1) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # do tally zone_fp_stat = {} zone_gid_idx = layer_field_index(tmp_join1_layer, "%s_" % GID_FIELD_NAME) grid_gid_idx = layer_field_index(tmp_join1_layer, "GRID_GID") fp_area_idx = layer_field_index(tmp_join1_layer, AREA_FIELD_NAME) fp_ht_idx = layer_field_index(tmp_join1_layer, HT_FIELD_NAME) fp_has_height = False for _f in layer_features(tmp_join1_layer): zone_gid = _f.attributeMap()[zone_gid_idx].toString() grid_gid = _f.attributeMap()[grid_gid_idx].toString() area = _f.attributeMap()[fp_area_idx].toDouble()[0] # area comes from geometry, always exists ht = _f.attributeMap()[fp_ht_idx].toDouble()[0] if ht > 0: fp_has_height = True area *= ht # this is actual area to be aggregated at the end self._update_stat(zone_fp_stat, "%s|%s" % (grid_gid, zone_gid), 1, area) self._update_stat(zone_totals, zone_gid, 1, area) # 5. generate grid with adjusted building counts fields = { 0: QgsField(GID_FIELD_NAME, QVariant.String), 1: QgsField(zone_field, QVariant.String), 2: QgsField(CNT_FIELD_NAME, QVariant.Double), 3: QgsField(AREA_FIELD_NAME, QVariant.Double), } output_layername = "grid_%s" % get_unique_filename() output_file = "%s%s.shp" % (self._tmp_dir, output_layername) writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for key in zone_stat2.keys(): (grid_gid, zone_gid) = str(key).split("|") s_zone = zone_stat[QString(zone_gid)] # overall statistics for the zone from zone file (always exists) s_zone_grid = zone_stat2[key] # grid specific statistic from from zone file (always exists) if zone_totals.has_key(QString(zone_gid)): # overall statistics for the zone from footprints s_total = zone_totals[QString(zone_gid)] else: s_total = [0, 0] # set to zero if missing if zone_fp_stat.has_key(key): # grid specific statistic from from footprint s_fp = zone_fp_stat[key] else: s_fp = [0, 0] # set to zero if missing zone_leftover_count = s_zone[cnt_idx] - s_total[cnt_idx] if zone_has_area: zone_leftover_area = zone_area[QString(zone_gid)] - s_total[area_idx] else: zone_leftover_area = s_zone[area_idx] - s_total[area_idx] if zone_leftover_count > 0: # there are still building not accounted for # distribute to grid based on ratio of grid leftover area over zone leftover area # (leftover area is area of zone after subtracting footprint areas grid_leftover_count = zone_leftover_count * ( (s_zone_grid[area_idx] - s_fp[area_idx]) / zone_leftover_area ) grid_count = s_fp[cnt_idx] + grid_leftover_count else: grid_count = s_fp[cnt_idx] if fp_has_height: # area can be actual area based on footprint area * height area = s_fp[area_idx] elif zone_has_area: area = s_zone_grid[area_idx] else: # no area defined area = 0 # max(s_zone_grid[area_idx], s_fp[area_idx]) f.setGeometry(self._outputGeometryFromGridId(grid_gid)) f.addAttribute(0, grid_gid) f.addAttribute(1, zone_names[QString(zone_gid)]) f.addAttribute(2, grid_count) f.addAttribute(3, area) writer.addFeature(f) del writer # clean up del tmp_grid_lyr1 del tmp_join_layer del tmp_join1_layer remove_shapefile(tmp_grid1_file) remove_shapefile(tmp_join_file) remove_shapefile(tmp_join1_file) # store data in output self._load_output(output_file, output_layername)
@logAPICall def do_operation(self): """ perform apply mapping scheme operation """ # input/output data checking already done during property set src_layer = self.inputs[0].value zone_field = self.inputs[1].value count_field = self.inputs[2].value ms = self.inputs[3].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(src_layer) self._test_layer_field_exists(src_layer, zone_field) self._test_layer_field_exists(src_layer, count_field) # loop through all zones and assign mapping scheme # outputs exposure_layername = 'exp_%s' % get_unique_filename() exposure_file = '%sexp_%s.shp' % (self._tmp_dir, exposure_layername) # loop through all input features provider = src_layer.dataProvider() if provider is None: raise OperatorError("input layer not correctly loaded", self.__class__) zone_idx = layer_field_index(src_layer, zone_field) if zone_idx == -1: raise OperatorError("field %s not found in input layer" % zone_field, self.__class__) count_idx = layer_field_index(src_layer, count_field) if count_idx == -1: raise OperatorError("field %s not found in input layer" % count_field, self.__class__) gid_idx = layer_field_index(src_layer, GID_FIELD_NAME) if gid_idx == -1: raise OperatorError("field %s not found in input layer" % GID_FIELD_NAME, self.__class__) area_idx = layer_field_index(src_layer, AREA_FIELD_NAME) provider.select(provider.attributeIndexes(), provider.extent()) provider.rewind() try: writer = QgsVectorFileWriter(exposure_file, "utf-8", self._fields, provider.geometryType(), self._crs, "ESRI Shapefile") out_feature = QgsFeature() gid = 0 for in_feature in layer_features(src_layer): geom = in_feature.geometry() centroid = geom.centroid().asPoint () gid = in_feature.attributeMap()[gid_idx] zone_str = str(in_feature.attributeMap()[zone_idx].toString()) count = in_feature.attributeMap()[count_idx].toDouble()[0] if area_idx > 0: area = in_feature.attributeMap()[area_idx].toDouble()[0] else: area = 0 count = int(count+0.5) if count == 0: continue stats = ms.get_assignment_by_name(zone_str) # use default stats if missing if stats is None: raise Exception("no mapping scheme found for zone %s" % zone_str) for _sample in stats.get_samples(count, self._extrapolationOption): # write out if there are structures assigned _type = _sample[0] _cnt = _sample[1] if area > 0: # use area provided by footprint/zone if defined _size = area * ( float(_sample[1]) / count ) if _sample[3] > 0 and _sample[2] > 0: _cost = (_sample[3] / _sample[2]) * area else: _cost = 0 else: # use mapping scheme generic area otherwise _size = _sample[2] _cost = _sample[3] if _cnt > 0: out_feature.setGeometry(geom) #out_feature.addAttribute(0, QVariant(gid)) out_feature.addAttribute(0, gid) out_feature.addAttribute(1, QVariant(centroid.x())) out_feature.addAttribute(2, QVariant(centroid.y())) out_feature.addAttribute(3, QVariant(_type)) out_feature.addAttribute(4, QVariant(zone_str)) out_feature.addAttribute(5, QVariant(_cnt)) out_feature.addAttribute(6, QVariant(_size)) out_feature.addAttribute(7, QVariant(_cost)) writer.addFeature(out_feature) del writer, out_feature except Exception as err: remove_shapefile(exposure_file) raise OperatorError("error creating exposure file: %s" % err, self.__class__) del src_layer # load shapefile as layer exposure_layer = load_shapefile(exposure_file, exposure_layername) if not exposure_layer: raise OperatorError('Error loading exposure file' % (exposure_file), self.__class__) # store data in output self.outputs[0].value = exposure_layer
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput fp_layer = self.inputs[0].value zone_field = self.inputs[1].value # aggregate footprint into grids logAPICall.log('aggregate statistic for grid ...', logAPICall.DEBUG) total_features = fp_layer.dataProvider().featureCount() if total_features > MAX_FEATURES_IN_MEMORY: # use bsddb to store temporary lat/lon tmp_db_file = '%sdb_%s.db' % (self._tmp_dir, get_unique_filename()) db = bsddb.btopen(tmp_db_file, 'c') use_db = True else: db = {} use_db = False zone_idx = layer_field_index(fp_layer, zone_field) for f in layer_features(fp_layer): geom = f.geometry() zone_str = str(f.attributeMap()[zone_idx].toString()) centroid = geom.centroid().asPoint() # use floor, this truncates all points within grid to grid's # bottom-left corner x = math.floor(centroid.x() / DEFAULT_GRID_SIZE) y = math.floor(centroid.y() / DEFAULT_GRID_SIZE) key = '%s %d %d' % (zone_str, x,y) if db.has_key(key): db[key] = str(int(db[key]) + 1) else: db[key] = '1' # output grid logAPICall.log('create grid ...', logAPICall.DEBUG) fields = { 0 : QgsField(self._lon_field, QVariant.Double), 1 : QgsField(self._lat_field, QVariant.Double), 2 : QgsField(CNT_FIELD_NAME, QVariant.Double), 3 : QgsField(zone_field, QVariant.String), } grid_layername = 'grid_%s' % get_unique_filename() grid_file = '%s%s.shp' % (self._tmp_dir, grid_layername) try: writer = QgsVectorFileWriter(grid_file, "utf-8", fields, QGis.WKBPoint , self._crs, "ESRI Shapefile") f = QgsFeature() for key, val in db.iteritems(): (zone_str, x, y) = key.split(' ') # point were aggregated to grid's bottom-left corner # add half grid size to place point at center of grid point = QgsPoint(int(x)*DEFAULT_GRID_SIZE+(DEFAULT_GRID_SIZE/2.0), int(y)*DEFAULT_GRID_SIZE+(DEFAULT_GRID_SIZE/2.0)) f.setGeometry(QgsGeometry.fromPoint(point)) f.addAttribute(0, QVariant(point.x())) f.addAttribute(1, QVariant(point.y())) f.addAttribute(2, QVariant(val)) f.addAttribute(3, QVariant(zone_str)) writer.addFeature(f) del writer except Exception as err: remove_shapefile(grid_file) raise OperatorError("error creating joined grid: " % err, self.__class__) grid_layer = load_shapefile(grid_file, grid_layername) if not grid_layer: raise OperatorError('Error loading created grid file' % (grid_file), self.__class__) # clean up if use_db: db.close() os.remove(tmp_db_file) # done self.outputs[0].value = grid_layer self.outputs[1].value = grid_file
def createFeature(self, geom): # layer = self.canvas.currentLayer() layer = self.iface.activeLayer() provider = layer.dataProvider() f = QgsFeature() if (geom.isGeosValid()): f.setGeometry(geom) else: reply = QMessageBox.question(self.iface.mainWindow(), 'Feature not valid', "The geometry of the feature you just added isn't valid. Do you want to use it anyway?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: f.setGeometry(geom) else: return False # Add attribute fields to feature. fields = layer.pendingFields() try: #API-Break 1.8 vs. 2.0 handling attr = f.initAttributes(len(fields)) #@UnusedVariable for i in range(len(fields)): f.setAttribute(i, provider.defaultValue(i)) except AttributeError: #<=1.8 # Add attributefields to feature. for i in fields: f.addAttribute(i, provider.defaultValue(i)) idx = layer.fieldNameIndex('epa_type') f[idx] = self.elem_type_type # Upload changes layer.startEditing() layer.addFeature(f) # Control PostgreSQL exceptions boolOk = layer.commitChanges() # Update canvas self.canvas.refresh() # Capture edit exception if boolOk: # Spatial query to retrieve last added line, start searchingcandidates cands = layer.getFeatures(QgsFeatureRequest().setFilterRect(f.geometry().boundingBox())) # Iterate on candidates for line_feature in cands: if line_feature.geometry().equals(f.geometry()): # Highlight layer.setSelectedFeatures([line_feature.id()]) # Open form self.iface.openFeatureForm(layer, line_feature) break else: # Delete layer.rollBack() # User error msg = "Error adding PIPE: Typically this occurs if\n the first point is not located in a existing\n node or feature is out of the defined sectors." QMessageBox.information(None, "PostgreSQL error:", msg)
def do_operation(self): """ perform create mapping scheme operation """ # validate inputs fp_layer = self.inputs[0].value zone_layer = self.inputs[1].value zone_field = self.inputs[2].value count_field = self.inputs[3].value area_field = self.inputs[4].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(fp_layer) self._test_layer_loaded(zone_layer) self._test_layer_field_exists(zone_layer, GID_FIELD_NAME) self._test_layer_field_exists(zone_layer, zone_field) # count_field is not required # if count field is not defined, then generate building count from footprints # area_field is not required # local variables analyzer = QgsOverlayAnalyzer() area_idx = ToGrid.STAT_AREA_IDX cnt_idx = ToGrid.STAT_COUNT_IDX zone_names, zone_stat, zone_stat2, zone_totals = {}, {}, {}, {} # 1. find building count and total area for each zone # project geometry into mercator and get area in m2 mercator_crs = QgsCoordinateReferenceSystem() mercator_crs.createFromEpsg(3395) mercator_transform = QgsCoordinateTransform(zone_layer.crs(), mercator_crs) try: # use zone geometry area self._create_zone_statistics(zone_layer, zone_field, count_field, zone_stat, zone_names) except Exception as err: raise OperatorError(str(err), self.__class__) # 2. create grids around extent of zone tmp_grid1 = 'grid_' + get_unique_filename() tmp_grid1_file = self._tmp_dir + tmp_grid1 + '.shp' extent = zone_layer.extent() [x_min, y_min, x_max, y_max] = [extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum()] tmp_grid_lyr1 = self._create_grid(tmp_grid1, tmp_grid1_file, \ x_min, y_min, x_max, y_max, \ DEFAULT_GRID_SIZE, DEFAULT_GRID_SIZE) # tally total building area if there is defined bldg_area_idx = layer_field_index(zone_layer, area_field) zone_area = {} zone_has_area = False if bldg_area_idx > 0: zone_has_area = True zone_gid_idx = layer_field_index(zone_layer, GID_FIELD_NAME) for _f in layer_features(zone_layer): gid = _f.attributeMap()[zone_gid_idx].toString() area = _f.attributeMap()[bldg_area_idx].toDouble()[0] if zone_area.has_key(gid): zone_area[gid] = str(float(zone_area[gid]))+area else: zone_area[gid] = area # 3. intersect grids and zones to obtain polygons with # - grid_id and zone_id # - ratio of grid covered by zone (polygon area / zone area) # apply ratio to zone building count to obtain count assigned to polygon tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) try: # do intersection analyzer.intersection(tmp_grid_lyr1, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile(tmp_join_file, tmp_join) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # do tally zone_gid_idx = layer_field_index(tmp_join_layer, GID_FIELD_NAME) grid_gid_idx = layer_field_index(tmp_join_layer, "GRID_GID") bldg_cnt_idx = layer_field_index(tmp_join_layer, count_field) for _f in layer_features(tmp_join_layer): geom = _f.geometry() geom.transform(mercator_transform) area = geom.area() # generate all stats of interest zone_gid = _f.attributeMap()[zone_gid_idx].toString() grid_gid = _f.attributeMap()[grid_gid_idx].toString() stat = zone_stat[zone_gid] # calculate count/area as proportion of total zone area area_ratio = (area/stat[area_idx]) if bldg_cnt_idx > 0: bldg_cnt = _f.attributeMap()[bldg_cnt_idx].toDouble()[0] * area_ratio else: bldg_cnt = 0 if zone_has_area: area = zone_area[zone_gid] * area_ratio else: area = stat[area_idx] * area_ratio self._update_stat(zone_stat2, '%s|%s'%(grid_gid, zone_gid), bldg_cnt, area) # 4. find total buildings in each zone based on footprint # - simply join the files and tally count and total area tmp_join1 = 'joined_%s' % get_unique_filename() tmp_join1_file = '%s%s.shp' % (self._tmp_dir, tmp_join1) try: # do intersection analyzer.intersection(fp_layer, tmp_join_layer, tmp_join1_file) tmp_join1_layer = load_shapefile(tmp_join1_file, tmp_join1) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) # do tally zone_fp_stat = {} zone_gid_idx = layer_field_index(tmp_join1_layer, '%s_'% GID_FIELD_NAME) grid_gid_idx = layer_field_index(tmp_join1_layer, "GRID_GID") fp_area_idx = layer_field_index(tmp_join1_layer, AREA_FIELD_NAME) fp_ht_idx = layer_field_index(tmp_join1_layer, HT_FIELD_NAME) fp_has_height = False for _f in layer_features(tmp_join1_layer): zone_gid = _f.attributeMap()[zone_gid_idx].toString() grid_gid = _f.attributeMap()[grid_gid_idx].toString() area = _f.attributeMap()[fp_area_idx].toDouble()[0] # area comes from geometry, always exists ht = _f.attributeMap()[fp_ht_idx].toDouble()[0] if ht > 0: fp_has_height = True area *= ht # this is actual area to be aggregated at the end self._update_stat(zone_fp_stat, '%s|%s'%(grid_gid, zone_gid), 1, area) self._update_stat(zone_totals, zone_gid, 1, area) # 5. generate grid with adjusted building counts fields = { 0 : QgsField(GID_FIELD_NAME, QVariant.String), 1 : QgsField(zone_field, QVariant.String), 2 : QgsField(CNT_FIELD_NAME, QVariant.Double), 3 : QgsField(AREA_FIELD_NAME, QVariant.Double), } output_layername = 'grid_%s' % get_unique_filename() output_file = '%s%s.shp' % (self._tmp_dir, output_layername) writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPolygon, self._crs, "ESRI Shapefile") f = QgsFeature() for key in zone_stat2.keys(): (grid_gid, zone_gid) = str(key).split("|") s_zone = zone_stat[QString(zone_gid)] # overall statistics for the zone from zone file (always exists) s_zone_grid = zone_stat2[key] # grid specific statistic from from zone file (always exists) if zone_totals.has_key(QString(zone_gid)): # overall statistics for the zone from footprints s_total = zone_totals[QString(zone_gid)] else: s_total = [0,0] # set to zero if missing if zone_fp_stat.has_key(key): # grid specific statistic from from footprint s_fp = zone_fp_stat[key] else: s_fp = [0, 0] # set to zero if missing zone_leftover_count = s_zone[cnt_idx] - s_total[cnt_idx] if zone_has_area: zone_leftover_area = zone_area[QString(zone_gid)] - s_total[area_idx] else: zone_leftover_area = s_zone[area_idx] - s_total[area_idx] if zone_leftover_count > 0: # there are still building not accounted for # distribute to grid based on ratio of grid leftover area over zone leftover area # (leftover area is area of zone after subtracting footprint areas grid_leftover_count = zone_leftover_count * ((s_zone_grid[area_idx]-s_fp[area_idx])/zone_leftover_area) grid_count = s_fp[cnt_idx] + grid_leftover_count else: grid_count = s_fp[cnt_idx] if fp_has_height: # area can be actual area based on footprint area * height area = s_fp[area_idx] elif zone_has_area: area = s_zone_grid[area_idx] else: # no area defined area = 0 # max(s_zone_grid[area_idx], s_fp[area_idx]) f.setGeometry(self._outputGeometryFromGridId(grid_gid)) f.addAttribute(0, grid_gid) f.addAttribute(1, zone_names[QString(zone_gid)]) f.addAttribute(2, grid_count) f.addAttribute(3, area) writer.addFeature(f) del writer # clean up del tmp_grid_lyr1 del tmp_join_layer del tmp_join1_layer remove_shapefile(tmp_grid1_file) remove_shapefile(tmp_join_file) remove_shapefile(tmp_join1_file) # store data in output self._load_output(output_file, output_layername)
def do_operation(self): """ perform footprint load operation """ # input/output data checking already done during property set zone_layer = self.inputs[0].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(zone_layer) x_off = self._x_off y_off = self._y_off extent = zone_layer.extent() [x_min, y_min, x_max, y_max] = [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ] # create grid based on extent of given region tmp_grid1 = 'grid_' + get_unique_filename() tmp_grid1_file = self._tmp_dir + tmp_grid1 + '.shp' try: self._write_grid_shapefile(tmp_grid1_file, x_min, y_min, x_max, y_max, x_off, y_off) except: remove_shapefile(tmp_grid1_file) raise OperatorError('error creating temporary grid', self.__class__) tmp_grid1_layer = load_shapefile(tmp_grid1_file, tmp_grid1) # temporary grid for joined shape with all grid points not within region removed tmp_grid2 = 'grid_' + get_unique_filename() tmp_grid2_file = self._tmp_dir + tmp_grid2 + '.shp' tmp_grid2_layer = None try: analyzer = QgsOverlayAnalyzer() analyzer.intersection(tmp_grid1_layer, zone_layer, tmp_grid2_file) tmp_grid2_layer = load_shapefile(tmp_grid2_file, tmp_grid2) except: raise OperatorError('error creating grid', self.__class__) # create result layer grid_layername = 'grid_%s' % get_unique_filename() grid_file = self._tmp_dir + grid_layername + '.shp' try: writer = QgsVectorFileWriter(grid_file, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() lon_idx = layer_field_index(tmp_grid2_layer, self._lon_field) lat_idx = layer_field_index(tmp_grid2_layer, self._lat_field) for _f in layer_features(tmp_grid2_layer): lon = _f.attributeMap()[lon_idx].toDouble()[0] lat = _f.attributeMap()[lat_idx].toDouble()[0] f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(lon)) f.addAttribute(1, QVariant(lat)) writer.addFeature(f) del writer except Exception as err: logAPICall.log(str(err), logAPICall.ERROR) raise OperatorError('error writing out grid', self.__class__) grid_layer = load_shapefile(grid_file, grid_layername) if not grid_layer: raise OperatorError('Error loading result grid file' % (grid_file), self.__class__) # clean up del analyzer, tmp_grid1_layer, tmp_grid2_layer remove_shapefile(tmp_grid1_file) remove_shapefile(tmp_grid2_file) self.outputs[0].value = grid_layer self.outputs[1].value = grid_file
def do_operation(self): """ perform create mapping scheme operation """ # input/output verification already performed during set input/ouput zone_layer = self.inputs[0].value zone_field = self.inputs[1].value fp_layer = self.inputs[2].value # merge with zone to get assignment tmp_join = 'joined_%s' % get_unique_filename() tmp_join_file = '%s%s.shp' % (self._tmp_dir, tmp_join) analyzer = QgsOverlayAnalyzer() try: analyzer.intersection(fp_layer, zone_layer, tmp_join_file) tmp_join_layer = load_shapefile_verify(tmp_join_file, tmp_join, [zone_field]) except AssertionError as err: raise OperatorError(str(err), self.__class__) except Exception as err: raise OperatorError(str(err), self.__class__) fields = { 0: QgsField(self._lon_field, QVariant.Double), 1: QgsField(self._lat_field, QVariant.Double), 2: QgsField(zone_field, QVariant.String), } zone_idx = layer_field_index(tmp_join_layer, zone_field) fp_layername = 'fpc_%s' % get_unique_filename() fp_file = '%s%s.shp' % (self._tmp_dir, fp_layername) try: writer = QgsVectorFileWriter(fp_file, "utf-8", fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() for _f in layer_features(tmp_join_layer): centroid = _f.geometry().centroid().asPoint() lon = centroid.x() lat = centroid.y() zone_str = str(_f.attributeMap()[zone_idx].toString()).upper() f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(lon)) f.addAttribute(1, QVariant(lat)) f.addAttribute(2, QVariant(zone_str)) writer.addFeature(f) del writer except Exception as err: logAPICall.log(err, logAPICall.ERROR) remove_shapefile(fp_file) raise OperatorError("error creating joined grid: %s" % err, self.__class__) # load shapefile as layer fp_layer = load_shapefile(fp_file, fp_layername) if not fp_layer: raise OperatorError( 'Error loading footprint centroid file' % (fp_file), self.__class__) # clean up del tmp_join_layer remove_shapefile(tmp_join_file) self.outputs[0].value = fp_layer self.outputs[1].value = fp_file
def do_operation(self): """ perform footprint load operation """ # input/output data checking already done during property set zone_layer = self.inputs[0].value # make sure input is correct # NOTE: these checks cannot be performed at set input time # because the data layer maybe is not loaded yet self._test_layer_loaded(zone_layer) x_off = self._x_off y_off = self._y_off extent = zone_layer.extent() [x_min, y_min, x_max, y_max] = [extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum()] # create grid based on extent of given region tmp_grid1 = 'grid_' + get_unique_filename() tmp_grid1_file = self._tmp_dir + tmp_grid1 + '.shp' try: self._write_grid_shapefile(tmp_grid1_file, x_min, y_min, x_max, y_max, x_off, y_off) except: remove_shapefile(tmp_grid1_file) raise OperatorError('error creating temporary grid', self.__class__) tmp_grid1_layer = load_shapefile(tmp_grid1_file, tmp_grid1) # temporary grid for joined shape with all grid points not within region removed tmp_grid2 = 'grid_' + get_unique_filename() tmp_grid2_file = self._tmp_dir + tmp_grid2 + '.shp' tmp_grid2_layer = None try: analyzer = QgsOverlayAnalyzer() analyzer.intersection(tmp_grid1_layer, zone_layer, tmp_grid2_file) tmp_grid2_layer = load_shapefile(tmp_grid2_file, tmp_grid2) except: raise OperatorError('error creating grid', self.__class__) # create result layer grid_layername = 'grid_%s' % get_unique_filename() grid_file = self._tmp_dir + grid_layername + '.shp' try: writer = QgsVectorFileWriter(grid_file, "utf-8", self._fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() lon_idx = layer_field_index(tmp_grid2_layer, self._lon_field) lat_idx = layer_field_index(tmp_grid2_layer, self._lat_field) for _f in layer_features(tmp_grid2_layer): lon = _f.attributeMap()[lon_idx].toDouble()[0] lat = _f.attributeMap()[lat_idx].toDouble()[0] f.setGeometry(QgsGeometry.fromPoint(QgsPoint(lon, lat))) f.addAttribute(0, QVariant(lon)) f.addAttribute(1, QVariant(lat)) writer.addFeature(f) del writer except Exception as err: logAPICall.log(str(err), logAPICall.ERROR) raise OperatorError('error writing out grid', self.__class__) grid_layer = load_shapefile(grid_file, grid_layername) if not grid_layer: raise OperatorError('Error loading result grid file' % (grid_file), self.__class__) # clean up del analyzer, tmp_grid1_layer, tmp_grid2_layer remove_shapefile(tmp_grid1_file) remove_shapefile(tmp_grid2_file) self.outputs[0].value = grid_layer self.outputs[1].value = grid_file
def do_operation(self): """ perform footprint load operation """ # input/output data checking already done during property set # load and verify popgrid_file = self.inputs[0].value pop_field = self.inputs[1].value popgrid_layername = 'zone_%s' % get_unique_filename() try: tmp_popgrid_layer = load_shapefile_verify(popgrid_file, popgrid_layername, [pop_field]) except AssertionError as err: raise OperatorError(str(err), self.__class__) logAPICall.log( 'tmp_fp_layer.crs().epsg() %s ' % tmp_popgrid_layer.crs().epsg(), logAPICall.DEBUG) if tmp_popgrid_layer.crs().epsg() != self._crs.epsg(): transform = QgsCoordinateTransform(tmp_popgrid_layer.crs(), self._crs) transform_required = True else: transform_required = False # output grid fields = { 0: QgsField(GID_FIELD_NAME, QVariant.Int), 1: QgsField(CNT_FIELD_NAME, QVariant.Double), } pop_idx = layer_field_index(tmp_popgrid_layer, pop_field) output_file = '%spop_grid_%s.shp' % (self._tmp_dir, get_unique_filename()) logAPICall.log('create outputfile %s ... ' % output_file, logAPICall.DEBUG) try: writer = QgsVectorFileWriter(output_file, "utf-8", fields, QGis.WKBPoint, self._crs, "ESRI Shapefile") f = QgsFeature() gid = 0 for _f in layer_features(tmp_popgrid_layer): # NOTE: geom.transform does projection in place to underlying C object # 1. get geometry geom = _f.geometry() # 2. change project if required if transform_required: geom = transform.transform(geom) # 3. write to file gid += 1 f.setGeometry(geom) f.addAttribute(0, QVariant(gid)) f.addAttribute(1, _f.attributeMap()[pop_idx]) writer.addFeature(f) del writer, f except Exception as err: remove_shapefile(output_file) raise OperatorError("error creating footprint centroids: %s" % err, self.__class__) popgrid_layername = 'popgrid_%s' % get_unique_filename() popgrid_layer = load_shapefile(output_file, popgrid_layername) if not popgrid_layer: raise OperatorError( 'Error loading footprint centroid file' % (output_file), self.__class__) # clean up del tmp_popgrid_layer # store data in output self.outputs[0].value = popgrid_layer self.outputs[1].value = output_file