def testJSONExporter(self): """ test converting features to GeoJSON """ fields = QgsFields() fields.append(QgsField("name", QVariant.String)) fields.append(QgsField("cost", QVariant.Double)) fields.append(QgsField("population", QVariant.Int)) feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPointV2(5, 6))) feature.setAttributes(['Valsier Peninsula', 6.8, 198]) exporter = QgsJSONExporter() expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) # test with linestring for bbox inclusion l = QgsLineString() l.setPoints([QgsPointV2(5, 6), QgsPointV2(15, 16)]) feature.setGeometry(QgsGeometry(QgsLineString(l))) expected = """{ "type":"Feature", "id":5, "bbox":[5, 6, 15, 16], "geometry": {"type": "LineString", "coordinates": [ [5, 6], [15, 16]]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) # test that precision is respected feature.setGeometry(QgsGeometry(QgsPointV2(5.444444444, 6.333333333))) exporter.setPrecision(3) self.assertEqual(exporter.precision(), 3) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5.444, 6.333]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) feature.setGeometry(QgsGeometry(QgsPointV2(5, 6))) exporter.setPrecision(17) # test that attribute subset is respected exporter.setAttributes([0, 2]) self.assertEqual(exporter.attributes(), [0, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([1]) self.assertEqual(exporter.attributes(), [1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "cost":6.8 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([]) # text excluding attributes exporter.setExcludedAttributes([1]) self.assertEqual(exporter.excludedAttributes(), [1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setExcludedAttributes([1, 2]) self.assertEqual(exporter.excludedAttributes(), [1, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula" } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setExcludedAttributes([0, 1, 2]) self.assertEqual(exporter.excludedAttributes(), [0, 1, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) # test that excluded attributes take precedence over included exporter.setAttributes([1, 2]) exporter.setExcludedAttributes([0, 1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([]) exporter.setExcludedAttributes([]) # test excluding geometry exporter.setIncludeGeometry(False) self.assertEqual(exporter.includeGeometry(), False) feature.setGeometry(QgsGeometry(QgsLineString(l))) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeGeometry(True) feature.setGeometry(QgsGeometry(QgsPointV2(5, 6))) # test excluding attributes exporter.setIncludeAttributes(False) self.assertEqual(exporter.includeAttributes(), False) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeGeometry(False) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeAttributes(True) # test overriding ID expected = """{ "type":"Feature", "id":29, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature, id=29), expected) # test injecting extra attributes expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198, "extra":"val1", "extra2":2 } }""" self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": 2}), expected) exporter.setIncludeAttributes(False) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "extra":"val1", "extra2":{"nested_map":5, "nested_map2":"val"}, "extra3":[1,2,3] } }""" self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": {"nested_map": 5, "nested_map2": "val"}, "extra3": [1, 2, 3]}), expected) exporter.setIncludeGeometry(True)
def testJSONExporter(self): """ test converting features to GeoJSON """ fields = QgsFields() fields.append(QgsField("name", QVariant.String)) fields.append(QgsField("cost", QVariant.Double)) fields.append(QgsField("population", QVariant.Int)) feature = QgsFeature(fields, 5) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) feature.setAttributes(['Valsier Peninsula', 6.8, 198]) exporter = QgsJsonExporter() expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) # test with linestring for bbox inclusion l = QgsLineString() l.setPoints([QgsPoint(5, 6), QgsPoint(15, 16)]) feature.setGeometry(QgsGeometry(QgsLineString(l))) expected = """{ "type":"Feature", "id":5, "bbox":[5, 6, 15, 16], "geometry": {"type": "LineString", "coordinates": [ [5, 6], [15, 16]]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) # test that precision is respected feature.setGeometry(QgsGeometry(QgsPoint(5.444444444, 6.333333333))) exporter.setPrecision(3) self.assertEqual(exporter.precision(), 3) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5.444, 6.333]}, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) exporter.setPrecision(17) # test that attribute subset is respected exporter.setAttributes([0, 2]) self.assertEqual(exporter.attributes(), [0, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([1]) self.assertEqual(exporter.attributes(), [1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "cost":6.8 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([]) # text excluding attributes exporter.setExcludedAttributes([1]) self.assertEqual(exporter.excludedAttributes(), [1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula", "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setExcludedAttributes([1, 2]) self.assertEqual(exporter.excludedAttributes(), [1, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "name":"Valsier Peninsula" } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setExcludedAttributes([0, 1, 2]) self.assertEqual(exporter.excludedAttributes(), [0, 1, 2]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) # test that excluded attributes take precedence over included exporter.setAttributes([1, 2]) exporter.setExcludedAttributes([0, 1]) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":{ "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setAttributes([]) exporter.setExcludedAttributes([]) # test excluding geometry exporter.setIncludeGeometry(False) self.assertEqual(exporter.includeGeometry(), False) feature.setGeometry(QgsGeometry(QgsLineString(l))) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeGeometry(True) feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) # test excluding attributes exporter.setIncludeAttributes(False) self.assertEqual(exporter.includeAttributes(), False) expected = """{ "type":"Feature", "id":5, "geometry": {"type": "Point", "coordinates": [5, 6]}, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeGeometry(False) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":null }""" self.assertEqual(exporter.exportFeature(feature), expected) exporter.setIncludeAttributes(True) # test overriding ID expected = """{ "type":"Feature", "id":29, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198 } }""" self.assertEqual(exporter.exportFeature(feature, id=29), expected) # test injecting extra attributes expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "name":"Valsier Peninsula", "cost":6.8, "population":198, "extra":"val1", "extra2":2 } }""" self.assertEqual( exporter.exportFeature(feature, extraProperties={ "extra": "val1", "extra2": 2 }), expected) exporter.setIncludeAttributes(False) expected = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "extra":"val1", "extra2":{"nested_map":5, "nested_map2":"val"}, "extra3":[1,2,3] } }""" expected2 = """{ "type":"Feature", "id":5, "geometry":null, "properties":{ "extra":"val1", "extra2":{"nested_map":5,"nested_map2":"val"}, "extra3":[1,2,3] } }""" exp_f = exporter.exportFeature(feature, extraProperties={ "extra": "val1", "extra2": { "nested_map": 5, "nested_map2": "val" }, "extra3": [1, 2, 3] }) self.assertTrue(exp_f == expected or exp_f == expected2) exporter.setIncludeGeometry(True)
def processAlgorithm(self, feedback): extent = self.getParameterValue(self.EXTENT).split(',') hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) hOverlay = self.getParameterValue(self.HOVERLAY) vOverlay = self.getParameterValue(self.VOVERLAY) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: {0}/{1}').format( hSpacing, vSpacing)) if hSpacing <= hOverlay or vSpacing <= vOverlay: raise GeoAlgorithmExecutionException( self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay)) if width < hSpacing: raise GeoAlgorithmExecutionException( self.tr( 'Horizontal spacing is too small for the covered area')) if height < vSpacing: raise GeoAlgorithmExecutionException( self.tr('Vertical spacing is too small for the covered area')) fields = [ QgsField('left', QVariant.Double, '', 24, 16), QgsField('top', QVariant.Double, '', 24, 16), QgsField('right', QVariant.Double, '', 24, 16), QgsField('bottom', QVariant.Double, '', 24, 16), QgsField('id', QVariant.Int, '', 10, 0), QgsField('coord', QVariant.Double, '', 24, 15) ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.LineString, crs) if hOverlay > 0: hSpace = [hSpacing - hOverlay, hOverlay] else: hSpace = [hSpacing, hSpacing] if vOverlay > 0: vSpace = [vSpacing - vOverlay, vOverlay] else: vSpace = [vSpacing, vSpacing] feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPointV2(bbox.xMinimum(), y) pt2 = QgsPointV2(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) writer.addFeature(feat) y = y - vSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPointV2(x, bbox.yMaximum()) pt2 = QgsPointV2(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) writer.addFeature(feat) x = x + hSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) del writer
def processAlgorithm(self, progress): extent = self.getParameterValue(self.EXTENT).split(",") hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException(self.tr("Invalid grid spacing: %s/%s" % (hSpacing, vSpacing))) if width < hSpacing: raise GeoAlgorithmExecutionException(self.tr("Horizontal spacing is too small for the covered area")) if height < vSpacing: raise GeoAlgorithmExecutionException(self.tr("Vertical spacing is too small for the covered area")) fields = [ QgsField("left", QVariant.Double, "", 24, 16), QgsField("top", QVariant.Double, "", 24, 16), QgsField("right", QVariant.Double, "", 24, 16), QgsField("bottom", QVariant.Double, "", 24, 16), QgsField("id", QVariant.Int, "", 10, 0), QgsField("coord", QVariant.Double, "", 24, 15), ] writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.LineString, crs) feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPointV2(bbox.xMinimum(), y) pt2 = QgsPointV2(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) writer.addFeature(feat) y = y - vSpacing id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(int(count / count_max * 50)) progress.setPercentage(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPointV2(x, bbox.yMaximum()) pt2 = QgsPointV2(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) writer.addFeature(feat) x = x + hSpacing id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: progress.setPercentage(50 + int(count / count_max * 50)) del writer
def processAlgorithm(self, parameters, context, feedback): hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context) vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context) hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context) vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context) crs = self.parameterAsCrs(parameters, self.CRS, context) bbox = self.parameterAsExtent(parameters, self.EXTENT, context, crs) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise QgsProcessingException( self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing)) if hSpacing <= hOverlay or vSpacing <= vOverlay: raise QgsProcessingException( self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay)) if width < hSpacing: raise QgsProcessingException( self.tr('Horizontal spacing is too small for the covered area')) if height < vSpacing: raise QgsProcessingException( self.tr('Vertical spacing is too small for the covered area')) fields = QgsFields() fields.append(QgsField('left', QVariant.Double, '', 24, 16)) fields.append(QgsField('top', QVariant.Double, '', 24, 16)) fields.append(QgsField('right', QVariant.Double, '', 24, 16)) fields.append(QgsField('bottom', QVariant.Double, '', 24, 16)) fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('coord', QVariant.Double, '', 24, 15)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, crs) if hOverlay > 0: hSpace = [hSpacing - hOverlay, hOverlay] else: hSpace = [hSpacing, hSpacing] if vOverlay > 0: vSpace = [vSpacing - vOverlay, vOverlay] else: vSpace = [vSpacing, vSpacing] feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): if feedback.isCanceled(): break pt1 = QgsPoint(bbox.xMinimum(), y) pt2 = QgsPoint(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) sink.addFeature(feat, QgsFeatureSink.FastInsert) y = y - vSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): if feedback.isCanceled(): break pt1 = QgsPoint(x, bbox.yMaximum()) pt2 = QgsPoint(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) sink.addFeature(feat, QgsFeatureSink.FastInsert) x = x + hSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context) vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context) hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context) vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context) crs = self.parameterAsCrs(parameters, self.CRS, context) bbox = self.parameterAsExtent(parameters, self.EXTENT, context, crs) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise QgsProcessingException( self.tr('Invalid grid spacing: {0}/{1}').format( hSpacing, vSpacing)) if hSpacing <= hOverlay or vSpacing <= vOverlay: raise QgsProcessingException( self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay)) if width < hSpacing: raise QgsProcessingException( self.tr( 'Horizontal spacing is too small for the covered area')) if height < vSpacing: raise QgsProcessingException( self.tr('Vertical spacing is too small for the covered area')) fields = QgsFields() fields.append(QgsField('left', QVariant.Double, '', 24, 16)) fields.append(QgsField('top', QVariant.Double, '', 24, 16)) fields.append(QgsField('right', QVariant.Double, '', 24, 16)) fields.append(QgsField('bottom', QVariant.Double, '', 24, 16)) fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('coord', QVariant.Double, '', 24, 15)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, crs) if hOverlay > 0: hSpace = [hSpacing - hOverlay, hOverlay] else: hSpace = [hSpacing, hSpacing] if vOverlay > 0: vSpace = [vSpacing - vOverlay, vOverlay] else: vSpace = [vSpacing, vSpacing] feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): if feedback.isCanceled(): break pt1 = QgsPoint(bbox.xMinimum(), y) pt2 = QgsPoint(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) sink.addFeature(feat, QgsFeatureSink.FastInsert) y = y - vSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): if feedback.isCanceled(): break pt1 = QgsPoint(x, bbox.yMaximum()) pt2 = QgsPoint(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) sink.addFeature(feat, QgsFeatureSink.FastInsert) x = x + hSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) return {self.OUTPUT: dest_id}
def run(self): """Run method that performs all the real work""" # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started if self.first_start == True: self.first_start = False self.dlg = SurvexImportDialog() self.dlg.selectedFile.clear() self.dlg.fileSelector.clicked.connect(self.select_3d_file) self.dlg.selectedGPKG.clear() self.dlg.GPKGSelector.clicked.connect(self.select_gpkg) self.dlg.CRSFromProject.setChecked(False) self.dlg.CRSFromFile.clicked.connect(self.crs_from_file) self.dlg.CRSFromFile.setChecked(False) self.dlg.CRSFromProject.clicked.connect(self.crs_from_project) self.dlg.ImportAll.clicked.connect(self.toggle_import_all) self.dlg.Legs.clicked.connect(self.all_checked) self.dlg.Stations.clicked.connect(self.all_checked) self.dlg.Polygons.clicked.connect(self.all_checked) self.dlg.Walls.clicked.connect(self.all_checked) self.dlg.XSections.clicked.connect(self.all_checked) self.dlg.Traverses.clicked.connect(self.all_checked) self.dlg.LegsSurface.clicked.connect(self.all_checked) self.dlg.LegsSplay.clicked.connect(self.all_checked) self.dlg.LegsDuplicate.clicked.connect(self.all_checked) self.dlg.StationsSurface.clicked.connect(self.all_checked) self.dlg.show() # show the dialog result = self.dlg.exec_() # Run the dialog event loop if result: # The user pressed OK, and this is what happened next! survex_3d = self.dlg.selectedFile.text() gpkg_file = self.dlg.selectedGPKG.text() include_legs = self.dlg.Legs.isChecked() include_stations = self.dlg.Stations.isChecked() include_polygons = self.dlg.Polygons.isChecked() include_walls = self.dlg.Walls.isChecked() include_xsections = self.dlg.XSections.isChecked() include_traverses = self.dlg.Traverses.isChecked() exclude_surface_legs = not self.dlg.LegsSurface.isChecked() exclude_splay_legs = not self.dlg.LegsSplay.isChecked() exclude_duplicate_legs = not self.dlg.LegsDuplicate.isChecked() exclude_surface_stations = not self.dlg.StationsSurface.isChecked() use_clino_wgt = self.dlg.UseClinoWeights.isChecked() include_up_down = self.dlg.IncludeUpDown.isChecked() discard_features = not self.dlg.KeepFeatures.isChecked() if not os.path.exists(survex_3d): raise Exception("File '%s' doesn't exist" % survex_3d) if discard_features: self.leg_list = [] self.station_list = [] self.station_xyz = {} self.xsect_list = [] # Read .3d file as binary, parse, and save data structures with open(survex_3d, 'rb') as fp: line = fp.readline().rstrip() # File ID check if not line.startswith(b'Survex 3D Image File'): raise IOError('Not a survex .3d file: ' + survex_3d) line = fp.readline().rstrip() # File format version if not line.startswith(b'v'): raise IOError('Unrecognised survex .3d version in ' + survex_3d) version = int(line[1:]) if version < 8: raise IOError('Survex .3d version >= 8 required in ' + survex_3d) line = fp.readline().rstrip( ) # Metadata (title and coordinate system) fields = line.split(b'\x00') previous_title = '' if discard_features else self.title if previous_title: self.title = previous_title + ' + ' + fields[0].decode( 'ascii') else: self.title = fields[0].decode('ascii') self.set_crs( fields[1].decode('ascii') if len(fields) > 1 else None) line = fp.readline().rstrip( ) # Timestamp, unused in present application if not line.startswith(b'@'): raise IOError('Unrecognised timestamp in ' + survex_3d) # timestamp = int(line[1:]) flag = ord(fp.read(1)) # file-wide flag if flag & 0x80: # abort if extended elevation raise IOError("Can't deal with extended elevation in " + survex_3d) # All file-wide header data read in, now read byte-wise # according to .3d spec. Note that all elements must # be processed, in order, otherwise we get out of sync. # We first define some baseline dates date0 = QDate(1900, 1, 1) date1 = QDate(1900, 1, 1) date2 = QDate(1900, 1, 1) label, style = '', 0xff # initialise label and style legs = [] # will be used to capture leg data between MOVEs xsect = [] # will be used to capture XSECT data nlehv = None # .. remains None if there isn't any error data... while True: # start of byte-gobbling while loop char = fp.read(1) if not char: # End of file (reached prematurely?) raise IOError('Premature end of file in ' + survex_3d) byte = ord(char) if byte <= 0x05: # STYLE if byte == 0x00 and style == 0x00: # this signals end of data if legs: # there may be a pending list of legs to save self.leg_list.append((legs, nlehv)) break # escape from byte-gobbling while loop else: style = byte elif byte <= 0x0e: # Reserved continue elif byte == 0x0f: # MOVE xyz = self.read_xyz(fp) if legs: self.leg_list.append((legs, nlehv)) legs = [] elif byte == 0x10: # DATE (none) date1 = date2 = date0 elif byte == 0x11: # DATE (single date) days = unpack('<H', fp.read(2))[0] date1 = date2 = date0.addDays(days) elif byte == 0x12: # DATE (date range, short format) days, extra = unpack('<HB', fp.read(3)) date1 = date0.addDays(days) date2 = date0.addDays(days + extra + 1) elif byte == 0x13: # DATE (date range, long format) days1, days2 = unpack('<HH', fp.read(4)) date1 = date0.addDays(days1) date2 = date0.addDays(days2) elif byte <= 0x1e: # Reserved continue elif byte == 0x1f: # Error info nlehv = unpack('<iiiii', fp.read(20)) elif byte <= 0x2f: # Reserved continue elif byte <= 0x33: # XSECT label = self.read_label(fp, label) if byte & 0x02: lrud = unpack('<iiii', fp.read(16)) else: lrud = unpack('<hhhh', fp.read(8)) xsect.append((label, lrud)) if byte & 0x01: # XSECT_END self.xsect_list.append(xsect) xsect = [] elif byte <= 0x3f: # Reserved continue elif byte <= 0x7f: # LINE flag = byte & 0x3f if not (flag & 0x20): label = self.read_label(fp, label) xyz_prev = xyz xyz = self.read_xyz(fp) while (True): # code pattern to implement logic if exclude_surface_legs and flag & 0x01: break if exclude_duplicate_legs and flag & 0x02: break if exclude_splay_legs and flag & 0x04: break legs.append(((xyz_prev, xyz), label, style, date1, date2, flag)) break elif byte <= 0xff: # LABEL (or NODE) flag = byte & 0x7f label = self.read_label(fp, label) xyz = self.read_xyz(fp) while (True): # code pattern to implement logic if exclude_surface_stations and flag & 0x01 and not flag & 0x02: break self.station_list.append((xyz, label, flag)) break self.station_xyz[label] = xyz # End of byte-gobbling while loop # file closes automatically, with open(survex_3d, 'rb') as fp: layers = [] # used to keep a list of the created layers if include_stations and self.station_list: # station layer station_layer = self.add_layer('stations', 'PointZ') attrs = [ QgsField(self.station_attr[k], QVariant.Int) for k in self.station_flags ] attrs.insert(0, QgsField('ELEVATION', QVariant.Double)) attrs.insert(0, QgsField('NAME', QVariant.String)) station_layer.dataProvider().addAttributes(attrs) station_layer.updateFields() features = [] for (xyz, label, flag) in self.station_list: xyz = [0.01 * v for v in xyz] attrs = [1 if flag & k else 0 for k in self.station_flags] attrs.insert(0, round(xyz[2], 2)) # elevation attrs.insert(0, label) feat = QgsFeature() geom = QgsGeometry(QgsPoint(*xyz)) feat.setGeometry(geom) feat.setAttributes(attrs) features.append(feat) station_layer.dataProvider().addFeatures(features) layers.append(station_layer) if include_legs and self.leg_list: # leg layer leg_layer = self.add_layer('legs', 'LineStringZ') attrs = [ QgsField(self.leg_attr[k], QVariant.Int) for k in self.leg_flags ] if nlehv: [ attrs.insert(0, QgsField(s, QVariant.Double)) for s in self.error_fields ] attrs.insert(0, QgsField('NLEGS', QVariant.Int)) attrs.insert(0, QgsField('DATE2', QVariant.Date)) attrs.insert(0, QgsField('DATE1', QVariant.Date)) attrs.insert(0, QgsField('STYLE', QVariant.String)) attrs.insert(0, QgsField('ELEVATION', QVariant.Double)) attrs.insert(0, QgsField('NAME', QVariant.String)) leg_layer.dataProvider().addAttributes(attrs) leg_layer.updateFields() features = [] for legs, nlehv in self.leg_list: for (xyz_pair, label, style, from_date, to_date, flag) in legs: elev = 0.5 * sum([0.01 * xyz[2] for xyz in xyz_pair]) points = [] for xyz in xyz_pair: xyz = [0.01 * v for v in xyz] points.append(QgsPoint(*xyz)) attrs = [1 if flag & k else 0 for k in self.leg_flags] if nlehv: [ attrs.insert(0, 0.01 * v) for v in reversed(nlehv[1:5]) ] attrs.insert(0, nlehv[0]) attrs.insert(0, to_date) attrs.insert(0, from_date) attrs.insert(0, self.style_type[style]) attrs.insert(0, round(elev, 2)) attrs.insert(0, label) linestring = QgsLineString() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) features.append(feat) leg_layer.dataProvider().addFeatures(features) layers.append(leg_layer) # Now do wall features if asked if (include_traverses or include_xsections or include_walls or include_polygons) and self.xsect_list: trav_features = [] wall_features = [] xsect_features = [] quad_features = [] for xsect in self.xsect_list: if len(xsect) < 2: # if there's only one station .. continue # .. give up as we don't know which way to face centerline = [ ] # will contain the station position and LRUD data for label, lrud in xsect: xyz = self.station_xyz[ label] # look up coordinates from label lrud_or_zero = tuple([max(0, v) for v in lrud ]) # deal with missing data centerline.append( xyz + lrud_or_zero) # and collect as 7-uple direction = [ ] # will contain the corresponding direction vectors # The calculations below use integers for xyz and lrud, and # conversion to metres is left to the end. Then dh2 is an # integer and the test for a plumb is safely dh2 = 0. # The directions are unit vectors optionally weighted by # cos(inclination) = dh/dl where dh^2 = dx^2 + dy^2 (note, no dz^2), # and dl^2 = dh^2 + dz^2. The normalisation is correspondingly # either 1/dh, or 1/dh * dh/dl = 1/dl. for i, xyzlrud in enumerate(centerline): x, y, z = xyzlrud[0:3] if i > 0: dx, dy, dz = x - xp, y - yp, z - zp dh2 = dx * dx + dy * dy # integer horizontal displacement (mm^2) norm = sqrt(dh2 + dz * dz) if use_clino_wgt else sqrt(dh2) dx, dy = (dx / norm, dy / norm) if dh2 > 0 and norm > 0 else (0, 0) direction.append((dx, dy)) xp, yp, zp = x, y, z left_wall = [] right_wall = [] up_down = [] # We build the walls by walking through the list # of stations and directions, with simple defaults # for the start and end stations for i, (x, y, z, l, r, u, d) in enumerate(centerline): d1x, d1y = direction[i - 1] if i > 0 else (0, 0) d2x, d2y = direction[i] if i + 1 < len( centerline) else (0, 0) dx, dy = d1x + d2x, d1y + d2y # mean (sum of) direction vectors norm = sqrt(dx * dx + dy * dy) # normalise to unit vector ex, ey = (dx / norm, dy / norm) if norm > 0 else (0, 0) # Convert to metres when saving the points left_wall.append((0.01 * (x - l * ey), 0.01 * (y + l * ex), 0.01 * z)) right_wall.append((0.01 * (x + r * ey), 0.01 * (y - r * ex), 0.01 * z)) up_down.append((0.01 * u, 0.01 * d)) # Mean elevation of centerline, used for elevation attribute elev = 0.01 * sum([xyzlrud[2] for xyzlrud in centerline ]) / len(centerline) attrs = [round(elev, 2)] # Now create the feature sets - first the centerline traverse points = [] for xyzlrud in centerline: xyz = [0.01 * v for v in xyzlrud[0:3] ] # These were mm, convert to metres points.append(QgsPoint(*xyz)) linestring = QgsLineString() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) trav_features.append(feat) # The walls as line strings for wall in (left_wall, right_wall): points = [QgsPoint(*xyz) for xyz in wall] linestring = QgsLineString() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) wall_features.append(feat) # Slightly more elaborate, pair up points on left # and right walls, and build a cross section as a # 2-point line string, and a quadrilateral polygon # with a closed 5-point line string for the # exterior ring. Note that QGIS polygons are # supposed to have their points ordered clockwise. for i, xyz_pair in enumerate(zip(left_wall, right_wall)): elev = 0.01 * centerline[i][ 2] # elevation of station in centerline attrs = [round(elev, 2)] points = [QgsPoint(*xyz) for xyz in xyz_pair] linestring = QgsLineString() linestring.setPoints(points) feat = QgsFeature() geom = QgsGeometry(linestring) feat.setGeometry(geom) feat.setAttributes(attrs) xsect_features.append(feat) if i > 0: elev = 0.5 * (prev_xyz_pair[0][2] + xyz_pair[0][2] ) # average elevation attrs = [round(elev, 2)] if include_up_down: # average up / down attrs += [ 0.5 * (v1 + v2) for (v1, v2) in zip(up_down[i - 1], up_down[i]) ] points = [ ] # will contain the exterior 5-point ring, as follows... for xyz in tuple( reversed(prev_xyz_pair)) + xyz_pair + ( prev_xyz_pair[1], ): points.append(QgsPoint(*xyz)) linestring = QgsLineString() linestring.setPoints(points) polygon = QgsPolygon() polygon.setExteriorRing(linestring) feat = QgsFeature() geom = QgsGeometry(polygon) feat.setGeometry(geom) feat.setAttributes(attrs) quad_features.append(feat) prev_xyz_pair = xyz_pair # End of processing xsect_list - now add features to requested layers attrs = [QgsField('ELEVATION', QVariant.Double)] # common to all if include_traverses and trav_features: # traverse layer travs_layer = self.add_layer('traverses', 'LineStringZ') travs_layer.dataProvider().addAttributes(attrs) travs_layer.updateFields() travs_layer.dataProvider().addFeatures(trav_features) layers.append(travs_layer) if include_xsections and xsect_features: # xsection layer xsects_layer = self.add_layer('xsections', 'LineStringZ') xsects_layer.dataProvider().addAttributes(attrs) xsects_layer.updateFields() xsects_layer.dataProvider().addFeatures(xsect_features) layers.append(xsects_layer) if include_walls and wall_features: # wall layer walls_layer = self.add_layer('walls', 'LineStringZ') walls_layer.dataProvider().addAttributes(attrs) walls_layer.updateFields() walls_layer.dataProvider().addFeatures(wall_features) layers.append(walls_layer) if include_up_down: # add fields if requested for polygons attrs += [ QgsField(s, QVariant.Double) for s in ('MEAN_UP', 'MEAN_DOWN') ] if include_polygons and quad_features: # polygon layer quads_layer = self.add_layer('polygons', 'PolygonZ') quads_layer.dataProvider().addAttributes(attrs) quads_layer.updateFields() quads_layer.dataProvider().addFeatures(quad_features) layers.append(quads_layer) # All layers have been created, now update extents and add to QGIS registry if layers: [layer.updateExtents() for layer in layers] QgsProject.instance().addMapLayers(layers) # Write to GeoPackage if requested if gpkg_file: opts = [ QgsVectorFileWriter.CreateOrOverwriteFile, QgsVectorFileWriter.CreateOrOverwriteLayer ] for i, layer in enumerate(layers): options = QgsVectorFileWriter.SaveVectorOptions() options.actionOnExistingFile = opts[int( i > 0)] # create file or layer layer_name = layer.name() match = search( ' - ([a-z]*)', layer_name) # ie, extract 'legs', 'stations', etc options.layerName = str( match.group(1)) if match else layer_name writer = QgsVectorFileWriter.writeAsVectorFormat( layer, gpkg_file, options) if writer: msg = "'{}' -> {} in {}".format( layer_name, options.layerName, gpkg_file) QgsMessageLog.logMessage(msg, tag='Import .3d', level=Qgis.Info) options, writer = None, None
def read(self, params): self.inp_path = self.inp_path self.params = params statinfo = os.stat(self.inp_path) file_size = statinfo.st_size if file_size == 0: return None ref = read_epanet_file.InpReader(self.inp_path) # ref.LoadFile(self.inp_path) # ref.BinUpdateClass() links_count = ref.getBinLinkCount() # Get all Sections mixing = ref.getMixingSection() reactions = ref.getReactionsSection() sources = ref.getSourcesSection() rules = ref.getRulesSection() quality = ref.getQualitySection() curves = ref.getCurvesSection() patterns = ref.getPatternsSection() controls = ref.getControlsSection() emitters = ref.getEmittersSection() emitters_d = {} for emitter in emitters: emitters_d[emitter[0]] = emitter[1] status = ref.getStatusSection() demands = ref.getDemandsSection() energy = ref.getEnergySection() opt_reactions = ref.getReactionsOptionsSection() times = ref.getTimesSection() report = ref.getReportSection() options = ref.getOptionsSection() tags = ref.get_tags() tags_d = {} # Check for QEPANET section in inp file. If it's there, update layer attributes qepanet_junctions_elevcorr_od, qepanet_junctions_zone_end_od, \ qepanet_junctions_pressure_od, qepanet_junctions_pressure_units_od = \ self.read_qepanet_junctions() qepanet_tanks_od = self.read_qepanet_tanks() (qepanet_reservoirs_deltaz_od, qepanet_reservoirs_press_head_od) = self.read_qepanet_reservoirs() (qepanet_pipes_material_od, qepanet_pipes_edu_od, qepanet_pipes_zone_id_od, qepanet_pipes_velocity_od, qepanet_pipes_frictionloss_od, qepanet_pipes_length_units_od, qepanet_pipes_diameter_units_od, qepanet_pipes_velocity_units_od, qepanet_pipes_frictionloss_units_od) = self.read_qepanet_pipes() qepanet_vertices_od = self.read_qepanet_vertices() # Create layers and update if mixing: self.update_mixing(mixing) if reactions: self.update_reactions(reactions) if sources: self.update_sources(sources) if rules: self.update_rules(rules) if quality: self.update_quality(quality) if controls: self.update_controls(controls) if demands: self.update_demands(demands) if energy: self.update_energy(energy) if opt_reactions: self.update_opt_reactions(opt_reactions) if times: self.update_times(times) if report: self.update_report(report) if options: self.update_options(options) # Get all Section lengths all_sections = [ len(energy), len(opt_reactions), len(demands), len(status), len(emitters), len(controls), len(patterns), len(curves[0]), len(quality), len(rules), len(sources), len(reactions), len(mixing), len(times), len(report), len(options), ref.getBinNodeCount(), ref.getBinLinkCount() ] ss = max(all_sections) if tags: for tag in tags: tags_d[tag.element_id] = tag.tag self.params.tag_names = set(tags_d.values()) xy = ref.getBinNodeCoordinates() x = xy[0] y = xy[1] vertx = xy[2] verty = xy[3] vertxyFinal = [] for i in range(len(vertx)): vertxy = [] for u in range(len(vertx[i])): vertxy.append([float(vertx[i][u]), float(verty[i][u])]) if vertxy != []: vertxyFinal.append(vertxy) # Get data of Junctions ndEle = ref.getBinNodeJunctionElevations() ndBaseD = ref.getBinNodeBaseDemands() ndID = ref.getBinNodeNameID() nodes_desc = ref.get_nodes_desc() ndPatID = ref.getBinNodeDemandPatternID() junctions_lay = None if ref.getBinNodeJunctionCount() > 0: junctions_lay = MemoryDS.create_junctions_lay(crs=params.crs) junctions_lay_dp = junctions_lay.dataProvider() # Get data of Pipes pipes_lay = None pumps_lay = None valves_lay = None if links_count > 0: # Pipes pipes_lay = MemoryDS.create_pipes_lay(crs=params.crs) pipes_lay_dp = pipes_lay.dataProvider() # Pumps pumps_lay = MemoryDS.create_pumps_lay(crs=params.crs) pumps_lay_dp = pumps_lay.dataProvider() # Valves valves_lay = MemoryDS.create_valves_lay(crs=params.crs) valves_lay_dp = valves_lay.dataProvider() pump_index = ref.getBinLinkPumpIndex() valve_index = ref.getBinLinkValveIndex() ndlConn = ref.getBinNodesConnectingLinksID() x1 = [] x2 = [] y1 = [] y2 = [] stat = ref.getBinLinkInitialStatus() kk = 0 ch = 0 linkID = ref.getBinLinkNameID() link_descs = ref.get_links_desc() linkLengths = ref.getBinLinkLength() linkDiameters = ref.getBinLinkDiameter() linkRough = ref.getBinLinkRoughnessCoeff() linkMinorloss = ref.getBinLinkMinorLossCoeff() # Write Tank Shapefile and get tank data tanks_lay = None if ref.getBinNodeTankCount() > 0: tanks_lay = MemoryDS.create_tanks_lay(crs=params.crs) tanks_lay_dp = tanks_lay.dataProvider() ndTankelevation = ref.getBinNodeTankElevations() initiallev = ref.getBinNodeTankInitialLevel() minimumlev = ref.getBinNodeTankMinimumWaterLevel() maximumlev = ref.getBinNodeTankMaximumWaterLevel() diameter = ref.getBinNodeTankDiameter() minimumvol = ref.getBinNodeTankMinimumWaterVolume() volumecurv = ref.getBinNodeTankVolumeCurveID() ndTankID = ref.getBinNodeTankNameID() reservoirs_lay = None if ref.getBinNodeReservoirCount() > 0: reservoirs_lay = MemoryDS.create_reservoirs_lay(crs=params.crs) reservoirs_lay_dp = reservoirs_lay.dataProvider() reservoirs_elev = ref.getBinNodeReservoirElevations() # posReservoirs.startEditing() vvLink = 68 bbLink = 1 vPos = 0 pPos = 0 pPosPower = 0 pPosHead = 0 pPosSpeed = 0 pPosSpeedPattern = 0 for i in range(ss): if i == ss / vvLink and vvLink > -1: vvLink = vvLink - 1 bbLink = bbLink + 1 if i < ref.getBinNodeJunctionCount(): featJ = QgsFeature() point = QgsPointXY(float(x[i]), float(y[i])) delta_z = 0 if qepanet_junctions_elevcorr_od: delta_z = float(qepanet_junctions_elevcorr_od[ndID[i]]) featJ.setGeometry(QgsGeometry.fromPointXY(point)) # Emitter emitter_coeff = NULL if ndID[i] in emitters_d: emitter_coeff = float(emitters_d[ndID[i]]) # Tag tag = '' if ndID[i] in tags_d: tag = tags_d[ndID[i]] zone_end = 0 if ndID[i] in qepanet_junctions_zone_end_od: zone_end = int(qepanet_junctions_zone_end_od[ndID[i]]) pressure = 0 if ndID[i] in qepanet_junctions_pressure_od: pressure = float(qepanet_junctions_pressure_od[ndID[i]]) pressure_units = 'meter' if ndID[i] in qepanet_junctions_pressure_units_od: pressure_units = qepanet_junctions_pressure_units_od[ ndID[i]] featJ.setAttributes([ ndID[i], ndEle[i] - delta_z, delta_z, ndPatID[i], ndBaseD[i], emitter_coeff, nodes_desc[i], tag, zone_end, pressure, pressure_units ]) junctions_lay_dp.addFeatures([featJ]) self.params.nodes_sindex.addFeature(featJ) if i < links_count: if len(stat) == i: ch = 1 if ch == 1: stat.append('OPEN') x1.append(x[ndID.index(ref.getBinLinkFromNode()[i])]) y1.append(y[ndID.index(ref.getBinLinkFromNode()[i])]) x2.append(x[ndID.index(ref.getBinLinkToNode()[i])]) y2.append(y[ndID.index(ref.getBinLinkToNode()[i])]) if i in pump_index: # Pump point1 = QgsPointXY(float(x1[i]), float(y1[i])) point2 = QgsPointXY(float(x2[i]), float(y2[i])) chPowerPump = ref.getBinLinkPumpPower() cheadpump = ref.getBinLinkPumpCurveNameID() pumpID = ref.getBinLinkPumpNameID() patternsIDs = ref.getBinLinkPumpPatterns() ppatt = ref.getBinLinkPumpPatternsPumpID() linkID = ref.getBinLinkNameID() Head = [] Flow = [] curve = [] power = [] pattern = [] pumpNameIDPower = ref.getBinLinkPumpNameIDPower() param = None head = None power = None speed = None if pumpID[pPos] in pumpNameIDPower: param = 'POWER' power = float(chPowerPump[pPosPower]) pPosPower += 1 else: param = 'HEAD' if len(cheadpump) > pPosHead: head = cheadpump[pPosHead] pPosHead += 1 else: head = NULL if len(pumpNameIDPower) > 0: for uu in range(0, len(pumpNameIDPower)): if pumpNameIDPower[uu] == pumpID[pPos]: power = float(chPowerPump[uu]) if len(patternsIDs) > 0: for uu in range(0, len(ppatt)): if ppatt[uu] == pumpID[pPos]: pattern = patternsIDs[uu] if ref.getBinCurveCount() > 0 and len( pumpNameIDPower) == 0: curveXY = ref.getBinCurvesXY() curvesID = ref.getBinCurvesNameID() for uu in range(0, len(curveXY)): if curvesID[uu] == cheadpump[pPos]: Head.append(str(curveXY[uu][0])) Flow.append(str(curveXY[uu][1])) curve = ref.getBinLinkPumpCurveNameID()[pPos] if pumpID[pPos] in ref.getBinLinkPumpSpeedID(): speed = float(ref.getBinLinkPumpSpeed()[pPosSpeed]) pPosSpeed += 1 pump_pattern = None if pumpID[pPos] in ppatt: pump_pattern = ref.getBinLinkPumpPatterns( )[pPosSpeedPattern] pPosSpeedPattern += 1 pump_status = Pump.status_open for statuss in status: if statuss[0] == pumpID[pPos]: if statuss[1].strip().upper( ) == Pump.status_closed or statuss[1].strip( ).upper() == Pump.status_open: pump_status = statuss[1].strip().upper() break featPump = QgsFeature() featPump.setGeometry( QgsGeometry.fromPolylineXY([point1, point2])) tag = '' if linkID[i] in tags_d: tag = tags_d[linkID[i]] featPump.setAttributes([ linkID[i], param, head, power, speed, pump_pattern, pump_status, link_descs[i], tag ]) pumps_lay_dp.addFeatures([featPump]) self.params.nodes_sindex.addFeature(featPump) pPos += 1 elif i in valve_index: # Valve point1 = QgsPointXY(float(x1[i]), float(y1[i])) point2 = QgsPointXY(float(x2[i]), float(y2[i])) length = 0 diameter = 0 roughness = 0 minorloss = 0 featValve = QgsFeature() featValve.setGeometry( (QgsGeometry.fromPolylineXY([point1, point2]))) linkID = ref.getBinLinkValveNameID() descs = ref.get_valves_desc() linkType = ref.getBinLinkValveType() linkDiameter = ref.getBinLinkValveDiameters() linkInitSett = ref.getBinLinkValveSetting() linkMinorloss = ref.getBinLinkValveMinorLoss() valve_status = Valve.status_none for statuss in status: if statuss[0] == linkID[vPos]: valve_status = statuss[1] break # Tag tag = '' if linkID[vPos] in tags_d: tag = tags_d[linkID[vPos]] featValve.setAttributes([ linkID[vPos], linkDiameter[vPos], linkType[vPos], linkInitSett[vPos], linkMinorloss[vPos], valve_status, descs[vPos], tag ]) valves_lay_dp.addFeatures([featValve]) self.params.nodes_sindex.addFeature(featValve) vPos += 1 else: # Pipe # Last point start_node_id = ndlConn[0][i] end_node_id = ndlConn[1][i] # Z start_node_elev = 0 end_node_elev = 0 for j in range(ref.getBinNodeJunctionCount()): delta_z = 0 if qepanet_junctions_elevcorr_od and ndID[ j] in qepanet_junctions_elevcorr_od: delta_z = qepanet_junctions_elevcorr_od[ndID[j]] if qepanet_reservoirs_deltaz_od and ndID[ j] in qepanet_reservoirs_deltaz_od: delta_z = qepanet_reservoirs_deltaz_od[ndID[j]] if qepanet_tanks_od and ndID[j] in qepanet_tanks_od: delta_z = qepanet_tanks_od[ndID[j]] if ndID[j] == start_node_id: start_node_elev = ndEle[j] + delta_z if ndID[j] == end_node_id: end_node_elev = ndEle[j] + delta_z point1 = QgsPoint(float(x1[i]), float(y1[i]), start_node_elev) point2 = QgsPoint(float(x2[i]), float(y2[i]), end_node_elev) if vertx[i]: parts = [point1] for mm in range(len(vertxyFinal[kk])): a = vertxyFinal[kk][mm] z = 0 if linkID[i] in qepanet_vertices_od: z = qepanet_vertices_od[linkID[i]] parts.append(QgsPoint(a[0], a[1], z)) parts.append(point2) featPipe = QgsFeature() linestring = QgsLineString() linestring.setPoints(parts) geom_3d = QgsGeometry(linestring) featPipe.setGeometry(geom_3d) kk += 1 else: featPipe = QgsFeature() # point1 = QgsPoint(float(x1[i]), float(y1[i])) # point2 = QgsPoint(float(x2[i]), float(y2[i])) linestring = QgsLineString() linestring.setPoints([point1, point2]) geom_3d = QgsGeometry(linestring) featPipe.setGeometry(geom_3d) # featPipe.setGeometry(QgsGeometry.fromPolyline([point1, point2])) material = None if linkID[i] in qepanet_pipes_material_od: material = qepanet_pipes_material_od[linkID[i]] tag = '' if linkID[i] in tags_d: tag = tags_d[linkID[i]] num_edu = 0 if linkID[i] in qepanet_pipes_edu_od: num_edu = int(qepanet_pipes_edu_od[linkID[i]]) zone_id = 0 if linkID[i] in qepanet_pipes_zone_id_od: zone_id = int(qepanet_pipes_zone_id_od[linkID[i]]) velocity = 0 if linkID[i] in qepanet_pipes_velocity_od: velocity = float(qepanet_pipes_velocity_od[linkID[i]]) frictionloss = 0 if linkID[i] in qepanet_pipes_frictionloss_od: frictionloss = float( qepanet_pipes_frictionloss_od[linkID[i]]) length_units = 'meters' if linkID[i] in qepanet_pipes_length_units_od: length_units = qepanet_pipes_length_units_od[linkID[i]] diameter_units = 'mm' if linkID[i] in qepanet_pipes_diameter_units_od: diameter_units = qepanet_pipes_diameter_units_od[ linkID[i]] velocity_units = 'm/s' if linkID[i] in qepanet_pipes_velocity_units_od: velocity_units = qepanet_pipes_velocity_units_od[ linkID[i]] frictionloss_units = 'm' if linkID[i] in qepanet_pipes_frictionloss_units_od: frictionloss_units = qepanet_pipes_frictionloss_units_od[ linkID[i]] featPipe.setAttributes([ linkID[i], linkLengths[i], linkDiameters[i], stat[i], linkRough[i], linkMinorloss[i], material, link_descs[i], tag, num_edu, zone_id, velocity, frictionloss, length_units, diameter_units, velocity_units, frictionloss_units ]) pipes_lay_dp.addFeatures([featPipe]) self.params.nodes_sindex.addFeature(featPipe) if i < ref.getBinNodeTankCount(): p = ref.getBinNodeTankIndex()[i] - 1 featTank = QgsFeature() point = QgsPointXY(float(x[p]), float(y[p])) featTank.setGeometry(QgsGeometry.fromPointXY(point)) delta_z = 0 if ndTankID[i] in qepanet_tanks_od: delta_z = qepanet_tanks_od[ndTankID[i]] # Tag tag = '' if ndTankID[i] in tags_d: tag = tags_d[ndTankID[i]] featTank.setAttributes([ ndTankID[i], ndTankelevation[i] - delta_z, delta_z, initiallev[i], minimumlev[i], maximumlev[i], diameter[i], minimumvol[i], volumecurv[i], nodes_desc[i], tag ]) tanks_lay_dp.addFeatures([featTank]) self.params.nodes_sindex.addFeature(featTank) if i < ref.getBinNodeReservoirCount(): p = ref.getBinNodeReservoirIndex()[i] - 1 feat_reserv = QgsFeature() point = QgsPointXY(float(x[p]), float(y[p])) feat_reserv.setGeometry(QgsGeometry.fromPointXY(point)) delta_z = 0 if ndID[p] in qepanet_reservoirs_deltaz_od: delta_z = qepanet_reservoirs_deltaz_od[ndID[p]] pressure_head = 0 if ndID[p] in qepanet_reservoirs_press_head_od: pressure_head = qepanet_reservoirs_press_head_od[ndID[p]] # Tag tag = '' if ndID[p] in tags_d: tag = tags_d[ndID[p]] feat_reserv.setAttributes([ ndID[p], reservoirs_elev[i] - delta_z - pressure_head, delta_z, pressure_head, ndPatID[p], nodes_desc[i], tag ]) reservoirs_lay_dp.addFeatures([feat_reserv]) self.params.nodes_sindex.addFeature(feat_reserv) if curves: self.update_curves() if patterns: self.update_patterns() return { Junction.section_name: junctions_lay, Reservoir.section_name: reservoirs_lay, Tank.section_name: tanks_lay, Pipe.section_name: pipes_lay, Pump.section_name: pumps_lay, Valve.section_name: valves_lay }
def processAlgorithm(self, parameters, context, feedback): extent = self.getParameterValue(self.EXTENT).split(',') hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) hOverlay = self.getParameterValue(self.HOVERLAY) vOverlay = self.getParameterValue(self.VOVERLAY) crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS)) bbox = QgsRectangle(float(extent[0]), float(extent[2]), float(extent[1]), float(extent[3])) width = bbox.width() height = bbox.height() if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing)) if hSpacing <= hOverlay or vSpacing <= vOverlay: raise GeoAlgorithmExecutionException( self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay)) if width < hSpacing: raise GeoAlgorithmExecutionException( self.tr('Horizontal spacing is too small for the covered area')) if height < vSpacing: raise GeoAlgorithmExecutionException( self.tr('Vertical spacing is too small for the covered area')) fields = QgsFields() fields.append(QgsField('left', QVariant.Double, '', 24, 16)) fields.append(QgsField('top', QVariant.Double, '', 24, 16)) fields.append(QgsField('right', QVariant.Double, '', 24, 16)) fields.append(QgsField('bottom', QVariant.Double, '', 24, 16)) fields.append(QgsField('id', QVariant.Int, '', 10, 0)) fields.append(QgsField('coord', QVariant.Double, '', 24, 15)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.LineString, crs, context) if hOverlay > 0: hSpace = [hSpacing - hOverlay, hOverlay] else: hSpace = [hSpacing, hSpacing] if vOverlay > 0: vSpace = [vSpacing - vOverlay, vOverlay] else: vSpace = [vSpacing, vSpacing] feat = QgsFeature() feat.initAttributes(len(fields)) count = 0 id = 1 # latitude lines count_max = height / vSpacing count_update = count_max * 0.10 y = bbox.yMaximum() while y >= bbox.yMinimum(): pt1 = QgsPoint(bbox.xMinimum(), y) pt2 = QgsPoint(bbox.xMaximum(), y) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([bbox.xMinimum(), y, bbox.xMaximum(), y, id, y]) writer.addFeature(feat, QgsFeatureSink.FastInsert) y = y - vSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(int(count / count_max * 50)) feedback.setProgress(50) # longitude lines # counters for progressbar - update every 5% count = 0 count_max = width / hSpacing count_update = count_max * 0.10 x = bbox.xMinimum() while x <= bbox.xMaximum(): pt1 = QgsPoint(x, bbox.yMaximum()) pt2 = QgsPoint(x, bbox.yMinimum()) line = QgsLineString() line.setPoints([pt1, pt2]) feat.setGeometry(QgsGeometry(line)) feat.setAttributes([x, bbox.yMaximum(), x, bbox.yMinimum(), id, x]) writer.addFeature(feat, QgsFeatureSink.FastInsert) x = x + hSpace[count % 2] id += 1 count += 1 if int(math.fmod(count, count_update)) == 0: feedback.setProgress(50 + int(count / count_max * 50)) del writer