Skip to content

Commit

Permalink
Merge pull request #318 from qwat/network_intervention_simulation
Browse files Browse the repository at this point in the history
Network intervention simulation
  • Loading branch information
ponceta authored Mar 6, 2023
2 parents 1a7aeb3 + 0efcce0 commit 3229eec
Show file tree
Hide file tree
Showing 10 changed files with 17,120 additions and 16,353 deletions.
Binary file removed 210910-teksi-drink-logos-en-01_20pp.png
Binary file not shown.
Binary file removed 210910-teksi-drink-logos-en-01_45pp.png
Binary file not shown.
Binary file removed 210910-teksi-drink-logos-en-01_96pp.png
Binary file not shown.
Binary file removed 210910-teksi-drink-logos-en-03.png
Binary file not shown.
Binary file removed 210910-teksi-drink-logos-en-03_45pp.png
Binary file not shown.
16 changes: 7 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
.. image:: 210910-teksi-drink-logos-en-01_96pp.png
.. image:: qwat.png


TEKSI drinking water module (Project QWAT)
=========================================================

Open source water distribution network module based on QGIS / Postgis
QWAT: QGIS Water Module
=======================

Documentation
-------------

Hosted version here: https://qwat.github.io/docs/
Hosted version here: https://qwat.github.io/docs/master/en/html/

The documentation has its own repository at https://github.com/qwat/docs

Expand All @@ -18,12 +16,12 @@ Requirements

Server side software components are:

* `PostgreSQL <https://postgresql.org/>`_ (> 10)
* `PostGIS <https://postgis.net/>`_, the spatial extension (> 2.5)
* `PostgreSQL <https://postgresql.org/>`_ (> 9.6)
* `PostGIS <https://postgis.net/>`_, the spatial extension (> 2.3)
* `Python <https://www.python.org/>`_, for installation and update (> 3.5)
* `PUM <https://github.com/opengisch/pum>`_ for upgrade

Supported and tested versions are PostgreSQL 10 and Postgis 2.5.
Supported and tested versions are PostgreSQL 9.6 and Postgis 2.3.

The exact required hardware configuration is very dependant on the data sizes.
However, water network data tend not to be huge volumes, and the minimal required configuration is very low.
Expand Down
142 changes: 142 additions & 0 deletions qgis-project/actions/action_incident.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
"""
This action code should be added to the pipe layer in the QGIS project
"""

from PyQt5.QtGui import QColor
from PyQt5.QtCore import QVariant
from qgis.utils import iface
from PyQt5 import uic
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtWidgets import *

GROUP_NAME = "Incident réseau"
LAYER_RESULAT_NAME = "Vannes à fermer"

VALVE_SOURCE_NAME = '"qwat_od"."valve"'

class SearchOpenedValvesDialog(QDialog):
def __init__(self, parent, pipe_id, x, y):
super(SearchOpenedValvesDialog, self).__init__(parent)
self.pipe_id = pipe_id
self.setWindowTitle("Incident sur le réseau")
self.point = QgsGeometry()
self.startFeature = None
self.endFeature = None
self.x = x
self.y = y

# Get CRS from settings table
query = "(select id, value from qwat_sys.settings)"
source = """{} key='id' table="({})" ()""".format("service=qwat", query)
crsLayer = QgsVectorLayer(source, "temporary", "postgres")
if crsLayer.isValid():
for feature in crsLayer.getFeatures():
self.crs = feature["value"]
break

self.layout = QGridLayout()
self.layout.setContentsMargins(10, 10, 10, 10)

self.kmLabel = QLabel("Km max. : ")
self.layout.addWidget(self.kmLabel, 0, 0)
self.kmSpinBox = QDoubleSpinBox()
self.kmSpinBox.setDecimals(2)
self.kmSpinBox.setMinimum(0.1)
self.kmSpinBox.setMaximum(50)
self.kmSpinBox.setValue(1)
self.layout.addWidget(self.kmSpinBox, 1, 0)

self.checkNetworkValves = QCheckBox("S'arrêter uniquement aux vannes réseaux")
self.checkNetworkValves.setChecked(True)
self.layout.addWidget(self.checkNetworkValves, 2, 0)

buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
self.buttonBox = QDialogButtonBox(buttons)
self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.searchOpenedValves)
self.buttonBox.rejected.connect(self.reject)
self.layout.addWidget(self.buttonBox, 3, 0)

self.setLayout(self.layout)

def showEvent(self, event):
self.setupLayers()

def setupLayers(self):
layers = QgsProject.instance().mapLayers()
valve_layername = None
for layer_id, layer in layers.items():
if layer.dataProvider().uri().quotedTablename() == VALVE_SOURCE_NAME:
valve_layername = layer.name()
break
if (valve_layername is None):
QgsMessageLog.logMessage("Valve layer does not exist in QGIS project !", 'Messages', Qgis.Critical)
iface.messageBar().pushMessage("Error", "Valve layer does not exist in QGIS project !", level=Qgis.Critical)
QTimer.singleShot(0, self.reject)
return
self.valve_layer = QgsProject.instance().mapLayersByName(valve_layername)[0]

def searchOpenedValves(self):
km = self.kmSpinBox.value()
stopOnNetworkValves = str(self.checkNetworkValves.isChecked())

# Check if the result layer already exists
self.cleanResults()

# Set query for a temporary layer which will retreive the data only one time
query = """(select * from qwat_network.ft_search_opened_valves({pipe_id},{x},{y},{km},{stopOnNetworkValves}))""".format(pipe_id=str(self.pipe_id), x=str(self.x), y=str(self.y), km=str(km), stopOnNetworkValves=str(stopOnNetworkValves))

# Set connection to database
source = """{} key='id' table="{}" (geometry)""".format("service=qwat", query)

tmpLayer = QgsVectorLayer(source, "temporary", "postgres")
if tmpLayer.isValid():
# Create a memory layer (the final one which will be display to the user)
layer = QgsVectorLayer("Point?crs=epsg:" + self.crs, LAYER_RESULAT_NAME, "memory")

# Copy feature from temporary layer to final one (memory)
attr = tmpLayer.dataProvider().fields().toList()
features = []
for feature in tmpLayer.getFeatures():
features.append(feature)

layer.startEditing()
dataP = layer.dataProvider()
dataP.addAttributes(attr)
layer.updateFields()
dataP.addFeatures(features)
layer.commitChanges()

# Join valve layer
join = QgsVectorLayerJoinInfo()
join.setJoinFieldName('id')
join.setTargetFieldName('id')
join.setJoinLayerId(self.valve_layer.id())
join.setUsingMemoryCache(True)
join.setJoinLayer(self.valve_layer)
layer.addJoin(join)

layer.renderer().symbol().setSize(10)
layer.renderer().symbol().setColor(QColor(255, 0, 0))
map_layer = QgsProject.instance().addMapLayer(layer, False)
self.group.addLayer(map_layer)
self.close()
self.reorderLayers(self.group)

def cleanResults(self):
root = QgsProject.instance().layerTreeRoot()
self.group = root.findGroup(GROUP_NAME)
if self.group:
self.group.removeAllChildren()
else:
self.group = root.insertGroup(0, GROUP_NAME)

def reorderLayers(self, group):
bridge = iface.layerTreeCanvasBridge()
order = bridge.rootGroup().customLayerOrder()
for layer in group.children():
order.insert(0, order.pop(order.index(layer.layer())))
bridge.rootGroup().setCustomLayerOrder(order)

sp = SearchOpenedValvesDialog(iface.mainWindow(), [% "ID" %], [% @click_x %], [% @click_y %])
sp.show()
Loading

0 comments on commit 3229eec

Please sign in to comment.