diff --git a/.gitignore b/.gitignore index 8fa8b8e..76cb7b0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,9 +12,9 @@ ArcGIS_plugin/bgt_inlooptool/rtree/finder.py ArcGIS_plugin/bgt_inlooptool/rtree/index.py ArcGIS_plugin/bgt_inlooptool/rtree/lib/spatialindex-64.dll ArcGIS_plugin/bgt_inlooptool/rtree/lib/spatialindex_c-64.dll -.vscode/launch.json -.vscode/settings.json .spyproject .bak plugin/bgtinlooptool/bgtinlooptool.zip -plugin/bgtinlooptool/bgtinlooptool/ \ No newline at end of file +plugin/bgtinlooptool/bgtinlooptool/ + +custom_libs \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..b271753 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "ms-python.black-formatter", + "ms-python.isort", + "aaron-bond.better-comments", + "davidanson.vscode-markdownlint", + "njpwerner.autodocstring" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..484d08d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "internalConsole", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8babd4c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,63 @@ +{ + "editor.rulers": [ + 120 + ], + "python.autoComplete.extraPaths": [ + "C:\\OSGeo4W\\apps\\qgis-ltr\\bin", + "C:\\OSGeo4W\\apps\\Qt5\bin", + "C:\\OSGeo4W\\apps\\grass\\grass83\bin", + "C:\\OSGeo4W\\apps\\Python312\\Scripts", + "C:\\OSGeo4W\\apps\\qgis-ltr\\python", + ], + "python.analysis.extraPaths": [ + "C:\\OSGeo4W\\apps\\qgis-ltr\\bin", + "C:\\OSGeo4W\\apps\\Qt5\bin", + "C:\\OSGeo4W\\apps\\grass\\grass83\bin", + "C:\\OSGeo4W\\apps\\Python312\\Scripts", + "C:\\OSGeo4W\\apps\\qgis-ltr\\python", + "C:\\Users\\vdi\\.vscode\\extensions\\ms-python.python-2022.20.2\\pythonFiles\\lib\\python", + ], + "python.defaultInterpreterPath": "C:\\OSGeo4W\\apps\\Python312\\python.exe", + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + }, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + "source.fixAll": "explicit", + "source.fixAll.unusedImports": "explicit" + }, + "python.analysis.typeCheckingMode": "basic", + "python.testing.unittestArgs": [ + "-v", + "-s", + "./tests", + "-p", + "test_*.py" + ], + "python.testing.unittestEnabled": true, + "terminal.integrated.env.windows": { + "PYTHONPATH": "C:\\OSGeo4W\\apps\\qgis-ltr\\python\\qgis", + "PATH": "C:\\OSGEO4~1\\apps\\qgis-ltr\\bin;C:\\OSGEO4~1\\apps\\Python312;C:\\OSGEO4~1\\apps\\Python312\\Scripts;C:\\OSGEO4~1\\apps\\qt5\\bin;C:\\OSGEO4~1\\apps\\Python312\\Scripts;C:\\OSGEO4~1\\bin;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\system32\\WBem;C:\\OSGEO4~1\\apps\\Python312\\lib\\site-packages\\pywin32_system32;C:\\OSGEO4~1\\apps\\Python312\\lib\\site-packages\\numpy\\.libs", + "GDAL_DATA": "C:\\OSGEO4~1\\share\\gdal", + "GDAL_DRIVER_PATH": "C:\\OSGEO4~1\\bin\\gdalplugins", + "GDAL_FILENAME_IS_UTF8": "YES", + "GEOTIFF_CSV": "C:\\OSGEO4~1\\share\\epsg_csv", + "O4W_QT_BINARIES": "C:\\OSGEO4~1\\apps\\Qt5\\bin", + "O4W_QT_DOC": "C:\\OSGEO4~1\\apps\\Qt5\\doc", + "O4W_QT_HEADERS": "C:\\OSGEO4~1\\apps\\Qt5\\include", + "O4W_QT_LIBRARIES": "C:\\OSGEO4~1\\apps\\Qt5\\lib", + "O4W_QT_PLUGINS": "C:\\OSGEO4~1\\apps\\Qt5\\plugins", + "O4W_QT_PREFIX": "C:\\OSGEO4~1\\apps\\Qt5", + "O4W_QT_TRANSLATIONS": "C:\\OSGEO4~1\\apps\\Qt5\\translations", + "QT_PLUGIN_PATH": "C:\\OSGEO4~1\\apps\\qgis-ltr\\qtplugins;C:\\OSGEO4~1\\apps\\qt5\\plugins", + "QGIS_PREFIX_PATH": "C:\\OSGEO4~1\\apps\\qgis-ltr", + }, + "markdownlint.config": { + "MD024": { + "siblings_only": true + } + }, + "python.testing.pytestEnabled": false, + "workbench.settings.useSplitJSON": false, +} \ No newline at end of file diff --git a/ArcGIS_plugin/BGTInloopToolbox.BGTInloopToolArcGIS.pyt.xml b/ArcGIS_plugin/BGTInloopToolbox.BGTInloopToolArcGIS.pyt.xml index 3e130bd..6f5a3f1 100644 --- a/ArcGIS_plugin/BGTInloopToolbox.BGTInloopToolArcGIS.pyt.xml +++ b/ArcGIS_plugin/BGTInloopToolbox.BGTInloopToolArcGIS.pyt.xml @@ -1,2 +1,2 @@ -20210510141035001.0TRUE20210510162608001500000005000ItemDescriptionc:\program files\arcgis\pro\Resources\Help\gp<DIV STYLE="text-align:Left;"><DIV><P><SPAN>De opgehaalde BGT data als Geopackage (.gpkg)</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>De opgehaalde BGT data als Geopackage (.gpkg)</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>De opgehaalde GWSW data als Geopackage (.gpkg)</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>De opgehaalde GWSW data als Geopackage (.gpkg)</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>De opgehaalde BAG data als Geopackage (.gpkg)</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>De opgehaalde BAG data als Geopackage (.gpkg)</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Een kolken bestand als gpkg layer, shapefile of featureclass</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Een kolken bestand als gpkg layer, shapefile of featureclass</SPAN></P><P><SPAN /></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Een gebied als polygon bestand als gpkg layer, shapefile of featureclass</SPAN></P></DIV><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Een gebied als polygon bestand als gpkg layer, shapefile of featureclass</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>De output locatie voor de gpkg, naast deze wordt ook nog een gdb gemaakt met alleen de inlooptabel erin om deze goed te kunnen weergeven in ArcGIS Pro</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>De output locatie voor de gpkg, naast deze wordt ook nog een gdb gemaakt met alleen de inlooptabel erin om deze goed te kunnen weergeven in ArcGIS Pro</SPAN></P></DIV><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” tot een hemelwater ontvangende voorziening (meestal riolering). Is de afstand van het vlak tot een voorziening groter dan ingevulde afstand, dan is het vlak niet aangesloten op een hemelwater ontvangende voorziening.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” tot een hemelwater ontvangende voorziening (meestal riolering). Is de afstand van het vlak tot een voorziening groter dan ingevulde afstand, dan is het vlak niet aangesloten op een hemelwater ontvangende voorziening.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” [niet zijnde pand of bouwwerk] tot oppervlaktewater. Is de afstand van het vlak tot het oppervlaktewater kleiner dan ingevuld, dan loost het vlak op oppervlaktewater</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” [niet zijnde pand of bouwwerk] tot oppervlaktewater. Is de afstand van het vlak tot het oppervlaktewater kleiner dan ingevuld, dan loost het vlak op oppervlaktewater</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>De afstand (m) van een “vlak” (pand/bouwwerk) tot oppervlaktewater. Is de afstand van het pand tot het oppervlaktewater kleiner dan ingevuld, dan loost het pand op oppervlaktewater.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>De afstand (m) van een “vlak” (pand/bouwwerk) tot oppervlaktewater. Is de afstand van het pand tot het oppervlaktewater kleiner dan ingevuld, dan loost het pand op oppervlaktewater.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Als het vlak verder af ligt van een kolk dan deze maximale afstand dan is het vlak “niet aangesloten”. </SPAN></SPAN></P><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Als het vlak verder af ligt van een kolk dan deze maximale afstand dan is het vlak “niet aangesloten”. </SPAN></SPAN></P><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Het verschil in afstand tussen a) het vlak tot de gemengde buis en b) het vlak tot de HWA buis. Indien dit verschil groter is en gemengd dichter bij het vlak ligt watert het vlak af op gemengd.</SPAN></SPAN></P></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Het verschil in afstand tussen a) het vlak tot de gemengde buis en b) het vlak tot de HWA buis. Indien dit verschil groter is en gemengd dichter bij het vlak ligt watert het vlak af op gemengd.</SPAN></SPAN></P><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>In andere worden omschrijven: hemelwater afkomstig van daken is schoon, dit water gaat direct zonder zuiveringsstap naar het oppervlakte water. Hemelwater afkomstig van verharding/wegen is ‘vervuild’ dit wordt ingezameld in een stelsel met zuiveringsstap (VGS of hemelwaterriool met bijvoorbeeld helofytenfilter of een stelsel waar nog een zuiveringsstap kan worden ingebouwd. Dit stelseltype komt niet veel voor met name op bedrijventerreinen/industrieterreinen/drukke verkeersaders aangelegd tussen eind jaren negentig tot begin zeros (ongeveer 2005).</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>In andere worden omschrijven: hemelwater afkomstig van daken is schoon, dit water gaat direct zonder zuiveringsstap naar het oppervlakte water. Hemelwater afkomstig van verharding/wegen is ‘vervuild’ dit wordt ingezameld in een stelsel met zuiveringsstap (VGS of hemelwaterriool met bijvoorbeeld helofytenfilter of een stelsel waar nog een zuiveringsstap kan worden ingebouwd. Dit stelseltype komt niet veel voor met name op bedrijventerreinen/industrieterreinen/drukke verkeersaders aangelegd tussen eind jaren negentig tot begin zeros (ongeveer 2005).</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Rekening houden met afgekoppelde daken. Indien </SPAN></SPAN><SPAN STYLE="text-decoration:underline;"><SPAN>niet</SPAN></SPAN><SPAN><SPAN> aangevinkt gaat de tool er van uit dat het dak sowieso is afgekoppeld van gemengd [indien gemengd en HWA voldoen aan “Maximale afstand afgekoppeld stelsel”]. Indien aangevinkt gaat de tool verder kijken naar het bouwjaar van het pand Oude panden (gebouwd vóór opgegeven bouwjaar) gaan naar 100% gemengd. Nieuwe panden worden volledig afgekoppeld van het gemengde riool. </SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Rekening houden met afgekoppelde daken. Indien </SPAN></SPAN><SPAN STYLE="text-decoration:underline;"><SPAN>niet</SPAN></SPAN><SPAN><SPAN> aangevinkt gaat de tool er van uit dat het dak sowieso is afgekoppeld van gemengd [indien gemengd en HWA voldoen aan “Maximale afstand afgekoppeld stelsel”]. Indien aangevinkt gaat de tool verder kijken naar het bouwjaar van het pand Oude panden (gebouwd vóór opgegeven bouwjaar) gaan naar 100% gemengd. Nieuwe panden worden volledig afgekoppeld van het gemengde riool. </SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Het jaartal vanaf wanneer de meeste woningen gescheiden riolering aanbieden. Deze gegevens haalt de tool uit de BAG. Het bepaalt (als de optie voor afkoppelen wordt gebruikt) of het pand onder niet, voor de helft of volledig wordt afgekoppeld indien er naast het gemengde riool ook een andere hemelwater ontvangende voorziening binnen X meter van het gemengde riool aanwezig is.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Het jaartal vanaf wanneer de meeste woningen gescheiden riolering aanbieden. Deze gegevens haalt de tool uit de BAG. Het bepaalt (als de optie voor afkoppelen wordt gebruikt) of het pand onder niet, voor de helft of volledig wordt afgekoppeld indien er naast het gemengde riool ook een andere hemelwater ontvangende voorziening binnen X meter van het gemengde riool aanwezig is.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Dit percentage van tuinen of grond rondom gebouwen wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Dit percentage van tuinen of grond rondom gebouwen wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN><SPAN>Dit percentage van half verharde wegen (b.v. schelpenpad) wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Dit percentage van half verharde wegen (b.v. schelpenpad) wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV>2. BGT InlooptoolBGT InlooptoolArcToolbox Tool20210510 +20210510141035001.0TRUE20241129153556001500000005000ItemDescriptionc:\program files\arcgis\pro\Resources\Help\gp<DIV STYLE="text-align:Left;"><DIV><P><SPAN>Geef een geopackage (.gpkg) op waar de resultaten van een vorige run van de tool inzitten. Deze resultaten kunnen dan bij de nieuwe run worden meegenomen</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Geef een geopackage (.gpkg) op waar de resultaten van een vorige run van de tool inzitten. Deze resultaten kunnen dan bij de nieuwe run worden meegenomen</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De opgehaalde BGT data als Geopackage (.gpkg)</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De opgehaalde BGT data als Geopackage (.gpkg)</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De opgehaalde GWSW data als Geopackage (.gpkg)</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De opgehaalde GWSW data als Geopackage (.gpkg)</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De opgehaalde BAG data als Geopackage (.gpkg)</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De opgehaalde BAG data als Geopackage (.gpkg)</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Een kolken bestand als gpkg layer, shapefile of featureclass</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Een kolken bestand als gpkg layer, shapefile of featureclass</SPAN></P><P><SPAN /></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Een gebied als polygon bestand als gpkg layer, shapefile of featureclass</SPAN></P></DIV><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Een gebied als polygon bestand als gpkg layer, shapefile of featureclass</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Selecteer een polygonenbestand wat door de tool gebruikt kan worden statistiek mee te bepalen</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Selecteer een polygonenbestand wat door de tool gebruikt kan worden statistiek mee te bepalen</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” tot een hemelwater ontvangende voorziening (meestal riolering). Is de afstand van het vlak tot een voorziening groter dan ingevulde afstand, dan is het vlak niet aangesloten op een hemelwater ontvangende voorziening.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” tot een hemelwater ontvangende voorziening (meestal riolering). Is de afstand van het vlak tot een voorziening groter dan ingevulde afstand, dan is het vlak niet aangesloten op een hemelwater ontvangende voorziening.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” [niet zijnde pand of bouwwerk] tot oppervlaktewater. Is de afstand van het vlak tot het oppervlaktewater kleiner dan ingevuld, dan loost het vlak op oppervlaktewater</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>A</SPAN><SPAN>fstand (m) “vlak” [niet zijnde pand of bouwwerk] tot oppervlaktewater. Is de afstand van het vlak tot het oppervlaktewater kleiner dan ingevuld, dan loost het vlak op oppervlaktewater</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>De afstand (m) van een “vlak” (pand/bouwwerk) tot oppervlaktewater. Is de afstand van het pand tot het oppervlaktewater kleiner dan ingevuld, dan loost het pand op oppervlaktewater.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>De afstand (m) van een “vlak” (pand/bouwwerk) tot oppervlaktewater. Is de afstand van het pand tot het oppervlaktewater kleiner dan ingevuld, dan loost het pand op oppervlaktewater.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Als het vlak verder af ligt van een kolk dan deze maximale afstand dan is het vlak “niet aangesloten”. </SPAN></SPAN></P><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Als het vlak verder af ligt van een kolk dan deze maximale afstand dan is het vlak “niet aangesloten”. </SPAN></SPAN></P><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Het verschil in afstand tussen a) het vlak tot de gemengde buis en b) het vlak tot de HWA buis. Indien dit verschil groter is en gemengd dichter bij het vlak ligt watert het vlak af op gemengd.</SPAN></SPAN></P></DIV><DIV STYLE="text-align:Left;"><P STYLE="margin:0 0 11 0;"><SPAN><SPAN>Het verschil in afstand tussen a) het vlak tot de gemengde buis en b) het vlak tot de HWA buis. Indien dit verschil groter is en gemengd dichter bij het vlak ligt watert het vlak af op gemengd.</SPAN></SPAN></P><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>In andere worden omschrijven: hemelwater afkomstig van daken is schoon, dit water gaat direct zonder zuiveringsstap naar het oppervlakte water. Hemelwater afkomstig van verharding/wegen is ‘vervuild’ dit wordt ingezameld in een stelsel met zuiveringsstap (VGS of hemelwaterriool met bijvoorbeeld helofytenfilter of een stelsel waar nog een zuiveringsstap kan worden ingebouwd. Dit stelseltype komt niet veel voor met name op bedrijventerreinen/industrieterreinen/drukke verkeersaders aangelegd tussen eind jaren negentig tot begin zeros (ongeveer 2005).</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>In andere worden omschrijven: hemelwater afkomstig van daken is schoon, dit water gaat direct zonder zuiveringsstap naar het oppervlakte water. Hemelwater afkomstig van verharding/wegen is ‘vervuild’ dit wordt ingezameld in een stelsel met zuiveringsstap (VGS of hemelwaterriool met bijvoorbeeld helofytenfilter of een stelsel waar nog een zuiveringsstap kan worden ingebouwd. Dit stelseltype komt niet veel voor met name op bedrijventerreinen/industrieterreinen/drukke verkeersaders aangelegd tussen eind jaren negentig tot begin zeros (ongeveer 2005).</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Rekening houden met afgekoppelde daken. Indien </SPAN></SPAN><SPAN STYLE="text-decoration:underline;"><SPAN>niet</SPAN></SPAN><SPAN><SPAN> aangevinkt gaat de tool er van uit dat het dak sowieso is afgekoppeld van gemengd [indien gemengd en HWA voldoen aan “Maximale afstand afgekoppeld stelsel”]. Indien aangevinkt gaat de tool verder kijken naar het bouwjaar van het pand Oude panden (gebouwd vóór opgegeven bouwjaar) gaan naar 100% gemengd. Nieuwe panden worden volledig afgekoppeld van het gemengde riool. </SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Rekening houden met afgekoppelde daken. Indien </SPAN></SPAN><SPAN STYLE="text-decoration:underline;"><SPAN>niet</SPAN></SPAN><SPAN><SPAN> aangevinkt gaat de tool er van uit dat het dak sowieso is afgekoppeld van gemengd [indien gemengd en HWA voldoen aan “Maximale afstand afgekoppeld stelsel”]. Indien aangevinkt gaat de tool verder kijken naar het bouwjaar van het pand Oude panden (gebouwd vóór opgegeven bouwjaar) gaan naar 100% gemengd. Nieuwe panden worden volledig afgekoppeld van het gemengde riool. </SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Het jaartal vanaf wanneer de meeste woningen gescheiden riolering aanbieden. Deze gegevens haalt de tool uit de BAG. Het bepaalt (als de optie voor afkoppelen wordt gebruikt) of het pand onder niet, voor de helft of volledig wordt afgekoppeld indien er naast het gemengde riool ook een andere hemelwater ontvangende voorziening binnen X meter van het gemengde riool aanwezig is.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Het jaartal vanaf wanneer de meeste woningen gescheiden riolering aanbieden. Deze gegevens haalt de tool uit de BAG. Het bepaalt (als de optie voor afkoppelen wordt gebruikt) of het pand onder niet, voor de helft of volledig wordt afgekoppeld indien er naast het gemengde riool ook een andere hemelwater ontvangende voorziening binnen X meter van het gemengde riool aanwezig is.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Dit percentage van tuinen of grond rondom gebouwen wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN><SPAN>Dit percentage van tuinen of grond rondom gebouwen wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN><SPAN>Dit percentage van half verharde wegen (b.v. schelpenpad) wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN><SPAN>Dit percentage van half verharde wegen (b.v. schelpenpad) wordt meegerekend als aangesloten verhard oppervlak.</SPAN></SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Of de leidingcodes aan de vlakken gekoppeld moeten worden</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Of de leidingcodes aan de vlakken gekoppeld moeten worden</SPAN></P></DIV><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Reset de rekeninstellingen naar hun standaardwaardes</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Reset de rekeninstellingen naar hun standaardwaardes</SPAN></P></DIV><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>De BGT-inlooptool maakt het gebruik van de BGT-inlooptabel eenvoudiger. De BGT-inlooptool is een plug-in voor GIS-softwarepakketten en zorgt voor een automatische koppeling tussen de BGT-vlakken en GWSW-conforme rioleringsbestanden. Hiermee genereert u herbruikbare basisdata voor modellen, analyses, afvalwaterprognoses en kaarten. Handmatig gearceerde kaarten zijn daarmee verleden tijd. De resultaten uit de tool zijn gaandeweg telkens te verfijnen op basis van lokale kennis.</SPAN></P></DIV></DIV></DIV>2. BGT InlooptoolBGT InlooptoolArcToolbox Tool20241129 diff --git a/ArcGIS_plugin/BGTInloopToolbox.DownloadBasisData.pyt.xml b/ArcGIS_plugin/BGTInloopToolbox.DownloadBasisData.pyt.xml new file mode 100644 index 0000000..97fc592 --- /dev/null +++ b/ArcGIS_plugin/BGTInloopToolbox.DownloadBasisData.pyt.xml @@ -0,0 +1,2 @@ + +20241127132943001.0TRUE diff --git a/ArcGIS_plugin/BGTInloopToolbox.pyt b/ArcGIS_plugin/BGTInloopToolbox.pyt index 1eaa40e..4495288 100644 --- a/ArcGIS_plugin/BGTInloopToolbox.pyt +++ b/ArcGIS_plugin/BGTInloopToolbox.pyt @@ -5,18 +5,16 @@ Created By: Sjoerd Hoekstra Date: 29/09/2020 """ -from bgt_inlooptool.bgt_inlooptool_ArcGIS import BGTInloopToolArcGIS -from bgt_inlooptool.download_bgt_vlakken import DownloadBGTVlakken +from bgt_inlooptool.pyt_bgt_inlooptool_arcgis import BGTInloopToolArcGIS +from bgt_inlooptool.pyt_download_basis_data import DownloadBasisData class Toolbox(object): def __init__(self): - self.label = 'BGT Inloop Toolbox voor ArcGIS' - self.alias = 'Toolbox' - self.description = 'BGT Inloop Toolbox voor ArcGIS' + self.label = "BGT Inloop Toolbox voor ArcGIS" + self.alias = "Toolbox" + self.description = "BGT Inloop Toolbox voor ArcGIS" # Explicitly define tools here. - self.tools = [BGTInloopToolArcGIS, DownloadBGTVlakken] - - + self.tools = [BGTInloopToolArcGIS, DownloadBasisData] diff --git a/ArcGIS_plugin/BGTInloopToolbox.pyt.xml b/ArcGIS_plugin/BGTInloopToolbox.pyt.xml index abf2174..e55350f 100644 --- a/ArcGIS_plugin/BGTInloopToolbox.pyt.xml +++ b/ArcGIS_plugin/BGTInloopToolbox.pyt.xml @@ -1,2 +1,2 @@ -20201112093704001.0TRUE2021051016070500Rename C:\GitHub\bgt-inlooptool\ArcGIS_plugin\bgt_inloop_toolbox.pyt C:\GitHub\bgt-inlooptool\ArcGIS_plugin\BGTInloopToolbox.pyt #1500000005000ItemDescriptionc:\program files\arcgis\pro\Resources\Help\gpBGTInloopToolboxDeze toolbox kan worden gebruikt om de bgt inlooptool door te rekenen voor een gebiedBGT inlooptoolArcToolbox Toolbox20210510 +20201112093704001.0TRUE20250129093810Rename C:\GitHub\bgt-inlooptool\ArcGIS_plugin\bgt_inloop_toolbox.pyt C:\GitHub\bgt-inlooptool\ArcGIS_plugin\BGTInloopToolbox.pyt #1500000005000ItemDescriptionc:\program files\arcgis\pro\Resources\Help\gpBGTInloopToolboxDeze toolbox kan worden gebruikt om de bgt inlooptool door te rekenen voor een gebiedBGT inlooptoolArcToolbox Toolbox20210510 diff --git a/ArcGIS_plugin/bgt_inlooptool/bgt_inlooptool_ArcGIS.py b/ArcGIS_plugin/bgt_inlooptool/bgt_inlooptool_ArcGIS.py deleted file mode 100644 index eaefe48..0000000 --- a/ArcGIS_plugin/bgt_inlooptool/bgt_inlooptool_ArcGIS.py +++ /dev/null @@ -1,424 +0,0 @@ -""" -Script Name: bgt inloop tool voor ArcGIS -Description: bgt inloop tool voor ArcGIS -Created By: Sjoerd Hoekstra -Date: 29/09/2020 -""" - -import sys -import os -import arcpy - -# Relative imports don't work well in arcgis, therefore paths are appended to sys -bgt_inlooptool_dir = os.path.dirname(__file__) -sys.path.append(bgt_inlooptool_dir) -sys.path.append(os.path.join(bgt_inlooptool_dir, "core")) - -# Set path to Generic modules -from cls_general_use import GeneralUse -from common import BaseTool, parameter, get_wkt_extent, layers_to_gdb -from common import add_bgt_inlooptabel_symbologyfield, add_gwsw_symbologyfield -from visualize_layers import VisualizeLayers - -# import bgt inlooptool -from core.inlooptool import InloopTool, InputParameters -from core.defaults import ( - MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, - MAX_AFSTAND_VLAK_OPPWATER, - MAX_AFSTAND_PAND_OPPWATER, - MAX_AFSTAND_VLAK_KOLK, - MAX_AFSTAND_AFGEKOPPELD, - MAX_AFSTAND_DRIEVOUDIG, - AFKOPPELEN_HELLENDE_DAKEN, - BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, - VERHARDINGSGRAAD_ERF, - VERHARDINGSGRAAD_HALF_VERHARD, -) - - -class BGTInloopToolArcGIS(BaseTool): - def __init__(self): - """ - Initialization. - """ - self.label = "2. BGT Inlooptool" - self.description = """BGT inlooptool voor ArcGIS""" - self.canRunInBackground = True - self.arcgis_com = GeneralUse(sys, arcpy) - - def getParameterInfo(self): - """return Parameter definitions.""" - """Create your parameters here using the paramater function. - Make sure you leave the enclosing brackets and separate your - parameters using commas. - parameter(displayName, name, datatype, defaultValue=None, parameterType='Required', direction='Input') - """ - layers = os.path.join(os.path.dirname(__file__), "layers") - - parameters = [ - parameter( - displayName="BGT (als zipfile)", - name="bgt", - datatype="DEFile", - parameterType="Required", - direction="Input", - ), - parameter( - displayName="GWSW Leidingen (als geopackage)", - name="leidingen", - datatype="DEDatasetType", - parameterType="Required", - direction="Input", - ), - parameter( - displayName="BAG (als geopackage)", - name="bag", - datatype="DEDatasetType", - parameterType="Optional", - direction="Input", - ), - parameter( - displayName="Kolken", - name="kolken_file", - datatype="GPFeatureLayer", - parameterType="Optional", - direction="Input", - ), - parameter( - displayName="Analyse gebied", - name="input_extent_mask_wkt", - datatype="GPFeatureLayer", - parameterType="Optional", - direction="Input", - ), - parameter( - displayName="Opslag locatie gpkg", - name="output_gpkg", - datatype="DEDatasetType", - parameterType="Required", - direction="Output", - ), - parameter( - displayName="maximale afstand vlak afwateringsvoorziening", - name="max_vlak_afwatervoorziening", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, - ), - parameter( - displayName="maximale afstand vlak oppervlaktewater", - name="max_vlak_oppwater", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=MAX_AFSTAND_VLAK_OPPWATER, - ), - parameter( - displayName="maximale afstand pand oppervlaktewater", - name="max_pand_opwater", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=MAX_AFSTAND_PAND_OPPWATER, - ), - parameter( - displayName="maximale afstand vlak kolk", - name="max_vlak_kolk", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=MAX_AFSTAND_VLAK_KOLK, - ), - parameter( - displayName="maximale afstand afgekoppeld", - name="max_afgekoppeld", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=MAX_AFSTAND_AFGEKOPPELD, - ), - parameter( - displayName="maximale afstand drievoudig", - name="max_drievoudig", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=MAX_AFSTAND_DRIEVOUDIG, - ), - parameter( - displayName="afkoppelen hellende daken", - name="afkoppelen_daken", - datatype="GPBoolean", - parameterType="Required", - direction="Input", - defaultValue=AFKOPPELEN_HELLENDE_DAKEN, - ), - parameter( - displayName="bouwjaar gescheiden binnenhuisriolering", - name="bouwjaar_riool", - datatype="GPLong", - parameterType="Required", - direction="Input", - defaultValue=BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, - ), - parameter( - displayName="verhardingsgraad erf", - name="verhardingsgraaf_erf", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=VERHARDINGSGRAAD_ERF, - ), - parameter( - displayName="verhardingsgraad half verhard", - name="verhardingsgraad_half_verhard", - datatype="GPDouble", - parameterType="Required", - direction="Input", - defaultValue=VERHARDINGSGRAAD_HALF_VERHARD, - ), - parameter( - displayName="BGT oppervlakken symbology", - name="bgt_oppervlakken_symb", - datatype="GPLayer", - parameterType="Derived", - direction="Output", - symbology=os.path.join(layers, "bgt_oppervlakken.lyrx"), - ), - parameter( - displayName="BGT Inlooptabel symoblogy", - name="bgt_inlooptabel_symb", - datatype="GPLayer", - parameterType="Derived", - direction="Output", - symbology=os.path.join(layers, "bgt_inlooptabel.lyrx"), - ), - parameter( - displayName="GWSW lijnen symbology", - name="gwsw_lijn_symb", - datatype="GPLayer", - parameterType="Derived", - direction="Output", - symbology=os.path.join(layers, "gwsw_lijn.lyrx"), - ), - ] - - return parameters - - def updateParameters(self, parameters): - """ - updates a parameter in the interface if specified - """ - output_gpkg = parameters[5] - if output_gpkg.altered: - # TODO pad default naar projectmap - if "." in output_gpkg.valueAsText: - output_gpkg.value = output_gpkg.valueAsText.split(".")[0] + ".gpkg" - else: - output_gpkg.value = output_gpkg.valueAsText + ".gpkg" - - super(BGTInloopToolArcGIS, self).updateParameters(parameters) - - def updateMessages(self, parameters): - """ - returns messages in the interface the wrong paths are filled in for the different parameters - """ - bgt_file = parameters[0] - pipe_file = parameters[1] - bag_file = parameters[2] - input_area = parameters[4] - - if bgt_file.altered: - if bgt_file.valueAsText[-4:].lower() != ".zip": - bgt_file.setErrorMessage( - "De input voor bgt data moet een zip file zijn met .gml files" - ) - - if pipe_file.altered: - if pipe_file.valueAsText[-5:].lower() != ".gpkg": - pipe_file.setErrorMessage( - "De input voor leidingen data moet een geopackage (.gpkg) zijn" - ) - - if bag_file.altered: - if bag_file.valueAsText[-5:].lower() != ".gpkg": - bag_file.setErrorMessage( - "De input voor bag data moet een geopackage (.gpkg) zijn" - ) - - # Messages interesse gebied - if input_area.altered: - desc = arcpy.Describe(input_area.valueAsText) - if desc.dataType not in ["FeatureClass", "FeatureLayer", "ShapeFile"]: - input_area.setErrorMessage( - "De invoer is niet van het type featureclass/shapefile/gpkg layer!" - ) - else: - if desc.shapeType != "Polygon": - input_area.setErrorMessage( - "De featureclass/shapefile/gpkg layer is niet van het type polygoon!" - ) - else: - feature_count = int( - arcpy.management.GetCount(input_area.valueAsText).getOutput(0) - ) - if feature_count != 1: - input_area.setErrorMessage( - "Er is meer of minder dan 1 feature aanwezig of geselecteerd!" - ) - - super(BGTInloopToolArcGIS, self).updateMessages(parameters) - - def execute(self, parameters, messages): - try: - self.arcgis_com.StartAnalyse() - self.arcgis_com.AddMessage("Start BGT Inlooptool!") - - bgt_file = parameters[0].valueAsText - pipe_file = parameters[1].valueAsText - building_file = parameters[2].valueAsText - kolken_file = parameters[3].valueAsText - input_area = parameters[4].valueAsText - output_gpkg = parameters[5].valueAsText - - core_parameters = InputParameters( - max_afstand_vlak_afwateringsvoorziening=parameters[6].value, - max_afstand_vlak_oppwater=parameters[7].value, - max_afstand_pand_oppwater=parameters[8].value, - max_afstand_vlak_kolk=parameters[9].value, - max_afstand_afgekoppeld=parameters[10].value, - max_afstand_drievoudig=parameters[11].value, - afkoppelen_hellende_daken=parameters[12].value, - gebruik_bag=building_file != None, - gebruik_kolken=kolken_file != None, - bouwjaar_gescheiden_binnenhuisriolering=parameters[13].value, - verhardingsgraad_erf=parameters[14].value, - verhardingsgraad_half_verhard=parameters[15].value, - ) - - # Output layers - bgt_oppervlakken_symb = parameters[16] - bgt_inlooptabel_symb = parameters[17] - gwsw_lijn_symb = parameters[18] - - # start of the core - inlooptool = InloopTool(core_parameters) - # Import surfaces and pipes - self.arcgis_com.AddMessage("Importeren van BGT bestanden") - inlooptool.import_surfaces(bgt_file) - self.arcgis_com.AddMessage("Importeren van GWSW bestanden") - inlooptool.import_pipes(pipe_file) - - if core_parameters.gebruik_kolken: - self.arcgis_com.AddMessage("Importeren van kolken bestanden") - inlooptool.import_kolken(kolken_file) - inlooptool._database.add_index_to_inputs( - kolken=core_parameters.gebruik_kolken - ) - - if core_parameters.gebruik_bag: - self.arcgis_com.AddMessage("Importeren van BAG gebouw bestanden") - inlooptool._database.add_build_year_to_surface(file_path=building_file) - - if input_area is not None: - # get the input extent as wkt from the input_area - input_extent_mask_wkt = get_wkt_extent(input_area) - - inlooptool._database.remove_input_features_outside_clip_extent( - input_extent_mask_wkt - ) - inlooptool._database.add_index_to_inputs( - kolken=core_parameters.gebruik_kolken - ) - - self.arcgis_com.AddMessage("Afstanden aan het berekenen") - inlooptool.calculate_distances(parameters=core_parameters) - self.arcgis_com.AddMessage("Bereken Runoff targets") - inlooptool.calculate_runoff_targets() - - # Export results - self.arcgis_com.AddMessage("Exporteren naar GPKG") - inlooptool._database._write_to_disk(output_gpkg) - - # Add layers to the map - self.arcgis_com.AddMessage("Visualiseren van resultaten!") - out_gdb = output_gpkg.replace(".gpkg", ".gdb") - # add symbology field for bgt_inlooptabel - main_bgt_inlooptabel = layers_to_gdb( - input_dataset=os.path.join(output_gpkg, "main.bgt_inlooptabel"), - output_gdb=out_gdb, - ) - add_bgt_inlooptabel_symbologyfield(main_bgt_inlooptabel) - bgt_oppervlakken_symb.value = main_bgt_inlooptabel - bgt_inlooptabel_symb.value = main_bgt_inlooptabel - - # add symbology field for GWSW lijnen - main_default_lijn = layers_to_gdb( - input_dataset=os.path.join(pipe_file, "main.default_lijn"), - output_gdb=out_gdb, - ) - add_gwsw_symbologyfield(main_default_lijn) - gwsw_lijn_symb.value = main_default_lijn - - visualize_layers = VisualizeLayers() - for x, layer_parameter in enumerate( - [bgt_oppervlakken_symb, bgt_inlooptabel_symb, gwsw_lijn_symb], 16 - ): - visualize_layers.add_layer_to_map(in_param=layer_parameter, param_nr=x) - visualize_layers.save() - - except Exception: - self.arcgis_com.Traceback() - finally: - self.arcgis_com.AddMessage("Klaar") - return - - -if __name__ == "__main__": - # This is used for debugging. Using this separated structure makes it much - # easier to debug using standard Python development tools. - - try: - tool = BGTInloopToolArcGIS() - params = tool.getParameterInfo() - - main_path = r"C:\Users\vdi\OneDrive - TAUW Group bv\Werkzaamheden\1287914 - BGT inlooptool\testdata2" - # bgt_file - params[0].value = os.path.join(main_path, "BGT_Akersloot2.zip") - # pipe_file - params[1].value = os.path.join(main_path, "getGeoPackage_1934.gpkg") - # bag_file - params[2].value = os.path.join(main_path, "BAG_Akersloot.gpkg") - # kolken_file - params[3].value = os.path.join(main_path, "kolken_Castricum_Limmen_Akersloot.shp") - # area_file - params[4].value = os.path.join(main_path, "extent_Akersloot.shp") #os.path.join(main_path, r"polyoon_centrum.gdb\Polygoon_centrum") - # output_location - params[5].value = os.path.join(main_path, "output.gpkg") - - # maximale afstand vlak afwateringsvoorziening - params[6].value = 40 - # maximale afstand vlak oppervlaktewater - params[7].value = 2 - # maximale afstand pand oppervlaktewater - params[8].value = 6 - # 'maximale afstand vlak kolk - params[9].value = 30 - # maximale afstand afgekoppeld - params[10].value = 3 - # maximale afstand drievoudig - params[11].value = 4 - # afkoppelen hellende daken - params[12].value = True - # bouwjaar gescheiden binnenhuisriolering - params[13].value = 1992 - # verhardingsgraad erf - params[14].value = 50 - # verhardingsgraad half verhard - params[15].value = 50 - - tool.execute(parameters=params, messages=None) - - except Exception as ex: - print("iets ging fout!") diff --git a/ArcGIS_plugin/bgt_inlooptool/core/constants.py b/ArcGIS_plugin/bgt_inlooptool/core/constants.py index 141d9f8..5475865 100644 --- a/ArcGIS_plugin/bgt_inlooptool/core/constants.py +++ b/ArcGIS_plugin/bgt_inlooptool/core/constants.py @@ -73,6 +73,8 @@ VERHARDINGSTYPE_ONVERHARD = "onverhard" VERHARDINGSTYPE_OPEN_VERHARD = "open verhard" VERHARDINGSTYPE_GESLOTEN_VERHARD = "gesloten verhard" +VERHARDINGSTYPE_WATERPASSEREND_VERHARD = "waterpasserende verharding" +VERHARDINGSTYPE_GROEN_DAK = "groen(blauw) dak" SOURCE_PIPES_TABLE_NAME = "default_lijn" @@ -109,6 +111,7 @@ INTERNAL_PIPE_TYPE_GEMENGD_RIOOL = "gemengd_riool" INTERNAL_PIPE_TYPE_HEMELWATERRIOOL = "hemelwaterriool" INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL = "vgs_hemelwaterriool" +INTERNAL_PIPE_TYPE_VUILWATERRIOOL = "vuilwaterriool" INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING = "infiltratievoorziening" PIPE_MAP = { @@ -130,7 +133,7 @@ GWSW_PIPE_TYPE_PERCEELAANSLUITLEIDING: INTERNAL_PIPE_TYPE_IGNORE, GWSW_PIPE_TYPE_PERSLEIDING: INTERNAL_PIPE_TYPE_IGNORE, GWSW_PIPE_TYPE_TRANSPORTRIOOLLEIDING: INTERNAL_PIPE_TYPE_IGNORE, - GWSW_PIPE_TYPE_VUILWATERRIOOL: INTERNAL_PIPE_TYPE_IGNORE, + GWSW_PIPE_TYPE_VUILWATERRIOOL: INTERNAL_PIPE_TYPE_VUILWATERRIOOL, GWSW_PIPE_TYPE_DITRIOOL: INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, } @@ -140,6 +143,7 @@ BUILDINGS_TABLE_NAME = "buildings" KOLKEN_TABLE_NAME = "kolken" RESULT_TABLE_NAME = "bgt_inlooptabel" +RESULT_TABLE_NAME_PREV = "bgt_inlooptabel_oud" RESULT_TABLE_FIELD_ID = "id" RESULT_TABLE_FIELD_LAATSTE_WIJZIGING = "laatste_wijziging" @@ -151,9 +155,11 @@ # RESULT_TABLE_FIELD_BERGING_DAK = 'berging_dak' RESULT_TABLE_FIELD_TYPE_PRIVATE_VOORZIENING = "type_private_voorziening" RESULT_TABLE_FIELD_BERGING_PRIVATE_VOORZIENING = "berging_private_voorziening" -RESULT_TABLE_FIELD_PUTCODE = "putcode" -RESULT_TABLE_FIELD_LEIDINGCODE = "leidingcode" -RESULT_TABLE_FIELD_CODE_VOORZIENING = "code_voorziening" +RESULT_TABLE_FIELD_CODE_GEMENGD = "leidingcode_gemengd" +RESULT_TABLE_FIELD_CODE_HWA = "leidingcode_hwa" +RESULT_TABLE_FIELD_CODE_DWA = "leidingcode_dwa" +RESULT_TABLE_FIELD_CODE_INFILTRATIE = "leidingcode_infiltratie" +RESULT_TABLE_FIELD_WIJZIGING = "wijziging" TARGET_TYPE_GEMENGD_RIOOL = "gemengd_riool" TARGET_TYPE_HEMELWATERRIOOL = "hemelwaterriool" @@ -177,7 +183,142 @@ INTERNAL_PIPE_TYPE_GEMENGD_RIOOL, INTERNAL_PIPE_TYPE_HEMELWATERRIOOL, INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL, + INTERNAL_PIPE_TYPE_VUILWATERRIOOL, INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, KOLK, OPEN_WATER, } + +SETTINGS_TABLE_NAME = "rekeninstellingen" +SETTINGS_TABLE_NAME_PREV = "rekeninstellingen_oud" +INF_PAVEMENT_TABLE_NAME_PREV = "waterpasserende_verharding_oud" + +SETTINGS_TABLE_FIELD_ID = "run_id" +SETTINGS_TABLE_FIELD_TIJD_START = "tijd_start" +SETTINGS_TABLE_FIELD_TIJD_EIND = "tijd_eind" +SETTINGS_TABLE_FIELD_DOWNLOAD_BGT = "download_bgt" +SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW = "download_gwsw" +SETTINGS_TABLE_FIELD_DOWNLOAD_BAG = "download_bag" +SETTINGS_TABLE_FIELD_PAD_BGT = "pad_bgt" +SETTINGS_TABLE_FIELD_PAD_GWSW = "pad_gwsw" +SETTINGS_TABLE_FIELD_PAD_BAG = "pad_bag" +SETTINGS_TABLE_FIELD_PAD_KOLKEN = "pad_kolken" +SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING = "afstand_afwateringsvoorziening" +SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER = "afstand_verhard_opp_water" +SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER = "afstand_pand_opp_water" +SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK = "afstand_verhard_kolk" +SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD = "afstand_afgekoppeld" +SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG = "afstand_drievoudig" +SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF = "verhardingsgraad_erf" +SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD = "verhardingsgraad_half_verhard" +SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND = "afkoppelen_hellend" +SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS = "bouwjaar_gescheiden_binnenhuis" +SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN = "leidingcodes_koppelen" + +STATISTICS_TABLE_NAME = "statistieken" + +STATISTICS_TABLE_FIELD_ID = "id" +STATISTICS_TABLE_FIELD_OPP_TOTAAL = "opp_totaal" +STATISTICS_TABLE_FIELD_OPP_GEMENGD = "opp_gemengd" +STATISTICS_TABLE_FIELD_OPP_HWA = "opp_hwa" +STATISTICS_TABLE_FIELD_OPP_VGS = "opp_vgs" +STATISTICS_TABLE_FIELD_OPP_DWA = "opp_dwa" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING = "opp_infiltratievoorziening" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER = "opp_open_water" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD = "opp_maaiveld" +STATISTICS_TABLE_FIELD_PERC_GEMENGD = "perc_gemengd" +STATISTICS_TABLE_FIELD_PERC_HWA = "perc_hwa" +STATISTICS_TABLE_FIELD_PERC_VGS = "perc_vgs" +STATISTICS_TABLE_FIELD_PERC_DWA = "perc_dwa" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING = "perc_infiltratievoorziening" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER = "perc_open_water" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD = "perc_maaiveld" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_DAK = "opp_totaal_dak" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_GESL_VERH = "opp_totaal_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_OPEN_VERH = "opp_totaal_open_verh" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_ONVERHARD = "opp_totaal_onverhard" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_DAK = "opp_gemengd_dak" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_GESL_VERH = "opp_gemengd_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_OPEN_VERH = "opp_gemengd_open_verh" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_ONVERHARD = "opp_gemengd_onverhard" +STATISTICS_TABLE_FIELD_OPP_HWA_DAK = "opp_hwa_dak" +STATISTICS_TABLE_FIELD_OPP_HWA_GESL_VERH = "opp_hwa_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_HWA_OPEN_VERH = "opp_hwa_open_verh" +STATISTICS_TABLE_FIELD_OPP_HWA_ONVERHARD = "opp_hwa_onverhard" +STATISTICS_TABLE_FIELD_OPP_VGS_DAK = "opp_vgs_dak" +STATISTICS_TABLE_FIELD_OPP_VGS_GESL_VERH = "opp_vgs_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_VGS_OPEN_VERH = "opp_vgs_open_verh" +STATISTICS_TABLE_FIELD_OPP_VGS_ONVERHARD = "opp_vgs_onverhard" +STATISTICS_TABLE_FIELD_OPP_DWA_DAK = "opp_dwa_dak" +STATISTICS_TABLE_FIELD_OPP_DWA_GESL_VERH = "opp_dwa_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_DWA_OPEN_VERH = "opp_dwa_open_verh" +STATISTICS_TABLE_FIELD_OPP_DWA_ONVERHARD = "opp_dwa_onverhard" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_DAK = "opp_infiltratievoorziening_dak" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_GESL_VERH = "opp_infiltratievoorziening_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_OPEN_VERH = "opp_infiltratievoorziening_open_verh" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_ONVERHARD = "opp_infiltratievoorziening_onverhard" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_DAK = "opp_open_water_dak" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_GESL_VERH = "opp_open_water_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_OPEN_VERH = "opp_open_water_open_verh" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_ONVERHARD = "opp_open_water_onverhard" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_DAK = "opp_maaiveld_dak" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_GESL_VERH = "opp_maaiveld_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_OPEN_VERH = "opp_maaiveld_open_verh" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_ONVERHARD = "opp_maaiveld_onverhard" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_DAK = "perc_gemengd_dak" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_GESL_VERH = "perc_gemengd_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_OPEN_VERH = "perc_gemengd_open_verh" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_ONVERHARD = "perc_gemengd_onverhard" +STATISTICS_TABLE_FIELD_PERC_HWA_DAK = "perc_hwa_dak" +STATISTICS_TABLE_FIELD_PERC_HWA_GESL_VERH = "perc_hwa_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_HWA_OPEN_VERH = "perc_hwa_open_verh" +STATISTICS_TABLE_FIELD_PERC_HWA_ONVERHARD = "perc_hwa_onverhard" +STATISTICS_TABLE_FIELD_PERC_VGS_DAK = "perc_vgs_dak" +STATISTICS_TABLE_FIELD_PERC_VGS_GESL_VERH = "perc_vgs_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_VGS_OPEN_VERH = "perc_vgs_open_verh" +STATISTICS_TABLE_FIELD_PERC_VGS_ONVERHARD = "perc_vgs_onverhard" +STATISTICS_TABLE_FIELD_PERC_DWA_DAK = "perc_dwa_dak" +STATISTICS_TABLE_FIELD_PERC_DWA_GESL_VERH = "perc_dwa_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_DWA_OPEN_VERH = "perc_dwa_open_verh" +STATISTICS_TABLE_FIELD_PERC_DWA_ONVERHARD = "perc_dwa_onverhard" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_DAK = "perc_infiltratievoorziening_dak" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_GESL_VERH = "perc_infiltratievoorziening_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_OPEN_VERH = "perc_infiltratievoorziening_open_verh" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_ONVERHARD = "perc_infiltratievoorziening_onverhard" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_DAK = "perc_open_water_dak" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_GESL_VERH = "perc_open_water_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_OPEN_VERH = "perc_open_water_open_verh" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_ONVERHARD = "perc_open_water_onverhard" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_DAK = "perc_maaiveld_dak" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_GESL_VERH = "perc_maaiveld_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_OPEN_VERH = "perc_maaiveld_open_verh" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_ONVERHARD = "perc_maaiveld_onverhard" +STATISTICS_TABLE_FIELD_OPP_DAK = "opp_dak" +STATISTICS_TABLE_FIELD_OPP_GESL_VERH = "opp_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_OPEN_VERH = "opp_open_verh" +STATISTICS_TABLE_FIELD_OPP_ONVERHARD = "opp_onverhard" +STATISTICS_TABLE_FIELD_OPP_GROEN_DAK = "opp_groen_dak" +STATISTICS_TABLE_FIELD_OPP_WATERPAS_VERH = "opp_waterpas_verh" +STATISTICS_TABLE_FIELD_OPP_WATER = "opp_water" +STATISTICS_TABLE_FIELD_PERC_DAK = "perc_dak" +STATISTICS_TABLE_FIELD_PERC_GESL_VERH = "perc_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_OPEN_VERH = "perc_open_verh" +STATISTICS_TABLE_FIELD_PERC_ONVERHARD = "perc_onverhard" +STATISTICS_TABLE_FIELD_PERC_GROEN_DAK = "perc_groen_dak" +STATISTICS_TABLE_FIELD_PERC_WATERPAS_VERH = "perc_waterpas_verh" +STATISTICS_TABLE_FIELD_PERC_WATER = "perc_water" + + +CHECKS_TABLE_NAME = "controles" + +CHECKS_TABLE_FIELD_ID = "id" +CHECKS_TABLE_FIELD_LEVEL = "niveau" +CHECKS_TABLE_FIELD_CODE = "error_code" +CHECKS_TABLE_FIELD_TABLE = "tabel" +CHECKS_TABLE_FIELD_COLUMN = "kolom" +CHECKS_TABLE_FIELD_VALUE = "waarde" +CHECKS_TABLE_FIELD_DESCRIPTION = "omschrijving" + +CHECKS_LARGE_AREA = 5000 + + diff --git a/ArcGIS_plugin/bgt_inlooptool/core/defaults.py b/ArcGIS_plugin/bgt_inlooptool/core/defaults.py index 221e6fa..63e85ab 100644 --- a/ArcGIS_plugin/bgt_inlooptool/core/defaults.py +++ b/ArcGIS_plugin/bgt_inlooptool/core/defaults.py @@ -7,6 +7,12 @@ AFKOPPELEN_HELLENDE_DAKEN = True GEBRUIK_BAG = False GEBRUIK_KOLKEN = False +GEBRUIK_RESULTATEN = False +GEBRUIK_STATISTIEKEN = False +DOWNLOAD_BGT = False +DOWNLOAD_GWSW = False +DOWNLOAD_BAG = False +KOPPEL_LEIDINGCODES = False BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING = 1992 -VERHARDINGSGRAAD_ERF = 50 +VERHARDINGSGRAAD_ERF = 0 VERHARDINGSGRAAD_HALF_VERHARD = 50 diff --git a/ArcGIS_plugin/bgt_inlooptool/core/inlooptool.py b/ArcGIS_plugin/bgt_inlooptool/core/inlooptool.py index 54a75b3..930d3ff 100644 --- a/ArcGIS_plugin/bgt_inlooptool/core/inlooptool.py +++ b/ArcGIS_plugin/bgt_inlooptool/core/inlooptool.py @@ -1,43 +1,261 @@ +""" +Last update on Tue Jan 28 11:47:10 2025 +By: Ruben van der Zaag +Email: bgtinlooptool@nelen-schuurmans.nl +""" + +import contextlib + # System imports import os -import sys +from datetime import datetime + +import rtree # rtree is installed using a wheel (0.9.7 in python 3.9) # Third-party imports -from osgeo import osr -from osgeo import gdal -from osgeo import ogr -from datetime import datetime -from pathlib import Path - -try: - import rtree -except ImportError: - from .rtree_installer import unpack_rtree - if not os.path.isdir(Path(__file__).parent / "rtree"): # bgt_inlooptool\\rtree - rtree_path = unpack_rtree() - sys.path.append(str(rtree_path)) - - try: - import rtree - except ImportError: - print("The 'rtree' package installation failed.") +from osgeo import gdal, ogr, osr # Local imports -from core.table_schemas import * -from core.constants import * from core.constants import ( ALL_USED_SURFACE_TYPES, + BUILDINGS_TABLE_NAME, + CHECKS_LARGE_AREA, + CHECKS_TABLE_FIELD_CODE, + CHECKS_TABLE_FIELD_COLUMN, + CHECKS_TABLE_FIELD_DESCRIPTION, + CHECKS_TABLE_FIELD_ID, + CHECKS_TABLE_FIELD_LEVEL, + CHECKS_TABLE_FIELD_TABLE, + CHECKS_TABLE_FIELD_VALUE, + CHECKS_TABLE_NAME, + CONNECTABLE_SURFACE_TYPES, + DISTANCE_TYPES, + GWSW_PIPE_TYPE_AANSLUITLEIDING, + GWSW_PIPE_TYPE_BERGINGSLEIDING, + GWSW_PIPE_TYPE_DITRIOOL, + GWSW_PIPE_TYPE_DRAIN, + GWSW_PIPE_TYPE_DRUKLEIDING, + GWSW_PIPE_TYPE_DUIKER, + GWSW_PIPE_TYPE_DWAPERCEELAANSLUITLEIDING, + GWSW_PIPE_TYPE_FIELD, + GWSW_PIPE_TYPE_GEMENGDEPERCEELAANSLUITLEIDING, + GWSW_PIPE_TYPE_GEMENGDRIOOL, + GWSW_PIPE_TYPE_HEMELWATERRIOOL, + GWSW_PIPE_TYPE_HWAPERCEELAANSLUITLEIDING, + GWSW_PIPE_TYPE_INFILTRATIERIOOL, + GWSW_PIPE_TYPE_LOZELEIDING, + GWSW_PIPE_TYPE_LUCHTPERSLEIDING, + GWSW_PIPE_TYPE_MANTELBUIS, + GWSW_PIPE_TYPE_OVERSTORTLEIDING, + GWSW_PIPE_TYPE_PERCEELAANSLUITLEIDING, + GWSW_PIPE_TYPE_PERSLEIDING, + GWSW_PIPE_TYPE_TRANSPORTRIOOLLEIDING, + GWSW_PIPE_TYPE_VUILWATERRIOOL, + GWSW_STELSEL_TYPE_FIELD, + GWSW_STELSEL_TYPE_VERBETERDHEMELWATERSTELSEL, + INF_PAVEMENT_TABLE_NAME_PREV, + INTERNAL_PIPE_TYPE_FIELD, + INTERNAL_PIPE_TYPE_GEMENGD_RIOOL, + INTERNAL_PIPE_TYPE_HEMELWATERRIOOL, + INTERNAL_PIPE_TYPE_IGNORE, + INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, + INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL, + INTERNAL_PIPE_TYPE_VUILWATERRIOOL, + KOLK, + KOLK_CONNECTABLE_SURFACE_TYPES, + KOLKEN_TABLE_NAME, MULTIPLE_GEOMETRY_SURFACE_TYPES, - SURFACES_TABLE_NAME, + NON_CONNECTABLE_SURFACE_TYPES, + OPEN_WATER, + PIPE_MAP, + PIPES_TABLE_NAME, + PSEUDO_INFINITE, + RESULT_TABLE_FIELD_BERGING_PRIVATE_VOORZIENING, + RESULT_TABLE_FIELD_BGT_IDENTIFICATIE, + RESULT_TABLE_FIELD_CODE_DWA, + RESULT_TABLE_FIELD_CODE_GEMENGD, + RESULT_TABLE_FIELD_CODE_HWA, + RESULT_TABLE_FIELD_CODE_INFILTRATIE, RESULT_TABLE_FIELD_GRAAD_VERHARDING, + RESULT_TABLE_FIELD_HELLINGSPERCENTAGE, + RESULT_TABLE_FIELD_HELLINGSTYPE, + RESULT_TABLE_FIELD_ID, + RESULT_TABLE_FIELD_LAATSTE_WIJZIGING, + RESULT_TABLE_FIELD_TYPE_PRIVATE_VOORZIENING, RESULT_TABLE_FIELD_TYPE_VERHARDING, + RESULT_TABLE_FIELD_WIJZIGING, + RESULT_TABLE_NAME, + RESULT_TABLE_NAME_PREV, + SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND, + SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD, + SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING, + SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG, + SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER, + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK, + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER, + SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS, + SETTINGS_TABLE_FIELD_DOWNLOAD_BAG, + SETTINGS_TABLE_FIELD_DOWNLOAD_BGT, + SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW, + SETTINGS_TABLE_FIELD_ID, + SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN, + SETTINGS_TABLE_FIELD_PAD_BAG, + SETTINGS_TABLE_FIELD_PAD_BGT, + SETTINGS_TABLE_FIELD_PAD_GWSW, + SETTINGS_TABLE_FIELD_PAD_KOLKEN, + SETTINGS_TABLE_FIELD_TIJD_EIND, + SETTINGS_TABLE_FIELD_TIJD_START, + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF, + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD, + SETTINGS_TABLE_NAME, + SETTINGS_TABLE_NAME_PREV, + SOURCE_PIPES_TABLE_NAME, + STATISTICS_TABLE_FIELD_ID, + STATISTICS_TABLE_FIELD_OPP_DAK, + STATISTICS_TABLE_FIELD_OPP_DWA, + STATISTICS_TABLE_FIELD_OPP_DWA_DAK, + STATISTICS_TABLE_FIELD_OPP_DWA_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_DWA_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_DWA_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_GEMENGD, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_DAK, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_GROEN_DAK, + STATISTICS_TABLE_FIELD_OPP_HWA, + STATISTICS_TABLE_FIELD_OPP_HWA_DAK, + STATISTICS_TABLE_FIELD_OPP_HWA_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_HWA_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_HWA_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_DAK, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_DAK, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_DAK, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_TOTAAL, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_DAK, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_VGS, + STATISTICS_TABLE_FIELD_OPP_VGS_DAK, + STATISTICS_TABLE_FIELD_OPP_VGS_GESL_VERH, + STATISTICS_TABLE_FIELD_OPP_VGS_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_VGS_OPEN_VERH, + STATISTICS_TABLE_FIELD_OPP_WATER, + STATISTICS_TABLE_FIELD_OPP_WATERPAS_VERH, + STATISTICS_TABLE_FIELD_PERC_DAK, + STATISTICS_TABLE_FIELD_PERC_DWA, + STATISTICS_TABLE_FIELD_PERC_DWA_DAK, + STATISTICS_TABLE_FIELD_PERC_DWA_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_DWA_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_DWA_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_GEMENGD, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_DAK, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_GROEN_DAK, + STATISTICS_TABLE_FIELD_PERC_HWA, + STATISTICS_TABLE_FIELD_PERC_HWA_DAK, + STATISTICS_TABLE_FIELD_PERC_HWA_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_HWA_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_HWA_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_DAK, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_DAK, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_DAK, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_VGS, + STATISTICS_TABLE_FIELD_PERC_VGS_DAK, + STATISTICS_TABLE_FIELD_PERC_VGS_GESL_VERH, + STATISTICS_TABLE_FIELD_PERC_VGS_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_VGS_OPEN_VERH, + STATISTICS_TABLE_FIELD_PERC_WATER, + STATISTICS_TABLE_FIELD_PERC_WATERPAS_VERH, + STATISTICS_TABLE_NAME, + SURFACE_TYPE_BEGROEIDTERREINDEEL, + SURFACE_TYPE_GEBOUWINSTALLATIE, + SURFACE_TYPE_ONBEGROEIDTERREINDEEL, + SURFACE_TYPE_ONDERSTEUNENDWATERDEEL, + SURFACE_TYPE_ONDERSTEUNENDWEGDEEL, + SURFACE_TYPE_OVERBRUGGINGSDEEL, + SURFACE_TYPE_OVERIGBOUWWERK, SURFACE_TYPE_PAND, - VERHARDINGSTYPE_PAND, SURFACE_TYPE_WATERDEEL, + SURFACE_TYPE_WEGDEEL, + SURFACE_TYPES_MET_FYSIEK_VOORKOMEN, + SURFACES_TABLE_NAME, + TARGET_TYPE_GEMENGD_RIOOL, + TARGET_TYPE_HEMELWATERRIOOL, + TARGET_TYPE_INFILTRATIEVOORZIENING, + TARGET_TYPE_MAAIVELD, + TARGET_TYPE_OPEN_WATER, + TARGET_TYPE_VGS_HEMELWATERRIOOL, + TARGET_TYPE_VUILWATERRIOOL, + TARGET_TYPES, + VERHARDINGSTYPE_GESLOTEN_VERHARD, + VERHARDINGSTYPE_GROEN_DAK, + VERHARDINGSTYPE_ONVERHARD, + VERHARDINGSTYPE_OPEN_VERHARD, + VERHARDINGSTYPE_PAND, VERHARDINGSTYPE_WATER, - PIPES_TABLE_NAME, + VERHARDINGSTYPE_WATERPASSEREND_VERHARD, +) +from core.defaults import ( + AFKOPPELEN_HELLENDE_DAKEN, + BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, + DOWNLOAD_BAG, + DOWNLOAD_BGT, + DOWNLOAD_GWSW, + GEBRUIK_BAG, + GEBRUIK_KOLKEN, + GEBRUIK_RESULTATEN, + GEBRUIK_STATISTIEKEN, + KOPPEL_LEIDINGCODES, + MAX_AFSTAND_AFGEKOPPELD, + MAX_AFSTAND_DRIEVOUDIG, + MAX_AFSTAND_PAND_OPPWATER, + MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, + MAX_AFSTAND_VLAK_KOLK, + MAX_AFSTAND_VLAK_OPPWATER, + VERHARDINGSGRAAD_ERF, + VERHARDINGSGRAAD_HALF_VERHARD, +) +from core.table_schemas import ( + CHECKS_TABLE_SCHEMA, + RESULT_TABLE_SCHEMA, + SETTINGS_TABLE_SCHEMA, + STATISTICS_TABLE_SCHEMA, + SURFACES_TABLE_SCHEMA, ) -from core.defaults import * # Globals GFS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gfs") @@ -76,8 +294,14 @@ def __init__( max_afstand_afgekoppeld=MAX_AFSTAND_AFGEKOPPELD, max_afstand_drievoudig=MAX_AFSTAND_DRIEVOUDIG, afkoppelen_hellende_daken=AFKOPPELEN_HELLENDE_DAKEN, + leidingcodes_koppelen=KOPPEL_LEIDINGCODES, gebruik_bag=GEBRUIK_BAG, gebruik_kolken=GEBRUIK_KOLKEN, + gebruik_resultaten=GEBRUIK_RESULTATEN, + gebruik_statistieken=GEBRUIK_STATISTIEKEN, + download_bgt=DOWNLOAD_BGT, + download_gwsw=DOWNLOAD_GWSW, + download_bag=DOWNLOAD_BAG, bouwjaar_gescheiden_binnenhuisriolering=BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, verhardingsgraad_erf=VERHARDINGSGRAAD_ERF, verhardingsgraad_half_verhard=VERHARDINGSGRAAD_HALF_VERHARD, @@ -91,8 +315,14 @@ def __init__( self.max_afstand_afgekoppeld = max_afstand_afgekoppeld self.max_afstand_drievoudig = max_afstand_drievoudig self.afkoppelen_hellende_daken = afkoppelen_hellende_daken + self.leidingcodes_koppelen = leidingcodes_koppelen self.gebruik_bag = gebruik_bag self.gebruik_kolken = gebruik_kolken + self.gebruik_resultaten = gebruik_resultaten + self.gebruik_statistieken = gebruik_statistieken + self.download_bgt = download_bgt + self.download_gwsw = download_gwsw + self.download_bag = download_bag self.bouwjaar_gescheiden_binnenhuisriolering = ( bouwjaar_gescheiden_binnenhuisriolering ) @@ -111,17 +341,162 @@ def __init__(self, parameters): """Constructor.""" self.parameters = parameters self._database = Database() + self.inf_pavements_green_roof_surfaces = [] + self.relative_hoogteligging_surfaces = [] + self.new_BGT_surfaces = [] + self.outdated_changed_surfaces = [] + + def set_settings_start(self, bgt_file, pipe_file, building_file, kolken_file): + settings_table = self._database.settings_table + feature_defn = settings_table.GetLayerDefn() + feature = ogr.Feature(feature_defn) + + # Copy settings from previous runs to the new settings table: + prev_settings = self._database.mem_database.GetLayerByName( + SETTINGS_TABLE_NAME_PREV + ) + + if prev_settings is not None: + self._database.copy_features_with_matching_fields( + prev_settings, settings_table, "run_id" + ) + + max_fid = -1 + for feature in settings_table: + fid = feature.GetFID() + 1 + if fid > max_fid: + max_fid = fid + + if feature is None: + new_fid = 1 + else: + new_fid = max_fid + 1 + + feature.SetField( + SETTINGS_TABLE_FIELD_ID, + new_fid, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_TIJD_START, + datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + ) + feature.SetField( + SETTINGS_TABLE_FIELD_DOWNLOAD_BGT, self.parameters.download_bgt + ) + feature.SetField( + SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW, self.parameters.download_gwsw + ) + feature.SetField( + SETTINGS_TABLE_FIELD_DOWNLOAD_BAG, self.parameters.download_bag + ) + feature.SetField(SETTINGS_TABLE_FIELD_PAD_BGT, bgt_file) + feature.SetField(SETTINGS_TABLE_FIELD_PAD_GWSW, pipe_file) + feature.SetField(SETTINGS_TABLE_FIELD_PAD_BAG, building_file) + feature.SetField(SETTINGS_TABLE_FIELD_PAD_KOLKEN, kolken_file) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING, + self.parameters.max_afstand_vlak_afwateringsvoorziening, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER, + self.parameters.max_afstand_vlak_oppwater, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER, + self.parameters.max_afstand_pand_oppwater, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK, + self.parameters.max_afstand_vlak_kolk, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD, + self.parameters.max_afstand_afgekoppeld, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG, + self.parameters.max_afstand_drievoudig, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF, + self.parameters.verhardingsgraad_erf, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD, + self.parameters.verhardingsgraad_half_verhard, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND, + self.parameters.afkoppelen_hellende_daken, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS, + self.parameters.bouwjaar_gescheiden_binnenhuisriolering, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN, + self.parameters.leidingcodes_koppelen, + ) + + settings_table.CreateFeature(feature) + feature = None + settings_table = None + + def set_settings_end(self): + # Find the feature with the highest FID + max_fid = -1 + feature_to_update = None - def import_surfaces(self, file_path): + settings_table = self._database.settings_table + + for feature in settings_table: + fid = feature.GetFID() + if fid > max_fid: + max_fid = fid + feature_to_update = feature + + if feature_to_update is not None: + # Set the new value for the specified field + feature_to_update.SetField( + SETTINGS_TABLE_FIELD_TIJD_EIND, + datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + ) + + # Update the feature in the layer + settings_table.SetFeature(feature_to_update) + + # Clean up + feature_to_update = None + settings_table = None + print(f"Settings of run {max_fid} updated successfully.") + else: + print("No features found in the layer.") + + def import_results(self, file_path): + """ + Import results from previous run to _database + :param file_path: path to results gpkg of a previous run + :return: None + """ + self._database.import_settings_results(file_path) + self._database.import_inf_pavement_green_roofs(file_path) + self._database.import_it_results(file_path) + self._database.clean_it_results() + + def import_surfaces(self, file_path, extent_wkt): """ Import BGT Surfaces to _database :param file_path: path to bgt zip file + :param extent_wkt: exent of study area :return: None """ - self._database.import_surfaces_raw(file_path) + self._database.import_surfaces_raw(file_path, extent_wkt) self._database.clean_surfaces() self._database.merge_surfaces() self._database.classify_surfaces(self.parameters) + self.relative_hoogteligging_surfaces = ( + self._database.identify_overlapping_surfaces() + ) def import_pipes(self, file_path, relevant_only=True): """ @@ -164,7 +539,6 @@ def is_water(): def verhard(): """Is het oppervlak (mogelijk/deels) verhard?""" - a = surface.type_verharding if surface.surface_type in NON_CONNECTABLE_SURFACE_TYPES: return False elif surface.type_verharding in { @@ -398,12 +772,12 @@ def calculate_distances(self, parameters): surface_water_buffer_dist = max( [parameters.max_afstand_pand_oppwater, parameters.max_afstand_vlak_oppwater] ) - print(f"surface_water_buffer_dist: {surface_water_buffer_dist}") + # print(f"surface_water_buffer_dist: {surface_water_buffer_dist}") # Distance to pipes for surface in self._database.bgt_surfaces: if not surface: - print("surface kapoet") + print("surface invalid") continue surface_geom = surface.geometry().Clone() @@ -423,17 +797,18 @@ def calculate_distances(self, parameters): if ( internal_pipe_type not in distances.keys() ): # Leiding van dit type is nog niet langsgekomen - distances[internal_pipe_type] = pipe_geom.Distance( - surface_geom - ) + distances[internal_pipe_type] = { + "distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"], + } else: - if distances[internal_pipe_type] > pipe_geom.Distance( - surface_geom - ): - distances[internal_pipe_type] = pipe_geom.Distance( - surface_geom - ) - + if distances[internal_pipe_type][ + "distance" + ] > pipe_geom.Distance(surface_geom): + distances[internal_pipe_type] = { + "distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"], + } # Distance to water surface if surface.surface_type != SURFACE_TYPE_WATERDEEL: surface_geom_buffer_surface_water = surface_geom.Buffer( @@ -457,8 +832,10 @@ def calculate_distances(self, parameters): min_water_distance = dist_to_this_water_surface # add to dict - distances[OPEN_WATER] = min_water_distance - + distances[OPEN_WATER] = { + "distance": min_water_distance, + "leidingcode": None, + } # Distance to kolk if self.parameters.gebruik_kolken: if surface.surface_type in KOLK_CONNECTABLE_SURFACE_TYPES: @@ -478,19 +855,25 @@ def calculate_distances(self, parameters): min_kolk_distance = dist_to_this_kolk # add to dict - distances[KOLK] = min_kolk_distance - + distances[KOLK] = { + "distance": min_kolk_distance, + "leidingcode": None, + } # Write distances to surfaces layer for distance_type in DISTANCE_TYPES: if distance_type in distances: - if distances[distance_type] == PSEUDO_INFINITE: - distances[distance_type] = None - surface["distance_" + distance_type] = distances[distance_type] + if distances[distance_type]["distance"] == PSEUDO_INFINITE: + distances[distance_type]["distance"] = None + surface["distance_" + distance_type] = distances[distance_type][ + "distance" + ] + surface["code_" + distance_type] = distances[distance_type][ + "leidingcode" + ] self._database.bgt_surfaces.SetFeature(surface) surface = None - self._database.bgt_surfaces.ResetReading() self._database.bgt_surfaces.SetSpatialFilter(None) @@ -529,6 +912,10 @@ def calculate_runoff_targets(self): feature.SetField( RESULT_TABLE_FIELD_GRAAD_VERHARDING, surface.graad_verharding ) + feature.SetField("surface_type", surface.surface_type) + feature.SetField("bgt_fysiek_voorkomen", surface.bgt_fysiek_voorkomen) + feature.SetField("build_year", surface.build_year) + feature.SetField(RESULT_TABLE_FIELD_WIJZIGING, 0) # feature.SetField(RESULT_TABLE_FIELD_HELLINGSTYPE, val) # not yet implemented # feature.SetField(RESULT_TABLE_FIELD_HELLINGSPERCENTAGE, val) # not yet implemented # feature.SetField(RESULT_TABLE_FIELD_BERGING_DAK, val) # not yet implemented @@ -536,9 +923,644 @@ def calculate_runoff_targets(self): # feature.SetField(RESULT_TABLE_FIELD_LEIDINGCODE, val) # not yet implemented for tt in TARGET_TYPES: feature.SetField(tt, afwatering[tt]) + if self.parameters.leidingcodes_koppelen: + if feature.GetField(TARGET_TYPE_GEMENGD_RIOOL) > 0: + feature.SetField( + RESULT_TABLE_FIELD_CODE_GEMENGD, + surface["code_" + INTERNAL_PIPE_TYPE_GEMENGD_RIOOL], + ) + if ( + feature.GetField(TARGET_TYPE_HEMELWATERRIOOL) > 0 + or feature.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL) > 0 + ): + if feature.GetField(TARGET_TYPE_HEMELWATERRIOOL) > feature.GetField( + TARGET_TYPE_VGS_HEMELWATERRIOOL + ): + feature.SetField( + RESULT_TABLE_FIELD_CODE_HWA, + surface["code_" + INTERNAL_PIPE_TYPE_HEMELWATERRIOOL], + ) + else: + feature.SetField( + RESULT_TABLE_FIELD_CODE_HWA, + surface["code_" + INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL], + ) + if feature.GetField(TARGET_TYPE_VUILWATERRIOOL) > 0: + feature.SetField( + RESULT_TABLE_FIELD_CODE_DWA, + surface["code_" + INTERNAL_PIPE_TYPE_VUILWATERRIOOL], + ) + if feature.GetField(TARGET_TYPE_INFILTRATIEVOORZIENING) > 0: + feature.SetField( + RESULT_TABLE_FIELD_CODE_INFILTRATIE, + surface["code_" + INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING], + ) + result_table.CreateFeature(feature) feature = None + def get_nearest_pipe_code(self, feature): + surface_geom = feature.geometry().Clone() + surface_geom_buffer_afwateringsvoorziening = surface_geom.Buffer( + self.parameters.max_afstand_vlak_afwateringsvoorziening + ) + + distances = {} + for pipe_id in self._database.pipes_idx.intersection( + surface_geom_buffer_afwateringsvoorziening.GetEnvelope() + ): + pipe = self._database.pipes.GetFeature(pipe_id) + pipe_geom = pipe.geometry().Clone() + if pipe_geom.Intersects(surface_geom_buffer_afwateringsvoorziening): + internal_pipe_type = pipe[INTERNAL_PIPE_TYPE_FIELD] + if internal_pipe_type != INTERNAL_PIPE_TYPE_IGNORE: + if ( + internal_pipe_type not in distances.keys() + ): # Leiding van dit type is nog niet langsgekomen + distances[internal_pipe_type] = { + "distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"], + } + else: + if distances[internal_pipe_type][ + "distance" + ] > pipe_geom.Distance(surface_geom): + distances[internal_pipe_type] = { + "distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"], + } + pipe = None + return distances + + def overwrite_by_manual_edits(self): + result_table = self._database.result_table + manual_results_prev = self._database.mem_database.GetLayerByName( + RESULT_TABLE_NAME_PREV + ) + bgt_surfaces = self._database.bgt_surfaces + + if manual_results_prev is None: + print("No manual edits to keep.") + return + + records_to_delete = [] + features_to_update = [] + + # Iterate over each feature in manual_results_prev + for count, prev_feat in enumerate(manual_results_prev, 1): + if self.parameters.leidingcodes_koppelen: + distances = self.get_nearest_pipe_code(prev_feat) + + # Assign the correct code based on the type of the pipe + if prev_feat.GetField(TARGET_TYPE_GEMENGD_RIOOL) > 0: + if INTERNAL_PIPE_TYPE_GEMENGD_RIOOL in distances: + prev_feat.SetField( + RESULT_TABLE_FIELD_CODE_GEMENGD, + distances[INTERNAL_PIPE_TYPE_GEMENGD_RIOOL]["leidingcode"], + ) + else: + print( + f"No mixed sewerage pipe found for prev_feat {prev_feat.GetFID()}" + ) + + elif ( + prev_feat.GetField(TARGET_TYPE_HEMELWATERRIOOL) > 0 + or prev_feat.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL) > 0 + ): + if prev_feat.GetField( + TARGET_TYPE_HEMELWATERRIOOL + ) > prev_feat.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL): + if INTERNAL_PIPE_TYPE_HEMELWATERRIOOL in distances: + prev_feat.SetField( + RESULT_TABLE_FIELD_CODE_HWA, + distances[INTERNAL_PIPE_TYPE_HEMELWATERRIOOL][ + "leidingcode" + ], + ) + else: + print( + f"No rainwater pipe found for prev_feat {prev_feat.GetFID()}" + ) + elif INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL in distances: + prev_feat.SetField( + RESULT_TABLE_FIELD_CODE_HWA, + distances[INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL][ + "leidingcode" + ], + ) + else: + print( + f"No VGS rainwater pipe found for prev_feat {prev_feat.GetFID()}" + ) + + elif prev_feat.GetField(TARGET_TYPE_VUILWATERRIOOL) > 0: + if INTERNAL_PIPE_TYPE_VUILWATERRIOOL in distances: + prev_feat.SetField( + RESULT_TABLE_FIELD_CODE_DWA, + distances[INTERNAL_PIPE_TYPE_VUILWATERRIOOL]["leidingcode"], + ) + else: + print( + f"No waste water pipe found for prev_feat {prev_feat.GetFID()}" + ) + + elif prev_feat.GetField(TARGET_TYPE_INFILTRATIEVOORZIENING) > 0: + if INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING in distances: + prev_feat.SetField( + RESULT_TABLE_FIELD_CODE_INFILTRATIE, + distances[INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING][ + "leidingcode" + ], + ) + else: + print( + f"No infiltration pipe found for prev_feat {prev_feat.GetFID()}" + ) + + # Collect the features for batch processing + features_to_update.append(prev_feat) + + # Mark records in result_table for deletion based on matching key field + key_value = prev_feat.GetField("bgt_identificatie") + result_table.SetAttributeFilter(f"bgt_identificatie = '{key_value}'") + for result_feat in result_table: + records_to_delete.append(result_feat.GetFID()) + result_table.SetAttributeFilter(None) # Clear the filter for next iteration + + # Batch delete records + if records_to_delete: + for fid in records_to_delete: + result_table.DeleteFeature(fid) + + # Batch update manual_results_prev in result_table + if features_to_update: + for feat in features_to_update: + manual_results_prev.SetFeature(feat) + + # Copy features from manual_results_prev to result_table + self._database.copy_features_with_matching_fields( + manual_results_prev, result_table, "id" + ) + + # Sync the changes to disk + result_table.SyncToDisk() + + # Check if the manual edits overlap with new BGT feature (for more than 50% of its own surface) + for prev_feat in manual_results_prev: + # intersecting_fids = [] + overlapping_area = 0 + # calculate area of prev_feat + prev_feat_geom = prev_feat.GetGeometryRef() + area_prev_feat = prev_feat_geom.GetArea() + for surface in bgt_surfaces: + surface_geom = surface.GetGeometryRef() + if surface_geom.Intersects(prev_feat_geom) and ( + prev_feat["bgt_identificatie"] != surface["identificatie_lokaalid"] + ): + intersection = surface_geom.Intersection(prev_feat_geom) + if intersection: + overlapping_area += intersection.GetArea() + + if area_prev_feat > 0 and (overlapping_area / area_prev_feat > 0.5): + self.new_BGT_surfaces.append(prev_feat) + + # Check if the manual edits have an eindregistratie (and are therefor old BGT features) + surfaces_ids = [] + for surface in bgt_surfaces: + surfaces_ids.append(surface.GetField("identificatie_lokaalid")) + + if prev_feat["bgt_identificatie"] not in surfaces_ids: + self.outdated_changed_surfaces.append(prev_feat) + + def intersect_inf_pavement_green_roofs(self): + result_table = self._database.result_table + points_layer = self._database.mem_database.GetLayerByName( + INF_PAVEMENT_TABLE_NAME_PREV + ) + + # Iterate over features in the points_layer + if points_layer is None: + print("No infiltrating pavement or green roofs specified.") + else: + for point_feature in points_layer: + point_geom = ( + point_feature.GetGeometryRef() + ) # Get the geometry of the current point feature + + # Get the value of the 'type' field for the current point feature + feature_type = point_feature.GetField("type") + + # Iterate over features in the result_table + for result_feature in result_table: + result_geom = ( + result_feature.GetGeometryRef() + ) # Get the geometry of the current result feature + + # Check if the geometries intersect + if result_geom.Intersects(point_geom): + # Update the 'surface_type' field based on the 'type' field from the point layer + if feature_type == "Waterpasserende verharding": + result_feature.SetField( + RESULT_TABLE_FIELD_TYPE_VERHARDING, + VERHARDINGSTYPE_WATERPASSEREND_VERHARD, + ) + elif feature_type == "Groen dak": + result_feature.SetField( + RESULT_TABLE_FIELD_TYPE_VERHARDING, + VERHARDINGSTYPE_GROEN_DAK, + ) + + # Update the feature in the result table + result_table.SetFeature(result_feature) + self.inf_pavements_green_roof_surfaces.append(result_feature) + + def calculate_statistics(self, stats_path): + dest_layer = self._database.statistics_table + stats_abspath = os.path.abspath(stats_path) + it_layer = self._database.result_table + + if not os.path.isfile(stats_abspath): + raise FileNotFoundError( + f"Shapefile met gebieden voor statistieken niet gevonden: {stats_abspath}" + ) + + stats_ds = ogr.Open(stats_abspath) + stats_layer = stats_ds.GetLayer() + gebied_id = 0 + field_prefix = ["opp", "perc"] + field_middle = [ + "_totaal", + "_gemengd", + "_hwa", + "_vgs", + "_dwa", + "_infiltratievoorziening", + "_open_water", + "_maaiveld", + ] + field_suffix = ["", "_dak", "_gesl_verh", "_open_verh", "_onverhard"] + field_suffix_verharding = [ + "_dak", + "_gesl_verh", + "_open_verh", + "_onverhard", + "_groen_dak", + "_waterpas_verh", + "_water", + ] + + for feature in stats_layer: + gebied_id += 1 + geom = feature.GetGeometryRef() + new_feature = ogr.Feature(dest_layer.GetLayerDefn()) + new_feature.SetGeometry(geom.Clone()) + new_feature.SetField(STATISTICS_TABLE_FIELD_ID, gebied_id) + + intersecting_it_features = self.find_indices_intersecting_features( + it_layer, new_feature + ) + + intersection_areas = {} + + for prefix in field_prefix: + for middle in field_middle: + middle_key = middle[1:] + if prefix == "opp": + for suffix in field_suffix: + field_name = ( + "STATISTICS_TABLE_FIELD_" + prefix + middle + suffix + ).upper() + if field_name not in intersection_areas: + intersection_areas[field_name] = ( + self.calculate_intersection_area( + intersecting_it_features, + new_feature, + middle_key, + suffix[1:], + ) + ) + new_feature.SetField( + globals()[field_name], intersection_areas[field_name] + ) + else: + for suffix in field_suffix: + if middle_key != "totaal": + field_name = ( + "STATISTICS_TABLE_FIELD_" + prefix + middle + suffix + ).upper() + field_name_opp = field_name.replace("PERC", "OPP") + field_name_tot = field_name_opp.replace( + middle_key.upper(), "TOTAAL" + ) + if new_feature[globals()[field_name_tot]] > 0: + perc_value = round( + ( + 100 + * new_feature[globals()[field_name_opp]] + / new_feature[globals()[field_name_tot]] + ), + 2, + ) + new_feature.SetField( + globals()[field_name], perc_value + ) + + for prefix in field_prefix: + for suffix_verharding in field_suffix_verharding: + field_name = ( + "STATISTICS_TABLE_FIELD_" + prefix + suffix_verharding + ).upper() + if prefix == "opp": + if field_name not in intersection_areas: + intersection_areas[field_name] = ( + self.calculate_intersection_area( + intersecting_it_features, + new_feature, + "verharding", + suffix_verharding[1:], + ) + ) + new_feature.SetField( + globals()[field_name], intersection_areas[field_name] + ) + else: + field_name_opp = field_name.replace("PERC", "OPP") + field_name_tot = field_name_opp.replace( + suffix_verharding[1:].upper(), "TOTAAL" + ) + if new_feature[globals()[field_name_tot]] > 0: + perc_value = round( + ( + 100 + * new_feature[globals()[field_name_opp]] + / new_feature[globals()[field_name_tot]] + ), + 2, + ) + new_feature.SetField(globals()[field_name], perc_value) + + dest_layer.CreateFeature(new_feature) + new_feature = None + + stats_ds = None + it_layer = None + + def find_indices_intersecting_features(self, layer, stats_feature): + """ + Returns a list of feature IDs (FIDs) of all features in 'layer' that intersect with 'stats_feature'. + + Parameters: + layer (ogr.Layer): The layer to check for intersecting features. + stats_feature (ogr.Feature): The feature to check intersections against. + + Returns: + List[int]: List of feature IDs (FIDs) in 'layer' that intersect with 'stats_feature'. + """ + intersecting_fids = [] + + # Get the geometry of the stats_feature to check intersections + stats_geom = stats_feature.GetGeometryRef() + + # Loop through all features in the layer + for feature in layer: + feature_geom = feature.GetGeometryRef() + + # Check if the geometries intersect + if feature_geom and stats_geom and feature_geom.Intersects(stats_geom): + intersecting_fids.append(feature.GetFID()) + + # Reset the reading for the layer to allow further use + layer.ResetReading() + + return intersecting_fids + + def calculate_intersection_area( + self, intersecting_it_features, stats_feature, stat_type, type_verharding + ): + it_layer = self._database.result_table + area_totals = { + "totaal": 0, + "gemengd": 0, + "hwa": 0, + "vgs": 0, + "dwa": 0, + "infiltratievoorziening": 0, + "open_water": 0, + "maaiveld": 0, + "verharding": 0, + } + + stats_geom = stats_feature.GetGeometryRef() + verhardingstype_map = { + "gesl_verh": VERHARDINGSTYPE_GESLOTEN_VERHARD, + "open_verh": VERHARDINGSTYPE_OPEN_VERHARD, + "groen_dak": VERHARDINGSTYPE_GROEN_DAK, + "waterpas_verh": VERHARDINGSTYPE_WATERPASSEREND_VERHARD, + } + verhardingstype = verhardingstype_map.get(type_verharding, type_verharding) + + if not stats_geom.IsValid(): + stats_geom = stats_geom.MakeValid() + + for fid in intersecting_it_features: + it_feature = it_layer.GetFeature(fid) + it_geom = it_feature.GetGeometryRef() + + if not it_geom.IsValid(): + it_geom = it_geom.MakeValid() + + if ( + it_feature[RESULT_TABLE_FIELD_TYPE_VERHARDING] == verhardingstype + or verhardingstype == "" + ): + if ( + it_geom + and stats_geom + and it_geom.IsValid() + and stats_geom.IsValid() + and stats_geom.Intersects(it_geom) + ): + try: + intersection_geom = stats_geom.Intersection(it_geom) + intersection_area = intersection_geom.GetArea() + area_totals["totaal"] += intersection_area + area_totals["verharding"] += intersection_area + area_totals["gemengd"] += ( + intersection_area + * it_feature[TARGET_TYPE_GEMENGD_RIOOL] + / 100 + ) + area_totals["hwa"] += ( + intersection_area + * it_feature[TARGET_TYPE_HEMELWATERRIOOL] + / 100 + ) + area_totals["vgs"] += ( + intersection_area + * it_feature[TARGET_TYPE_VGS_HEMELWATERRIOOL] + / 100 + ) + area_totals["dwa"] += ( + intersection_area + * it_feature[TARGET_TYPE_VUILWATERRIOOL] + / 100 + ) + area_totals["infiltratievoorziening"] += ( + intersection_area + * it_feature[TARGET_TYPE_INFILTRATIEVOORZIENING] + / 100 + ) + area_totals["open_water"] += ( + intersection_area * it_feature[TARGET_TYPE_OPEN_WATER] / 100 + ) + area_totals["maaiveld"] += ( + intersection_area * it_feature[TARGET_TYPE_MAAIVELD] / 100 + ) + except Exception as e: + print(f"Error calculating intersection: {e}") + continue + + return round(area_totals[stat_type] / 10000, 2) + + def generate_warnings(self): + checks_table = self._database.checks_table + it_layer = self._database.result_table + feature_defn = checks_table.GetLayerDefn() + # print(feature_defn) + fid = 0 + + # Check 1: large areas + warning_large_area = f"Dit BGT vlak is groter dan {CHECKS_LARGE_AREA} m2. De kans is groot dat dit vlak aangesloten is op meerdere stelseltypen. Controleer en corrigeer dit wanneer nodig." + + for it_feature in it_layer: + # Get the geometry of the feature and calculate area + geom = it_feature.GetGeometryRef() + area = geom.GetArea() + if area > CHECKS_LARGE_AREA: # value in m2 + fid += 1 + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID, fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE, 1) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE, "4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN, "") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE, str(round(area, 2))) + check_feature.SetField( + CHECKS_TABLE_FIELD_DESCRIPTION, warning_large_area + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + # Check 2: buildings that are in the BGT but not in the BAG + warning_bgt_bag_mismatch = "Dit pand ontbreekt in de BAG. Er is daarom geen bouwjaar toegewezen aan het pand." + + for building in self._database.non_matching_buildings: + fid += 1 + geom = building.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID, fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Info") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE, 2) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE, "4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN, "BGT Identificatie") + check_feature.SetField( + CHECKS_TABLE_FIELD_VALUE, building["identificatie_lokaalid"] + ) # identificatiebagpnd + check_feature.SetField( + CHECKS_TABLE_FIELD_DESCRIPTION, warning_bgt_bag_mismatch + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + # Check 3: surface which intersect with green roofs or infiltrating pavement + warning_infiltrating_surfaces = "Dit vlak is waterpasserende verharding of een groen dak. Alleen het type verharding is daarop aangepast. Ga na of er nog meer aangepast moet worden." + + for surface in self.inf_pavements_green_roof_surfaces: + fid += 1 + geom = surface.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID, fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Info") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE, 3) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE, "4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN, "Type verharding") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE, surface["type_verharding"]) + check_feature.SetField( + CHECKS_TABLE_FIELD_DESCRIPTION, warning_infiltrating_surfaces + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + # Check 4: relatieve hoogteligging + warning_relatieve_hoogteligging = "Dit vlak overlapt met een ander BGT vlak en heeft een hogere relatieve hoogteligging. Zorg dat er geen overlap is tussen de vlakken en dat alleen de vlakken met hoogste relatieve hoogteligging in de dataset zitten." + + for surface in self.relative_hoogteligging_surfaces: + fid += 1 + geom = surface.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID, fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE, 4) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE, "5_BGT_oppervlakken") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN, "BGT Identificatie") + check_feature.SetField( + CHECKS_TABLE_FIELD_VALUE, surface["identificatie_lokaalid"] + ) + check_feature.SetField( + CHECKS_TABLE_FIELD_DESCRIPTION, warning_relatieve_hoogteligging + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + # Check 5: nieuwe vlakken in de BGT, met nieuwe IDs, dan kunnen deze overlappen met de handmatige wijzigingen. + warning_new_BGT_surfaces = "Dit handmatige gewijzigde vlak heeft meer dan 50% overlap met een nieuw BGT vlak. Controleer of dit vlak behouden moet blijven." + for it_feature in self.new_BGT_surfaces: + fid += 1 + geom = it_feature.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID, fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE, 5) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE, "4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN, "BGT identificatie") + check_feature.SetField( + CHECKS_TABLE_FIELD_VALUE, it_feature["bgt_identificatie"] + ) + check_feature.SetField( + CHECKS_TABLE_FIELD_DESCRIPTION, warning_new_BGT_surfaces + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + # Check 6: handmatig gewijzigd BGT vlak heeft een eindregistratie gekregen + warning_outdated_changed_surfaces = "Dit handmatig gewijzigde vlak zit niet meer in de BGT data. Controleer of het nog steeds bestaat." + for it_feature in self.outdated_changed_surfaces: + fid += 1 + geom = it_feature.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID, fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE, 6) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE, "4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN, "BGT identificatie") + check_feature.SetField( + CHECKS_TABLE_FIELD_VALUE, it_feature["bgt_identificatie"] + ) + check_feature.SetField( + CHECKS_TABLE_FIELD_DESCRIPTION, warning_outdated_changed_surfaces + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + checks_table = None + it_layer = None + class Database: def __init__(self, epsg=28992): @@ -553,6 +1575,16 @@ def __init__(self, epsg=28992): self.create_table( table_name=RESULT_TABLE_NAME, table_schema=RESULT_TABLE_SCHEMA ) + self.create_table( + table_name=SETTINGS_TABLE_NAME, table_schema=SETTINGS_TABLE_SCHEMA + ) + self.create_table( + table_name=STATISTICS_TABLE_NAME, table_schema=STATISTICS_TABLE_SCHEMA + ) + self.create_table( + table_name=CHECKS_TABLE_NAME, table_schema=CHECKS_TABLE_SCHEMA + ) + self.non_matching_buildings = [] @property def result_table(self): @@ -561,6 +1593,27 @@ def result_table(self): """ return self.mem_database.GetLayerByName(RESULT_TABLE_NAME) + @property + def settings_table(self): + """Get reference to the Settings layer + :rtype ogr.Layer + """ + return self.mem_database.GetLayerByName(SETTINGS_TABLE_NAME) + + @property + def statistics_table(self): + """Get reference to the Settings layer + :rtype ogr.Layer + """ + return self.mem_database.GetLayerByName(STATISTICS_TABLE_NAME) + + @property + def checks_table(self): + """Get reference to the Settings layer + :rtype ogr.Layer + """ + return self.mem_database.GetLayerByName(CHECKS_TABLE_NAME) + @property def bgt_surfaces(self): """Get reference to BGT Surface layer @@ -604,6 +1657,91 @@ def create_table(self, table_name, table_schema): lyr = None + def import_it_results(self, file_path): + prev_gpkg_abspath = os.path.abspath(file_path) + if not os.path.isfile(prev_gpkg_abspath): + raise FileNotFoundError( + "Resultaten GeoPackage vorige run niet gevonden: {}".format( + prev_gpkg_abspath + ) + ) + it_ds = ogr.Open(file_path) + # TODO more thorough checks of validity of input geopackage + try: + self.mem_database.CopyLayer( + it_ds.GetLayerByName("4_BGT_inlooptabel"), RESULT_TABLE_NAME_PREV + ) + except Exception: + # TODO more specific exception + raise FileInputError( + "Ongeldige input: {} is geen geldige Resultaten GeoPackage".format( + prev_gpkg_abspath + ) + ) + + def clean_it_results(self): + """ + Update the results layer from the previous simulation such that only the manual changes are kept. + """ + layer = self.mem_database.GetLayerByName(RESULT_TABLE_NAME_PREV) + if layer is None: + raise DatabaseOperationError + + delete_fids = [] + for it_feat in layer: + if not it_feat["wijziging"]: + delete_fids.append(it_feat.GetFID()) + + for fid in delete_fids: + layer.DeleteFeature(fid) + + layer = None + + def import_settings_results(self, file_path): + prev_gpkg_abspath = os.path.abspath(file_path) + if not os.path.isfile(prev_gpkg_abspath): + raise FileNotFoundError( + "Resultaten GeoPackage vorige run niet gevonden: {}".format( + prev_gpkg_abspath + ) + ) + it_ds = ogr.Open(file_path) + # TODO more thorough checks of validity of input geopackage + try: + self.mem_database.CopyLayer( + it_ds.GetLayerByName("7_Rekeninstellingen"), SETTINGS_TABLE_NAME_PREV + ) + except Exception: + # TODO more specific exception + raise FileInputError( + "Ongeldige input: {} is geen geldige Resultaten GeoPackage".format( + prev_gpkg_abspath + ) + ) + + def import_inf_pavement_green_roofs(self, file_path): + prev_gpkg_abspath = os.path.abspath(file_path) + if not os.path.isfile(prev_gpkg_abspath): + raise FileNotFoundError( + "Resultaten GeoPackage vorige run niet gevonden: {}".format( + prev_gpkg_abspath + ) + ) + it_ds = ogr.Open(file_path) + # TODO more thorough checks of validity of input geopackage/shapefile + try: + self.mem_database.CopyLayer( + it_ds.GetLayerByName("1_Waterpasserende_verharding_en_groene_daken"), + INF_PAVEMENT_TABLE_NAME_PREV, + ) + except Exception: + # TODO more specific exception + raise FileInputError( + "Ongeldige input: {} is geen geldige Resultaten GeoPackage".format( + prev_gpkg_abspath + ) + ) + def import_pipes(self, file_path): """ Copy the required contents of the GWSW GeoPackage file to self.mem_database @@ -629,7 +1767,7 @@ def import_pipes(self, file_path): ) ) - def import_surfaces_raw(self, file_path): + def import_surfaces_raw(self, file_path, extent_wkt): """ Copy the required contents of the BGT zip file 'as is' to self.mem_database :param file_path: @@ -667,6 +1805,10 @@ def import_surfaces_raw(self, file_path): continue # TODO Warning else: nr_layers_with_features += 1 + # Set spatial filter on src_layer to only include features that intersect with the extent + if extent_wkt is not None: + extent_geometry = ogr.CreateGeometryFromWkt(extent_wkt) + src_layer.SetSpatialFilter(extent_geometry) self.mem_database.CopyLayer(src_layer=src_layer, new_name=stype) print( f"raw import of {stype} layer has {self.mem_database.GetLayerByName(stype).GetFeatureCount()} features" @@ -678,10 +1820,10 @@ def import_surfaces_raw(self, file_path): except FileInputError: raise except Exception: + # self.import_surfaces_raw_alternative(file_path) raise FileInputError(f"Probleem met laag {stype}.gml in BGT zip file") def import_kolken(self, file_path): - """ Copy point features from a ogr layer @@ -711,7 +1853,7 @@ def add_index_to_inputs(self, pipes=True, bgt_surfaces=True, kolken=True): def remove_input_features_outside_clip_extent(self, extent_wkt): extent_geometry = ogr.CreateGeometryFromWkt(extent_wkt) - + pipes = self.pipes bgt_surfaces = self.bgt_surfaces @@ -723,7 +1865,7 @@ def remove_input_features_outside_clip_extent(self, extent_wkt): pipe_geom = pipe.geometry() if pipe_geom.Intersects(extent_geometry): intersecting_pipes.append(pipe_fid) - + for surface in bgt_surfaces: surface_fid = surface.GetFID() surface_geom = surface.geometry() @@ -752,12 +1894,20 @@ def clean_surfaces(self): """ for surface_type in ALL_USED_SURFACE_TYPES: layer = self.mem_database.GetLayerByName(surface_type) - if layer is None: # this happens if this particular layer in the bgt input has no features + if ( + layer is None + ): # this happens if this particular layer in the bgt input has no features continue layer.ResetReading() delete_fids = [] for feature in layer: geom = feature.GetGeometryRef() + if geom is None: + # If no geometry is found, skip this feature + print( + f"Warning: Feature {feature.GetFID()} in layer {surface_type} has no geometry. Skipping." + ) + continue geom_type = geom.GetGeometryType() if geom_type == ogr.wkbPolygon: pass @@ -774,12 +1924,12 @@ def clean_surfaces(self): # print('Deleting feature {} because it is a Linestring'.format(f.GetFID())) delete_fids.append(feature.GetFID()) else: - print( - "Warning: Fixing feature {fid} in {stype} failed! No procedure defined to clean up geometry " - "type {geom_type}. Continuing anyway.".format( - fid=feature.GetFID(), stype=surface_type, geom_type=str(geom_type) - ) - ) + # print( + # "Warning: Fixing feature {fid} in {stype} failed! No procedure defined to clean up geometry " + # "type {geom_type}. Continuing anyway.".format( + # fid=feature.GetFID(), stype=surface_type, geom_type=str(geom_type) + # ) + # ) continue for fid in delete_fids: layer.DeleteFeature(fid) @@ -923,6 +2073,9 @@ def merge_surfaces(self): if stype == SURFACE_TYPE_PAND: new_feature["identificatiebagpnd"] = feature["identificatieBAGPND"] + new_feature.SetField( + "relatieve_hoogteligging", feature["relatieveHoogteligging"] + ) target_geometry = ogr.ForceToPolygon(feature.geometry()) target_geometry.AssignSpatialReference(self.srs) @@ -936,6 +2089,58 @@ def merge_surfaces(self): previous_fcount = dest_layer.GetFeatureCount() dest_layer = None + def identify_overlapping_surfaces(self): + """Finds all overlapping surfaces and saves the surfaces with the highest relatieve hoogteligging""" + layer = self.mem_database.GetLayerByName(SURFACES_TABLE_NAME) + if layer is None: + raise DatabaseOperationError + + # Check if the layer has any features + if layer.GetFeatureCount() == 0: + return + + # Create a list to store the features with the highest hoogteligging + highest_surfaces = [] + + # Loop through all surfaces in the layer + for feature in layer: + geom1 = ( + feature.GetGeometryRef() + ) # Get the geometry of the current feature (surface) + hoogteligging1 = feature.GetField( + "relatieve_hoogteligging" + ) # Get the "hoogteligging" field + + # Loop through all other surfaces in the layer to check for overlaps + layer.ResetReading() # Reset the reading to iterate over all features again + for other_feature in layer: + if other_feature.GetFID() == feature.GetFID(): + # Skip comparing the surface with itself + continue + + geom2 = ( + other_feature.GetGeometryRef() + ) # Get the geometry of the other feature + if geom1.Intersects( + geom2 + ): # Check if the geometries intersect (overlap) + hoogteligging2 = other_feature.GetField( + "relatieve_hoogteligging" + ) # Get the hoogteligging of the other feature + # Compare the two overlapping features and keep the one with the higher hoogteligging + if hoogteligging1 > hoogteligging2: + if feature not in highest_surfaces: + highest_surfaces.append( + feature + ) # Add the feature if it's not already in the list + elif hoogteligging1 < hoogteligging2: + if other_feature not in highest_surfaces: + highest_surfaces.append( + other_feature + ) # Add the other feature if it's not already in the list + + return highest_surfaces + def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): print("Started add_build_year_to_surface...") @@ -950,9 +2155,13 @@ def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): # create dict from buildings building_dict = {} for building in buildings: - building_dict[building["identificatie"][1:]] = building[field_name] + if building["identificatie"][0] == "0": + building_dict[building["identificatie"][1:]] = building[field_name] + else: + building_dict[building["identificatie"]] = building[field_name] building = None + # List to track bui;ding-surfaces that are in the BGT but not in the BAG for surface in surfaces: if surface["surface_type"] == SURFACE_TYPE_PAND: if surface["identificatiebagpnd"] in building_dict.keys(): @@ -960,6 +2169,8 @@ def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): surface["identificatiebagpnd"] ] surfaces.SetFeature(surface) + else: + self.non_matching_buildings.append(surface) surface = None buildings = None @@ -967,10 +2178,222 @@ def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): print("... done") return - def _write_to_disk(self, file_path): + def copy_features_with_matching_fields( + self, src_layer, dst_layer, primary_key_field + ): + # Get source layer definition + src_defn = src_layer.GetLayerDefn() + + # Get the names of the fields in the destination layer + dst_defn = dst_layer.GetLayerDefn() + dst_field_names = [ + dst_defn.GetFieldDefn(i).GetName() for i in range(dst_defn.GetFieldCount()) + ] + + # Iterate through the features in the source layer + for src_feat in src_layer: + # Create a new feature in the destination layer + dst_feat = ogr.Feature(dst_defn) + + # Copy the fields from the source to the destination if the field names match + for i in range(src_defn.GetFieldCount()): + field_name = src_defn.GetFieldDefn(i).GetName() + if field_name in dst_field_names: + dst_feat.SetField(field_name, src_feat.GetField(i)) + + # Set the primary key manually if needed + if primary_key_field: + dst_feat.SetField(primary_key_field, src_feat.GetFID()) + + # Set the geometry + geom = src_feat.GetGeometryRef() + if geom: + dst_feat.SetGeometry(geom.Clone()) + + # Add the feature to the destination layer + dst_layer.CreateFeature(dst_feat) + + # Destroy the feature to free resources + dst_feat = None + + # Sync the data to disk + dst_layer.SyncToDisk() + + def _save_to_gpkg(self, file_folder, template_gpkg): + print("Preparing template gpkg") + file_name = self.output_name(file_folder) + file_path = os.path.join(file_folder, file_name) + self.copy_and_rename_file(template_gpkg, file_path) + + print("Saving layers to gpkg") + # Initialize layers with common elements + layers = [ + (CHECKS_TABLE_NAME, "2_Te_controleren"), + (PIPES_TABLE_NAME, "3_GWSW_leidingen"), + (RESULT_TABLE_NAME, "4_BGT_inlooptabel"), + (SURFACES_TABLE_NAME, "5_BGT_oppervlakken"), + (STATISTICS_TABLE_NAME, "6_Statistieken"), + (SETTINGS_TABLE_NAME, "7_Rekeninstellingen"), + ] + + # Prepend the additional element if the layer exists + if self.mem_database.GetLayerByName(INF_PAVEMENT_TABLE_NAME_PREV) is not None: + layers.insert( + 0, + ( + INF_PAVEMENT_TABLE_NAME_PREV, + "1_Waterpasserende_verharding_en_groene_daken", + ), + ) + + with self.open_gpkg(file_path) as dst_gpkg: + for db_layer, gpkg_layer in layers: + print(f"Saving {gpkg_layer} layer in gpkg") + self._write_to_disk(dst_gpkg, db_layer, gpkg_layer) + if db_layer == RESULT_TABLE_NAME: + self.track_changes(dst_gpkg) + + print("All layers saved successfully.") + return str(file_path) + + def output_name(self, file_folder): + # Determine max. run_id + max_run_id = -1 + for feature in self.settings_table: + run_id = feature.GetField("run_id") + if run_id > max_run_id: + max_run_id = run_id + + if max_run_id < 1: + max_run_id = 1 + + # Set the initial output name + current_date = datetime.now().strftime("%Y%m%d") + output_name = f"v{max_run_id}_BGT_inlooptabel_{current_date}.gpkg" + file_path = os.path.join(file_folder, output_name) + + # Check if file already exists + if os.path.exists(file_path): + # Append current date and time to the output name + current_time = datetime.now().strftime("%Y%m%d_%H%M%S") + output_name = f"v{max_run_id}_BGT_inlooptabel_{current_time}.gpkg" + + return output_name + + def copy_and_rename_file(self, original_file_path, new_file_path): + """ + Copies a file and renames the copy using only sys and os modules. + + :param original_file_path: Path to the original file. + :param new_file_path: Path where the new file will be saved. + """ + try: + # Read the contents of the original file + with open(original_file_path, "rb") as original_file: + content = original_file.read() + + # Write the contents to the new file + with open(new_file_path, "wb") as new_file: + new_file.write(content) + + print(f"Template gpkg copied to {new_file_path}") + except FileNotFoundError: + print(f"The template {original_file_path} does not exist.") + except PermissionError: + print( + f"Permission denied. Unable to copy the template {original_file_path} to {new_file_path}." + ) + except Exception as e: + print(f"An error occurred when copying the template: {e}") + + def _write_to_disk(self, dst_gpkg, db_layer_name, dst_layer_name): """Copy self.mem_database to file_path""" - self.out_db = GPKG_DRIVER.CopyDataSource(self.mem_database, file_path) - self.out_db = None + # Get the source layer from the memory database + db_layer = self.mem_database.GetLayerByName(db_layer_name) + if db_layer is None: + raise ValueError(f"Layer '{db_layer_name}' not found in memory database.") + + dst_layer = dst_gpkg.GetLayerByName(dst_layer_name) + if dst_layer is None: + raise ValueError( + f"Layer '{dst_layer_name}' not found in destination GeoPackage." + ) + + layer_defn = db_layer.GetLayerDefn() + dst_layer_defn = dst_layer.GetLayerDefn() + + if layer_defn.GetFieldCount() != dst_layer_defn.GetFieldCount(): + print( + f"Warning: Source and destination layers have different field counts: {layer_defn.GetFieldCount()} vs {dst_layer_defn.GetFieldCount()}. Continuing anyway." + ) + + field_mapping = { + dst_layer_defn.GetFieldDefn(i).GetName(): layer_defn.GetFieldIndex( + dst_layer_defn.GetFieldDefn(i).GetName() + ) + for i in range(dst_layer_defn.GetFieldCount()) + } + + # Iterate over features in the source layer and copy them to the destination layer + for feature in db_layer: + dst_feature = ogr.Feature(dst_layer_defn) + for dst_field_name, src_field_index in field_mapping.items(): + if src_field_index != -1: # Ensure the field exists in the source layer + dst_feature.SetField( + dst_field_name, feature.GetField(src_field_index) + ) + else: + print( + f"Warning: Source field '{dst_field_name}' not found in the source layer. Skipping field." + ) + # for dst_field_name, src_field_index in field_mapping.items(): + # dst_feature.SetField(dst_field_name, feature.GetField(src_field_index)) + geom = feature.GetGeometryRef() + if geom: + dst_feature.SetGeometry(geom.Clone()) + dst_layer.CreateFeature(dst_feature) + dst_feature = None + print(f"Layer '{dst_layer_name}' saved successfully.") + + @contextlib.contextmanager + def open_gpkg(self, file_path): + dst_gpkg = GPKG_DRIVER.Open(file_path, 1) + if dst_gpkg is None: + raise ValueError(f"Could not open GeoPackage '{file_path}' for writing.") + try: + yield dst_gpkg + finally: + dst_gpkg = None + + def track_changes(self, dst_gpkg): + """Add SQL triggers to track changes""" + + # SQL statements to create the triggers + sql_time_last_change = """ + CREATE TRIGGER update_laaste_wijziging_on_update AFTER UPDATE + OF bgt_identificatie, type_verharding, graad_verharding, hellingstype, hellingspercentage, type_private_voorziening, berging_private_voorziening, leidingcode_gemengd, leidingcode_hwa, leidingcode_dwa, leidingcode_infiltratie, gemengd_riool, hemelwaterriool, vgs_hemelwaterriool, vuilwaterriool, infiltratievoorziening, open_water, maaiveld + ON "4_BGT_inlooptabel" + FOR EACH ROW + BEGIN + UPDATE "4_BGT_inlooptabel" SET laatste_wijziging = datetime('now', '+1 hour') WHERE id = old.id; + END + """ + + sql_changed_tf = """ + CREATE TRIGGER update_wijziging_on_update AFTER UPDATE + OF bgt_identificatie, type_verharding, graad_verharding, hellingstype, hellingspercentage, type_private_voorziening, berging_private_voorziening, leidingcode_gemengd, leidingcode_hwa, leidingcode_dwa, leidingcode_infiltratie, gemengd_riool, hemelwaterriool, vgs_hemelwaterriool, vuilwaterriool, infiltratievoorziening, open_water, maaiveld + ON "4_BGT_inlooptabel" + FOR EACH ROW + BEGIN + UPDATE "4_BGT_inlooptabel" SET wijziging = 1 WHERE id = old.id; + END + """ + + # Execute the SQL statements + dst_gpkg.ExecuteSQL(sql_time_last_change) + dst_gpkg.ExecuteSQL(sql_changed_tf) + + print("Triggers created successfully.") class Layer(object): diff --git a/ArcGIS_plugin/bgt_inlooptool/core/table_schemas.py b/ArcGIS_plugin/bgt_inlooptool/core/table_schemas.py index a85e49c..71da9b5 100644 --- a/ArcGIS_plugin/bgt_inlooptool/core/table_schemas.py +++ b/ArcGIS_plugin/bgt_inlooptool/core/table_schemas.py @@ -19,9 +19,11 @@ def __init__(self, fields, primary_key, geometry_column, geometry_type): RESULT_TABLE_FIELD_GRAAD_VERHARDING: ogr.OFTReal, "build_year": ogr.OFTInteger, "identificatiebagpnd": ogr.OFTString, + "relatieve_hoogteligging": ogr.OFTInteger, } for dist_type in DISTANCE_TYPES: surfaces_table_fields["distance_" + dist_type] = ogr.OFTReal + surfaces_table_fields["code_" + dist_type] = ogr.OFTString del dist_type SURFACES_TABLE_SCHEMA = TableSchema( @@ -43,18 +45,168 @@ def __init__(self, fields, primary_key, geometry_column, geometry_type): # RESULT_TABLE_FIELD_BERGING_DAK: ogr.OFTReal, RESULT_TABLE_FIELD_TYPE_PRIVATE_VOORZIENING: ogr.OFTString, RESULT_TABLE_FIELD_BERGING_PRIVATE_VOORZIENING: ogr.OFTReal, - RESULT_TABLE_FIELD_CODE_VOORZIENING: ogr.OFTString, - RESULT_TABLE_FIELD_PUTCODE: ogr.OFTString, - RESULT_TABLE_FIELD_LEIDINGCODE: ogr.OFTString, - TARGET_TYPE_GEMENGD_RIOOL: ogr.OFTReal, + RESULT_TABLE_FIELD_CODE_GEMENGD: ogr.OFTString, + RESULT_TABLE_FIELD_CODE_HWA: ogr.OFTString, + RESULT_TABLE_FIELD_CODE_DWA: ogr.OFTString, + RESULT_TABLE_FIELD_CODE_INFILTRATIE: ogr.OFTString, + TARGET_TYPE_GEMENGD_RIOOL: ogr.OFTReal, TARGET_TYPE_HEMELWATERRIOOL: ogr.OFTReal, TARGET_TYPE_VGS_HEMELWATERRIOOL: ogr.OFTReal, TARGET_TYPE_VUILWATERRIOOL: ogr.OFTReal, TARGET_TYPE_INFILTRATIEVOORZIENING: ogr.OFTReal, TARGET_TYPE_OPEN_WATER: ogr.OFTReal, TARGET_TYPE_MAAIVELD: ogr.OFTReal, + "surface_type": ogr.OFTString, + "bgt_fysiek_voorkomen": ogr.OFTString, + "build_year": ogr.OFTInteger, + RESULT_TABLE_FIELD_WIJZIGING: ogr.OFTInteger, }, primary_key="id", geometry_column="geom", geometry_type=ogr.wkbCurvePolygon, ) + + +SETTINGS_TABLE_SCHEMA = TableSchema( + fields={ + #"fid": ogr.OFTInteger, + SETTINGS_TABLE_FIELD_ID: ogr.OFTInteger, + SETTINGS_TABLE_FIELD_TIJD_START: ogr.OFTDateTime, + SETTINGS_TABLE_FIELD_TIJD_EIND: ogr.OFTDateTime, + SETTINGS_TABLE_FIELD_DOWNLOAD_BGT:ogr.OFTInteger, + SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW:ogr.OFTInteger, + SETTINGS_TABLE_FIELD_DOWNLOAD_BAG:ogr.OFTInteger, + SETTINGS_TABLE_FIELD_PAD_BGT: ogr.OFTString, + SETTINGS_TABLE_FIELD_PAD_GWSW: ogr.OFTString, + SETTINGS_TABLE_FIELD_PAD_BAG: ogr.OFTString, + SETTINGS_TABLE_FIELD_PAD_KOLKEN: ogr.OFTString, + SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG: ogr.OFTReal, + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF: ogr.OFTReal, + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND: ogr.OFTReal, + SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS: ogr.OFTInteger, + SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN: ogr.OFTReal, + }, + primary_key="run_id", + geometry_column="", #settings table has no geometry + geometry_type=ogr.wkbNone, +) + +STATISTICS_TABLE_SCHEMA = TableSchema( + fields={ + #"fid": ogr.OFTInteger, + STATISTICS_TABLE_FIELD_ID: ogr.OFTInteger, + STATISTICS_TABLE_FIELD_OPP_TOTAAL: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GROEN_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_WATERPAS_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_WATER:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GROEN_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_WATERPAS_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_WATER:ogr.OFTReal, + }, + primary_key="id", + geometry_column="geom", + geometry_type=ogr.wkbCurvePolygon, +) + +CHECKS_TABLE_SCHEMA = TableSchema( + fields={ + CHECKS_TABLE_FIELD_ID: ogr.OFTInteger, + CHECKS_TABLE_FIELD_LEVEL: ogr.OFTString, + CHECKS_TABLE_FIELD_CODE: ogr.OFTInteger, + CHECKS_TABLE_FIELD_TABLE: ogr.OFTString, + CHECKS_TABLE_FIELD_COLUMN: ogr.OFTString, + CHECKS_TABLE_FIELD_VALUE: ogr.OFTString, + CHECKS_TABLE_FIELD_DESCRIPTION: ogr.OFTString, + }, + primary_key="id", + geometry_column="geom", + geometry_type=ogr.wkbCurvePolygon, +) \ No newline at end of file diff --git a/ArcGIS_plugin/bgt_inlooptool/download_bgt_vlakken.py b/ArcGIS_plugin/bgt_inlooptool/download_bgt_vlakken.py deleted file mode 100644 index aabe160..0000000 --- a/ArcGIS_plugin/bgt_inlooptool/download_bgt_vlakken.py +++ /dev/null @@ -1,147 +0,0 @@ -""" -Script Name: Download de BGT vlakken van PDOK -Description: Download de BGT vlakken van PDOK -Created By: Sjoerd Hoekstra -Date: 29/09/2020 -""" - -import sys -import os -import arcpy - -# Relative imports don't work well in arcgis, therefore paths are appended to sys -bgt_inlooptool_dir = os.path.dirname(__file__) -sys.path.append(bgt_inlooptool_dir) -sys.path.append(os.path.join(bgt_inlooptool_dir, "core")) - -# Set path to Generic modules -from cls_general_use import GeneralUse -from common import BaseTool, parameter, get_wkt_extent -from get_bgt_api_surfaces import get_bgt_api_surfaces - - -class DownloadBGTVlakken(BaseTool): - def __init__(self): - """ - Initialization. - - """ - self.label = "1. Download de BGT vlakken van PDOK" - self.description = """Download de BGT vlakken van PDOK""" - self.canRunInBackground = True - - def getParameterInfo(self): - """return Parameter definitions.""" - """Create your parameters here using the paramater function. - Make sure you leave the enclosing brackets and separate your - parameters using commas. - parameter(displayName, name, datatype, defaultValue=None, parameterType='Required', direction='Input') - """ - - self.parameters = [ - parameter( - displayName="Interesse gebied als polygon", - name="interesse_gebied", - datatype="GPFeatureLayer", - parameterType="Required", - direction="Input", - ), - parameter( - displayName="BGT download als zipfile van PDOK", - name="bgt_zip", - datatype="DEFile", - parameterType="Required", - direction="Output", - ), - ] - return self.parameters - - def updateParameters(self, parameters): - """ - updates a parameter in the interface if specified - """ - if parameters[1].altered: - # TODO pad default naar projectmap - if "." in parameters[1].valueAsText: - parameters[1].value = parameters[1].valueAsText.split(".")[0] + ".zip" - else: - parameters[1].value = parameters[1].valueAsText + ".zip" - - super(DownloadBGTVlakken, self).updateParameters(parameters) - - def updateMessages(self, parameters): - """ - returns messages in the interface the wrong paths are filled in for the different parameters - """ - # Messages interesse gebied - if parameters[0].altered: - desc = arcpy.Describe(parameters[0].valueAsText) - if desc.dataType not in ["FeatureClass", "FeatureLayer", "ShapeFile"]: - parameters[0].setErrorMessage( - "De invoer is niet van het type featureclass/shapefile/gpkg layer!" - ) - else: - if desc.shapeType != "Polygon": - parameters[0].setErrorMessage( - "De featureclass/shapefile/gpkg layer is niet van het type polygoon!" - ) - else: - feature_count = int( - arcpy.management.GetCount(parameters[0].valueAsText).getOutput( - 0 - ) - ) - if feature_count != 1: - parameters[0].setErrorMessage( - "Er is meer of minder dan 1 feature aanwezig of geselecteerd!" - ) - - # Messages output BGT zipfile - if parameters[1].altered: - if os.path.exists(parameters[1].valueAsText): - parameters[1].setWarningMessage( - "Het output bestand bestaat al, kies een nieuwe naam!" - ) - - super(DownloadBGTVlakken, self).updateMessages(parameters) - - def execute(self, parameters, messages): - try: - self.arcgis_com = GeneralUse(sys, arcpy) - self.arcgis_com.StartAnalyse() - self.arcgis_com.AddMessage("Start downloading BGT from PDOK!") - - input_area = parameters[0].valueAsText - bgt_zip = parameters[1].valueAsText - - # get the input extent as wkt from the input_area - extent_wkt = get_wkt_extent(input_area) - get_bgt_api_surfaces(extent_wkt, bgt_zip) - - except Exception: - self.arcgis_com.Traceback() - finally: - self.arcgis_com.AddMessage("Klaar") - return - - -if __name__ == "__main__": - # This is used for debugging. Using this separated structure makes it much - # easier to debug using standard Python development tools. - - try: - tool = DownloadBGTVlakken() - params = tool.getParameterInfo() - - # bag_file - params[ - 0 - ].value = r"C:\Users\hsc\OneDrive - Tauw Group bv\ArcGIS\Projects\bgt_inlooptool\dokkum\ws.gdb\zwolle" - params[ - 1 - ].value = r"C:\Users\hsc\OneDrive - Tauw Group bv\ArcGIS\Projects\bgt_inlooptool\dokkum\nieuwe_plek.zip" - - tool.execute(parameters=params, messages=None) - - except Exception as ex: - print("iets ging fout!") diff --git a/ArcGIS_plugin/bgt_inlooptool/get_bgt_api_surfaces.py b/ArcGIS_plugin/bgt_inlooptool/get_bgt_api_surfaces.py deleted file mode 100644 index bd36fb0..0000000 --- a/ArcGIS_plugin/bgt_inlooptool/get_bgt_api_surfaces.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -@author: Emile.deBadts -""" - -SURFACE_TYPE_PAND = "pand" -SURFACE_TYPE_WEGDEEL = "wegdeel" -SURFACE_TYPE_ONDERSTEUNENDWEGDEEL = "ondersteunendwegdeel" -SURFACE_TYPE_BEGROEIDTERREINDEEL = "begroeidterreindeel" -SURFACE_TYPE_ONBEGROEIDTERREINDEEL = "onbegroeidterreindeel" -SURFACE_TYPE_WATERDEEL = "waterdeel" -SURFACE_TYPE_ONDERSTEUNENDWATERDEEL = "ondersteunendwaterdeel" -SURFACE_TYPE_OVERIGBOUWWERK = "overigbouwwerk" -SURFACE_TYPE_GEBOUWINSTALLATIE = "gebouwinstallatie" -SURFACE_TYPE_OVERBRUGGINGSDEEL = "overbruggingsdeel" - -ALL_USED_SURFACE_TYPES = { - SURFACE_TYPE_PAND, - SURFACE_TYPE_WEGDEEL, - SURFACE_TYPE_ONDERSTEUNENDWEGDEEL, - SURFACE_TYPE_BEGROEIDTERREINDEEL, - SURFACE_TYPE_ONBEGROEIDTERREINDEEL, - SURFACE_TYPE_WATERDEEL, - SURFACE_TYPE_ONDERSTEUNENDWATERDEEL, - SURFACE_TYPE_OVERIGBOUWWERK, - SURFACE_TYPE_GEBOUWINSTALLATIE, - SURFACE_TYPE_OVERBRUGGINGSDEEL, -} - -import requests -import zipfile -import json -import time -import arcpy - - -BGT_API_URL = "https://api.pdok.nl/lv/bgt/download/v1_0/full/custom" - - -def get_bgt_api_surfaces(extent_wkt, output_zip): - """ - Download the bgt surfaces for a given extent from the PDOK API - """ - try: - data = { - "featuretypes": list(ALL_USED_SURFACE_TYPES), - "format": "gmllight", - "geofilter": extent_wkt, - } - headers = {"Content-Type": "application/json"} - - r = requests.post(BGT_API_URL, data=json.dumps(data), headers=headers) - download_id = r.json()["downloadRequestId"] - status_link = BGT_API_URL + "/" + download_id + "/status" - - status = "PENDING" - while status != "COMPLETED": - request = requests.get(status_link) - status = request.json()["status"] - # if request.status_code >= 500: - # # TODO of restricties vanuit Wifi! netwerk! - # message = f"BGT API Server werkt niet zoals verwacht probeer het later nog eens status_code is {request.status_code}" - # arcpy.AddError(message) - # raise ValueError(message) - # elif request.status_code >= 400: - # message = f"Er is iets anders fout gegaan, status_code is {request.status_code}" - # arcpy.AddError(message) - # raise ValueError(message) - time.sleep(5) - - download_url_extract = request.json()["_links"]["download"]["href"] - download_url = "https://api.pdok.nl" + download_url_extract - download_request = requests.get(download_url) - - with open(output_zip, "wb") as f: - f.write(download_request.content) - - except Exception: - import sys - import traceback - - tb = sys.exc_info()[2] - tbinfo = traceback.format_tb(tb)[0] - print("PYTHON ERRORS:\nTraceback info:\n" + tbinfo) - print("############################") - print("Error Info:\n" + str(sys.exc_info()[1])) - print("einde!") - - -if __name__ == "__main__": - - extent_wkt = ( - extent_polygon_wkt - ) = "Polygon ((110870.34528933660476469 455397.70264967781258747, 110927.88217626001278404 454151.07009967073099688, 112143.82838657461979892 454139.56272228603484109, 112093.96308457433769945 455535.79117829399183393, 110870.34528933660476469 455397.70264967781258747))" - output_zip = r"C:\GIS\test_data_inlooptool\test_bgt_download1.zip" - get_bgt_api_surfaces(extent_wkt, output_zip) - - print("Klaar!") diff --git a/ArcGIS_plugin/bgt_inlooptool/helper_functions/__init__.py b/ArcGIS_plugin/bgt_inlooptool/helper_functions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ArcGIS_plugin/bgt_inlooptool/cls_general_use.py b/ArcGIS_plugin/bgt_inlooptool/helper_functions/cls_general_use.py similarity index 97% rename from ArcGIS_plugin/bgt_inlooptool/cls_general_use.py rename to ArcGIS_plugin/bgt_inlooptool/helper_functions/cls_general_use.py index 0a26f22..0b2273f 100644 --- a/ArcGIS_plugin/bgt_inlooptool/cls_general_use.py +++ b/ArcGIS_plugin/bgt_inlooptool/helper_functions/cls_general_use.py @@ -1,4 +1,5 @@ import sys + import arcpy @@ -52,7 +53,7 @@ def AddTimeMessage(self, strMessage, urg=0): strTime = ( "Elapsed time from start " - + str(round(time.perf_counter()- self.startTime)) + + str(round(time.perf_counter() - self.startTime)) + " seconds on " + time.strftime("%H:%M:%S") + "." diff --git a/ArcGIS_plugin/bgt_inlooptool/common.py b/ArcGIS_plugin/bgt_inlooptool/helper_functions/common.py similarity index 94% rename from ArcGIS_plugin/bgt_inlooptool/common.py rename to ArcGIS_plugin/bgt_inlooptool/helper_functions/common.py index 75fc1c9..6048e08 100644 --- a/ArcGIS_plugin/bgt_inlooptool/common.py +++ b/ArcGIS_plugin/bgt_inlooptool/helper_functions/common.py @@ -1,10 +1,12 @@ -import arcpy +import json import os import sys -import json -from cls_general_use import GeneralUse from collections import namedtuple +import arcpy + +from .cls_general_use import GeneralUse + arcgis_com = GeneralUse(sys, arcpy) SPATIAL_REFERENCE_CODE = 28992 # RD_NEW @@ -22,12 +24,21 @@ def layers_to_gdb(input_dataset, output_gdb): arcpy.env.workspace = output_gdb arcpy.env.overwriteOutput = True + desc = arcpy.Describe(input_dataset) + fc_name = os.path.basename(input_dataset).replace(".", "_") - out_dataset = str( - arcpy.FeatureClassToFeatureClass_conversion( - input_dataset, output_gdb, fc_name + if not hasattr( + desc, "featureType" + ): # providing a gpkg table to describe returns an empty describe object + out_dataset = str( + arcpy.conversion.TableToTable(input_dataset, output_gdb, fc_name) + ) + else: + out_dataset = str( + arcpy.FeatureClassToFeatureClass_conversion( + input_dataset, output_gdb, fc_name + ) ) - ) return out_dataset except Exception: diff --git a/ArcGIS_plugin/bgt_inlooptool/helper_functions/constants.py b/ArcGIS_plugin/bgt_inlooptool/helper_functions/constants.py new file mode 100644 index 0000000..5e01f7a --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/helper_functions/constants.py @@ -0,0 +1,18 @@ +from typing import NamedTuple, Union + +import arcpy + +BGT_API_URL = "https://api.pdok.nl/lv/bgt/download/v1_0/full/custom" +BAG_API_URL = "https://service.pdok.nl/lv/bag/wfs/v2_0?service=WFS&version=2.0.0&request=GetFeature&typeName=bag:pand&outputFormat=application/json" +GWSW_API_URL = "https://service.pdok.nl/rioned/beheerstedelijkwater/wfs/v1_0?service=WFS&version=2.0.0&request=GetFeature&typeName=beheerstedelijkwater:BeheerLeiding&outputFormat=application/json" +CBS_GEMEENTES_API_URL = "https://service.pdok.nl/kadaster/bestuurlijkegebieden/wfs/v1_0?service=WFS&version=1.0.0&request=GetFeature&typeName=Gemeentegebied&outputFormat=application/json" + +NOT_FOUND_GEMEENTES = [] # Initialize the list for not found gemeentes (GWSW server) + + +class VisualizeLayer(NamedTuple): + symbology_param: arcpy.Parameter + visualize_field: Union[str, None] + layer_name: str + params_idx: int + has_symbology: bool diff --git a/ArcGIS_plugin/bgt_inlooptool/helper_functions/download_apis.py b/ArcGIS_plugin/bgt_inlooptool/helper_functions/download_apis.py new file mode 100644 index 0000000..a69dd30 --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/helper_functions/download_apis.py @@ -0,0 +1,374 @@ +""" +@author: Emile.deBadts +""" + +SURFACE_TYPE_PAND = "pand" +SURFACE_TYPE_WEGDEEL = "wegdeel" +SURFACE_TYPE_ONDERSTEUNENDWEGDEEL = "ondersteunendwegdeel" +SURFACE_TYPE_BEGROEIDTERREINDEEL = "begroeidterreindeel" +SURFACE_TYPE_ONBEGROEIDTERREINDEEL = "onbegroeidterreindeel" +SURFACE_TYPE_WATERDEEL = "waterdeel" +SURFACE_TYPE_ONDERSTEUNENDWATERDEEL = "ondersteunendwaterdeel" +SURFACE_TYPE_OVERIGBOUWWERK = "overigbouwwerk" +SURFACE_TYPE_GEBOUWINSTALLATIE = "gebouwinstallatie" +SURFACE_TYPE_OVERBRUGGINGSDEEL = "overbruggingsdeel" + +ALL_USED_SURFACE_TYPES = { + SURFACE_TYPE_PAND, + SURFACE_TYPE_WEGDEEL, + SURFACE_TYPE_ONDERSTEUNENDWEGDEEL, + SURFACE_TYPE_BEGROEIDTERREINDEEL, + SURFACE_TYPE_ONBEGROEIDTERREINDEEL, + SURFACE_TYPE_WATERDEEL, + SURFACE_TYPE_ONDERSTEUNENDWATERDEEL, + SURFACE_TYPE_OVERIGBOUWWERK, + SURFACE_TYPE_GEBOUWINSTALLATIE, + SURFACE_TYPE_OVERBRUGGINGSDEEL, +} + +import json +import os +import time + +import arcpy +import requests +from osgeo import ogr, osr + +from .constants import BAG_API_URL, BGT_API_URL, CBS_GEMEENTES_API_URL, NOT_FOUND_GEMEENTES + + +def get_bgt_features(extent_wkt, output_zip): + """ + Download the bgt surfaces for a given extent from the PDOK API + """ + try: + data = { + "featuretypes": list(ALL_USED_SURFACE_TYPES), + "format": "gmllight", + "geofilter": extent_wkt, + } + headers = {"Content-Type": "application/json"} + + r = requests.post(BGT_API_URL, data=json.dumps(data), headers=headers) + download_id = r.json()["downloadRequestId"] + status_link = BGT_API_URL + "/" + download_id + "/status" + + status = "PENDING" + while status != "COMPLETED": + request = requests.get(status_link) + status = request.json()["status"] + arcpy.AddMessage("- BGT download wordt voorbereid. De download wordt zo gestart") + + # if request.status_code >= 500: + # # TODO of restricties vanuit Wifi! netwerk! + # message = f"BGT API Server werkt niet zoals verwacht probeer het later nog eens status_code is {request.status_code}" + # arcpy.AddError(message) + # raise ValueError(message) + # elif request.status_code >= 400: + # message = f"Er is iets anders fout gegaan, status_code is {request.status_code}" + # arcpy.AddError(message) + # raise ValueError(message) + time.sleep(5) + + download_url_extract = request.json()["_links"]["download"]["href"] + download_url = "https://api.pdok.nl" + download_url_extract + download_request = requests.get(download_url, stream=True) + block_size = 1024 * 1000 # = 1mb + total_size = int(download_request.headers.get("content-length", 0)) + processed_bytes = 0 + with open(output_zip, "wb") as f: + for data in download_request.iter_content(block_size): + f.write(data) + processed_bytes += len(data) + arcpy.AddMessage(f"- {int((processed_bytes / total_size) * 100)}% Gedownload") + + except Exception: + import sys + import traceback + + tb = sys.exc_info()[2] + tbinfo = traceback.format_tb(tb)[0] + print("PYTHON ERRORS:\nTraceback info:\n" + tbinfo) + print("############################") + print("Error Info:\n" + str(sys.exc_info()[1])) + print("einde!") + + +def get_gwsw_features(extent_wkt, output_gpkg): + try: + nwt = NetworkTask(CBS_GEMEENTES_API_URL, output_gpkg, extent_wkt, "default_lijn") + nwt.run() + except Exception: + import sys + import traceback + + tb = sys.exc_info()[2] + tbinfo = traceback.format_tb(tb)[0] + print("PYTHON ERRORS:\nTraceback info:\n" + tbinfo) + print("############################") + print("Error Info:\n" + str(sys.exc_info()[1])) + print("einde!") + + +def get_bag_features(extent_wkt, output_gpkg): + try: + nwt = NetworkTask(BAG_API_URL, output_gpkg, extent_wkt, "bag_panden") + nwt.run() + except Exception: + import sys + import traceback + + tb = sys.exc_info()[2] + tbinfo = traceback.format_tb(tb)[0] + print("PYTHON ERRORS:\nTraceback info:\n" + tbinfo) + print("############################") + print("Error Info:\n" + str(sys.exc_info()[1])) + print("einde!") + + +class NetworkTask: + def __init__(self, url, output_gpkg, extent_geometry_wkt, layer_name): + self.url = url + self.output_gpkg = output_gpkg + self.extent_geometry_wkt = extent_geometry_wkt + self.extent_bbox = self.wkt_to_bbox() + self.layer_name = layer_name + self.setProgress(0) + if layer_name != "bag_panden": + self.total_progress = 4 + else: + self.total_progress = 10 + + self.download_progress = 0 + + def setProgress(self, progress): + self.download_progress = progress + arcpy.AddMessage(f"- {progress}% gedownload") + + def progress(self): + """ + Function mock the QGIS progress function. Return the stored progress + + Returns: + int: return the progress + """ + return self.download_progress + + def increase_progress(self): + """ + Increase the progress with 1 unit. This is a percentage of the total progress. + The total progress is the number of steps an analysis has. This is set in the init + """ + self.setProgress(self.progress() + 100 / self.total_progress) + + def run(self): + extent_geometry = ogr.CreateGeometryFromWkt(self.extent_geometry_wkt).Buffer( + -0.5 + ) # Give the extent geometry a negative buffer of 0.5m, so that the intersect function works properly (when equal, no neighbouring geometries are used) + shrunk_extent_geometry_wkt = extent_geometry.ExportToWkt() + shrunk_extent_geometry_coordinates = shrunk_extent_geometry_wkt[ + shrunk_extent_geometry_wkt.find("((") + 2 : shrunk_extent_geometry_wkt.find("))") + ] + bbox = self.wkt_to_bbox() + if self.layer_name != "bag_panden": + # GWSW download: looks for names of municipalities first. Then uses these to download the right data. + self.increase_progress() + all_features = self.fetch_all_features_gwsw(shrunk_extent_geometry_coordinates) + else: + all_features = self.fetch_all_features_bag(bbox) + self.increase_progress() + self.save_features_to_gpkg(all_features, extent_geometry) + return True + + def fetch_all_features_gwsw(self, extent_geometry): + not_all_features_found = True + index = 0 + all_features = [] + + print("Fetching features within extent") + while not_all_features_found: + request_url = self.url + f"&startIndex={index}" + f"&Intersects={extent_geometry}" + response_text = self.load_api_data(request_url, "") + data = json.loads(response_text) + + all_features.extend(data["features"]) + + if len(data["features"]) < 1000: + not_all_features_found = False + else: + index += 1000 + + return all_features + + def fetch_all_features_bag(self, bbox): + not_all_features_found = True + index = 0 + all_features = [] + + print("Fetching features within BBox") + while not_all_features_found: + request_url = self.url + f"&startIndex={index}" + f"&BBOX={bbox}" + response_text = self.load_api_data(request_url, "") + data = json.loads(response_text) + + all_features.extend(data["features"]) + + if len(data["features"]) < 1000: + not_all_features_found = False + else: + index += 1000 + + return all_features + + def load_api_data(self, url, gemeente): + response = requests.get(url) + + if response.status_code == 404: + print(f"Error 404: {gemeente} not found.") + return None + + return response.text + + def save_features_to_gpkg(self, all_features, extent_geometry): + print("Saving features to GeoPackage") + + driver = ogr.GetDriverByName("GPKG") + if os.path.exists(self.output_gpkg): + driver.DeleteDataSource(self.output_gpkg) + datasource = driver.CreateDataSource(self.output_gpkg) + + srs = osr.SpatialReference() + srs.ImportFromEPSG(28992) + + if self.layer_name != "bag_panden": + all_features = self.filter_features_by_extent(all_features, extent_geometry) + all_features = self.fetch_gwsw_data(all_features) + all_features = self.remove_duplicate_gwsw_features(all_features) + self.num_features_per_step = round(len(all_features) / (self.total_progress - 2), 0) + else: + self.num_features_per_step = round(len(all_features) / (self.total_progress - 1), 0) + + layer_out = self.create_layer(datasource, srs) + self.add_features_to_layer(layer_out, all_features, extent_geometry) + datasource = None + + def filter_features_by_extent(self, all_features, extent_geometry): + selection_gemeentes = [] + + for feature in all_features: + geometry_wkt = self.geojson_to_wkt(feature["geometry"]) + geojson_geom = ogr.CreateGeometryFromWkt(geometry_wkt) + if extent_geometry.Intersects(geojson_geom): + selection_gemeentes.append(feature["properties"]["naam"]) + + return selection_gemeentes + + def fetch_gwsw_data(self, selection_gemeentes): + all_features = [] + + for gemeente_name in selection_gemeentes: + gemeente_name = gemeente_name.title().replace(" ", "").replace("-", "") + gemeente_name = gemeente_name[0].upper() + gemeente_name[1:].lower() + not_all_features_found = True + index = 0 + print(f"Extracting data for gemeente {gemeente_name}") + + while not_all_features_found: + request_url = ( + f"https://geodata.gwsw.nl/geoserver/{gemeente_name}-default/wfs/?&request=GetFeature&typeName={gemeente_name}-default:default_lijn&srsName=epsg:28992&OutputFormat=application/json" + + (f"&startIndex={index}" if index > 0 else "") + ) + response_text = self.load_api_data(request_url, gemeente_name) + if response_text is None: + NOT_FOUND_GEMEENTES.append(gemeente_name) + break + + data = json.loads(response_text) + all_features.extend(data["features"]) + + if len(data["features"]) < 1000: + not_all_features_found = False + else: + index += 1000 + + return all_features + + def remove_duplicate_gwsw_features(self, gwsw_features): + seen = set() # Set to keep track of already encountered (uri, name) pairs + unique_features = [] + + for feature in gwsw_features: + uri = feature["properties"].get("uri") # Extract URI + name = feature["properties"].get("naam") # Extract name + + # Check if both 'uri' and 'name' exist and are unique + if uri and name and (uri, name) not in seen: + seen.add((uri, name)) # Mark this (uri, name) as seen + unique_features.append(feature) # Keep the feature + + return unique_features + + def create_layer(self, datasource, srs): + if self.layer_name == "bag_panden": + return datasource.CreateLayer(self.layer_name, geom_type=ogr.wkbPolygon, srs=srs) + else: + return datasource.CreateLayer(self.layer_name, geom_type=ogr.wkbMultiLineString, srs=srs) + + def add_features_to_layer(self, layer_out, all_features, extent_geometry): + if not all_features: + return + + feature_example = all_features[0] + feature_fields = list(feature_example["properties"].keys()) + + for field_name in feature_fields: + field_defn = ogr.FieldDefn(field_name, ogr.OFTString) # Adjust field type as needed + layer_out.CreateField(field_defn) + + layer_defn = layer_out.GetLayerDefn() + + print("Writing features to GeoPackage") + feature_count = 0 + for feature_data in all_features: + feature_count += 1 + if feature_count == self.num_features_per_step: + self.increase_progress() + feature_count = 0 + geometry_wkt = self.geojson_to_wkt(feature_data["geometry"]) + geojson_geom = ogr.CreateGeometryFromWkt(geometry_wkt) + if extent_geometry.Intersects(geojson_geom): + out_feature = ogr.Feature(layer_defn) + geometry = ogr.CreateGeometryFromJson(json.dumps(feature_data["geometry"])) + out_feature.SetGeometry(geometry) + + for field_name, field_value in feature_data["properties"].items(): + field_index = layer_defn.GetFieldIndex(field_name) + if field_index != -1: + out_feature.SetField(field_name, field_value) + layer_out.CreateFeature(out_feature) + out_feature = None + + def wkt_to_bbox(self): + + geom = ogr.CreateGeometryFromWkt(self.extent_geometry_wkt) + env = geom.GetEnvelope() + return "%d,%d,%d,%d" % (env[0], env[2], env[1], env[3]) + + def geojson_to_wkt(self, geojson): + geom = ogr.CreateGeometryFromJson(str(geojson)) + return geom.ExportToWkt() + + +if __name__ == "__main__": + + extent_wkt = "Polygon ((110870.34528933660476469 455397.70264967781258747, 110927.88217626001278404 454151.07009967073099688, 112143.82838657461979892 454139.56272228603484109, 112093.96308457433769945 455535.79117829399183393, 110870.34528933660476469 455397.70264967781258747))" + output_zip = r"C:\Users\vdi\Downloads\test_inlooptool\test_bgt_download1.zip" + output_bag = r"C:\Users\vdi\Downloads\test_inlooptool\bag.gpkg" + output_gwsw = r"C:\Users\vdi\Downloads\test_inlooptool\gwsw.gpkg" + # get_bgt_features(extent_wkt, output_zip) + + # get_bag_features(extent_wkt, output_bag) + + get_gwsw_features(extent_wkt, output_gwsw) + + print("Klaar!") diff --git a/ArcGIS_plugin/bgt_inlooptool/gwsw_lijn.json b/ArcGIS_plugin/bgt_inlooptool/helper_functions/gwsw_lijn.json similarity index 100% rename from ArcGIS_plugin/bgt_inlooptool/gwsw_lijn.json rename to ArcGIS_plugin/bgt_inlooptool/helper_functions/gwsw_lijn.json diff --git a/ArcGIS_plugin/bgt_inlooptool/helper_functions/visualize_layers.py b/ArcGIS_plugin/bgt_inlooptool/helper_functions/visualize_layers.py new file mode 100644 index 0000000..9b697d2 --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/helper_functions/visualize_layers.py @@ -0,0 +1,61 @@ +from typing import Union + +import arcpy + +from .cls_general_use import GeneralUse +from .constants import VisualizeLayer + + +class VisualizeLayers: + def __init__(self, arcgis_project=None) -> None: + + if arcgis_project is None: + self.arcgis_project = arcpy.mp.ArcGISProject("CURRENT") + self.map = self.arcgis_project.activeMap + else: + self.arcgis_project = arcpy.mp.ArcGISProject(arcgis_project) + self.map = self.arcgis_project.listMaps()[0] + + self.arcgis_com = GeneralUse() + + def save(self): + self.arcgis_project.save() + + def add_layer_to_map( + self, + visualize_settings: VisualizeLayer, + ): + """ + Add layers to map with symbology if a symbology layer is specified + """ + try: + # add data to the map + output_layer = self.map.addDataFromPath( + visualize_settings.symbology_param.valueAsText + ) + output_layer.name = visualize_settings.layer_name + return output_layer + except Exception: + self.arcgis_com.Traceback() + + def apply_symbology(self, visualize_settings: VisualizeLayer, added_layer): + """ + Apply the specified layer file to the given layer + """ + try: + # add symbology if it is available + layer_file = arcpy.mp.LayerFile( + visualize_settings.symbology_param.symbology + ) + for layer in layer_file.listLayers(): + sym_layer = layer + break + else: + sym_layer = layer_file + arcpy.ApplySymbologyFromLayer_management(added_layer, sym_layer) + arcpy.SetParameterAsText(visualize_settings.params_idx, added_layer) + # https://support.esri.com/en/bugs/nimbus/QlVHLTAwMDExOTkwNw== + # workaround works when parameter 16 is defined as a layer and as parameterType Derived + + except Exception: + self.arcgis_com.Traceback() diff --git a/ArcGIS_plugin/bgt_inlooptool/layers/controles.lyrx b/ArcGIS_plugin/bgt_inlooptool/layers/controles.lyrx new file mode 100644 index 0000000..7557c21 --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/layers/controles.lyrx @@ -0,0 +1,776 @@ +{ + "type": "CIMLayerDocument", + "build": 15850, + "version": "2.3.0", + "layerDefinitions": [ + { + "type": "CIMFeatureLayer", + "useSourceMetadata": false, + "sourceModifiedTime": { + "type": "TimeInstant" + }, + "uRI": "CIMPATH=2__Controles_4aa9fc87_9b9c_4a2d_9801_4c1e6caae1fd.xml", + "name": "v1_BGT_inlooptabel \u2014 2. Controles", + "enableLayerEffects": false, + "useVisibilityTimeExtent": false, + "rasterizeOnExport": false, + "layerScaleVisibilityOptions": { + "type": "CIMLayerScaleVisibilityOptions", + "showLayerAtAllScales": true, + "savedMinScale": 100000000.0, + "savedMaxScale": 0.0 + }, + "allowDrapingOnIntegratedMesh": false, + "blendingMode": "Alpha", + "showMapTips": false, + "refreshRateUnit": "esriTimeUnitsSeconds", + "refreshRate": -1, + "searchable": false, + "serviceLayerID": -1, + "showPopups": false, + "maxDisplayCacheAge": 5, + "displayCacheType": "Permanent", + "visibility": true, + "transparency": 0.0, + "showLegends": true, + "layerType": "Operational", + "expanded": true, + "description": "", + "attribution": "", + "layerEffectsMode": "Layer", + "featureBlendingMode": "Alpha", + "displayFiltersType": "ByChoice", + "enableDisplayFilters": false, + "featureCacheType": "None", + "useSelectionSymbol": false, + "selectable": true, + "isFlattened": true, + "htmlPopupEnabled": false, + "featureTable": { + "type": "CIMFeatureTable", + "isLicensedDataSource": false, + "searchOrder": "esriSearchOrderSpatial", + "studyAreaSpatialRel": "esriSpatialRelUndefined", + "dataConnection": { + "type": "CIMSqlQueryDataConnection", + "datasetType": "esriDTFeatureClass", + "dataset": "main.%\"2. Controles\"", + "workspaceFactory": "Sql", + "workspaceConnectionString": "AUTHENTICATION_MODE=OSA;DATABASE=..\\inlooptool_test\\v1_BGT_inlooptabel.gpkg", + "mappedOIDFieldLength": "OID64Bit", + "isTableBased": true, + "spatialStorageType": 11, + "queryFields": [ + { + "name": "id", + "type": "esriFieldTypeBigInteger", + "isNullable": false, + "length": 8, + "precision": 0, + "scale": 0, + "required": true, + "editable": false, + "dbmsType": 11 + }, + { + "name": "geom", + "type": "esriFieldTypeGeometry", + "isNullable": true, + "length": 8, + "precision": 0, + "scale": 0, + "geometryDef": { + "avgNumPoints": 0, + "geometryType": "esriGeometryPolygon", + "hasM": false, + "hasZ": false, + "spatialReference": { + "latestWkid": 28992, + "wkid": 28992 + } + }, + "dbmsType": 8 + }, + { + "name": "niveau", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + }, + { + "name": "error_code", + "type": "esriFieldTypeBigInteger", + "isNullable": true, + "length": 8, + "precision": 0, + "scale": 0, + "dbmsType": 11 + }, + { + "name": "tabel", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + }, + { + "name": "kolom", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + }, + { + "name": "waarde", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + }, + { + "name": "omschrijving", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + } + ], + "geometryType": "esriGeometryPolygon", + "oIDFields": "id", + "spatialReference": { + "latestWkid": 28992, + "wkid": 28992 + }, + "srid": "28992", + "sqlQuery": "select id,geom,\"niveau\",\"error_code\",\"tabel\",\"kolom\",\"waarde\",\"omschrijving\" from main.\"2. Controles\"" + }, + "useSubtypeValue": false, + "selectRelatedData": false, + "timeDisplayDefinition": { + "type": "CIMTimeDisplayDefinition", + "timeOffsetUnits": "esriTimeUnitsYears", + "timeIntervalUnits": "esriTimeUnitsHours", + "timeInterval": 0, + "cumulative": false + }, + "timeDefinition": { + "type": "CIMTimeDataDefinition", + "timeExtentCanChange": false, + "hasLiveData": true, + "useTime": false + }, + "timeFields": { + "type": "CIMTimeTableDefinition" + }, + "editable": true + }, + "autoGenerateFeatureTemplates": true, + "showTracks": false, + "showPreviousObservations": false, + "useRealWorldSymbolSizes": false, + "snappable": true, + "scaleSymbols": true, + "renderer": { + "type": "CIMUniqueValueRenderer", + "showClassVisibility": false, + "isDefaultSymbolVisible": false, + "polygonSymbolColorTarget": "Fill", + "useDefaultSymbol": false, + "groups": [ + { + "type": "CIMUniqueValueGroup", + "heading": "error_code", + "classes": [ + { + "type": "CIMUniqueValueClass", + "visible": true, + "values": [ + { + "type": "CIMUniqueValue", + "fieldValues": [ + 1 + ] + } + ], + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 255, + 99, + 211, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 255, + 99, + 211, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "patch": "Default", + "label": "Groot BGT vlak", + "editable": false + }, + { + "type": "CIMUniqueValueClass", + "visible": true, + "values": [ + { + "type": "CIMUniqueValue", + "fieldValues": [ + 2.0 + ] + } + ], + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 232, + 32, + 28, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 232, + 32, + 28, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "patch": "Default", + "label": "Pand ontbreekt in BAG", + "editable": false + }, + { + "type": "CIMUniqueValueClass", + "visible": true, + "values": [ + { + "type": "CIMUniqueValue", + "fieldValues": [ + 3.0 + ] + } + ], + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 51, + 160, + 44, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 51, + 160, + 44, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "patch": "Default", + "label": "Waterpasserende verharding of groen dak", + "editable": false + }, + { + "type": "CIMUniqueValueClass", + "visible": true, + "values": [ + { + "type": "CIMUniqueValue", + "fieldValues": [ + 4 + ] + } + ], + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 31, + 120, + 180, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 31, + 120, + 180, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "patch": "Default", + "label": "Hogere relatieve hoogteligging", + "editable": false + }, + { + "type": "CIMUniqueValueClass", + "visible": true, + "values": [ + { + "type": "CIMUniqueValue", + "fieldValues": [ + 5 + ] + } + ], + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 234, + 122, + 70, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 234, + 122, + 70, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "patch": "Default", + "label": "Handmatige wijziging overlapt met nieuwe BGT data", + "editable": false + }, + { + "type": "CIMUniqueValueClass", + "visible": true, + "values": [ + { + "type": "CIMUniqueValue", + "fieldValues": [ + 6 + ] + } + ], + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 84, + 212, + 206, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 84, + 212, + 206, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "patch": "Default", + "label": "Handmatig gewijzigde vlak bestaat niet meer", + "editable": false + } + ] + } + ], + "fields": [ + "error_code" + ], + "defaultSymbolPatch": "Default", + "defaultSymbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.3039361864968906, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 255, + 127, + 0, + 100.0 + ] + } + }, + { + "type": "CIMHatchFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "separation": 5.669287767377785, + "rotation": 45.0, + "lineSymbol": { + "type": "CIMLineSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.8503931651066676, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Square", + "color": { + "type": "CIMRGBColor", + "values": [ + 255, + 127, + 0, + 100.0 + ] + } + } + ] + } + } + ], + "angleAlignment": "Display" + } + }, + "defaultLabel": "" + }, + "labelVisibility": false + } + ], + "layers": [ + "CIMPATH=2__Controles_4aa9fc87_9b9c_4a2d_9801_4c1e6caae1fd.xml" + ] +} \ No newline at end of file diff --git a/ArcGIS_plugin/bgt_inlooptool/layers/statistieken.lyrx b/ArcGIS_plugin/bgt_inlooptool/layers/statistieken.lyrx new file mode 100644 index 0000000..22b6747 --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/layers/statistieken.lyrx @@ -0,0 +1,1241 @@ +{ + "type" : "CIMLayerDocument", + "version" : "3.2.0", + "build" : 49743, + "layers" : [ + "CIMPATH=map/main__6_statistieken_.json" + ], + "layerDefinitions" : [ + { + "type" : "CIMFeatureLayer", + "name" : "6. Statistieken", + "uRI" : "CIMPATH=map/main__6_statistieken_.json", + "sourceModifiedTime" : { + "type" : "TimeInstant" + }, + "useSourceMetadata" : true, + "description" : "main.\"6_Statistieken\"", + "layerElevation" : { + "type" : "CIMLayerElevationSurface", + "elevationSurfaceLayerURI" : "CIMPATH=Map/2bcac69cf5ff4c5bb5c5ba351952a8da.json" + }, + "expanded" : true, + "layerType" : "Operational", + "showLegends" : true, + "visibility" : true, + "displayCacheType" : "Permanent", + "maxDisplayCacheAge" : 5, + "showPopups" : true, + "serviceLayerID" : -1, + "refreshRate" : -1, + "refreshRateUnit" : "esriTimeUnitsSeconds", + "blendingMode" : "Alpha", + "allowDrapingOnIntegratedMesh" : true, + "autoGenerateFeatureTemplates" : true, + "featureElevationExpression" : "0", + "featureTable" : { + "type" : "CIMFeatureTable", + "displayField" : "opp_totaal", + "editable" : true, + "dataConnection" : { + "type" : "CIMSqlQueryDataConnection", + "workspaceConnectionString" : "AUTHENTICATION_MODE=OSA;DATABASE=.\\inlooptool_test\\v1_BGT_inlooptabel_20241211_101215.gpkg", + "workspaceFactory" : "Sql", + "dataset" : "main.%\"6_Statistieken\"", + "datasetType" : "esriDTFeatureClass", + "sqlQuery" : "select id,geom,opp_totaal,opp_gemengd,opp_hwa,opp_vgs,opp_dwa,opp_infiltratievoorziening,opp_open_water,opp_maaiveld,perc_gemengd,perc_hwa,perc_vgs,perc_dwa,perc_infiltratievoorziening,perc_open_water,perc_maaiveld,opp_totaal_dak,opp_totaal_gesl_verh,opp_totaal_open_verh,opp_totaal_onverhard,opp_gemengd_dak,opp_gemengd_gesl_verh,opp_gemengd_open_verh,opp_gemengd_onverhard,opp_hwa_dak,opp_hwa_gesl_verh,opp_hwa_open_verh,opp_hwa_onverhard,opp_vgs_dak,opp_vgs_gesl_verh,opp_vgs_open_verh,opp_vgs_onverhard,opp_dwa_dak,opp_dwa_gesl_verh,opp_dwa_open_verh,opp_dwa_onverhard,opp_infiltratievoorziening_dak,opp_infiltratievoorziening_gesl_verh,opp_infiltratievoorziening_open_verh,opp_infiltratievoorziening_onverhard,opp_open_water_dak,opp_open_water_gesl_verh,opp_open_water_open_verh,opp_open_water_onverhard,opp_maaiveld_dak,opp_maaiveld_gesl_verh,opp_maaiveld_open_verh,opp_maaiveld_onverhard,perc_gemengd_dak,perc_gemengd_gesl_verh,perc_gemengd_open_verh,perc_gemengd_onverhard,perc_hwa_dak,perc_hwa_gesl_verh,perc_hwa_open_verh,perc_hwa_onverhard,perc_vgs_dak,perc_vgs_gesl_verh,perc_vgs_open_verh,perc_vgs_onverhard,perc_dwa_dak,perc_dwa_gesl_verh,perc_dwa_open_verh,perc_dwa_onverhard,perc_infiltratievoorziening_dak,perc_infiltratievoorziening_gesl_verh,perc_infiltratievoorziening_open_verh,perc_infiltratievoorziening_onverhard,perc_open_water_dak,perc_open_water_gesl_verh,perc_open_water_open_verh,perc_open_water_onverhard,perc_maaiveld_dak,perc_maaiveld_gesl_verh,perc_maaiveld_open_verh,perc_maaiveld_onverhard,opp_dak,opp_gesl_verh,opp_open_verh,opp_onverhard,opp_groen_dak,opp_waterpas_verh,opp_water,perc_dak,perc_gesl_verh,perc_open_verh,perc_onverhard,perc_groen_dak,perc_waterpas_verh,perc_water from main.\"6_Statistieken\"", + "srid" : "28992", + "spatialReference" : { + "wkid" : 28992, + "latestWkid" : 28992, + "xyTolerance" : 0.001, + "zTolerance" : 0.001, + "mTolerance" : 0.001, + "falseX" : -30515500, + "falseY" : -30279500, + "xyUnits" : 10000, + "falseZ" : -100000, + "zUnits" : 10000, + "falseM" : -100000, + "mUnits" : 10000 + }, + "oIDFields" : "id", + "geometryType" : "esriGeometryPolygon", + "queryFields" : [ + { + "name" : "id", + "type" : "esriFieldTypeBigInteger", + "isNullable" : false, + "length" : 8, + "precision" : 0, + "scale" : 0, + "required" : true, + "editable" : false, + "dbmsType" : 11 + }, + { + "name" : "geom", + "type" : "esriFieldTypeGeometry", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "geometryDef" : { + "avgNumPoints" : 0, + "geometryType" : "esriGeometryPolygon", + "hasM" : false, + "hasZ" : false, + "spatialReference" : { + "wkid" : 28992, + "latestWkid" : 28992, + "xyTolerance" : 0.001, + "zTolerance" : 0.001, + "mTolerance" : 0.001, + "falseX" : -30515500, + "falseY" : -30279500, + "xyUnits" : 10000, + "falseZ" : -100000, + "zUnits" : 10000, + "falseM" : -100000, + "mUnits" : 10000 + } + }, + "dbmsType" : 8 + }, + { + "name" : "opp_totaal", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_gemengd", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_hwa", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_vgs", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_dwa", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_infiltratievoorziening", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_open_water", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_maaiveld", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_gemengd", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_hwa", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_vgs", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_dwa", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_infiltratievoorziening", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_open_water", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_maaiveld", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_totaal_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_totaal_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_totaal_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_totaal_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_gemengd_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_gemengd_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_gemengd_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_gemengd_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_hwa_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_hwa_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_hwa_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_hwa_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_vgs_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_vgs_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_vgs_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_vgs_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_dwa_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_dwa_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_dwa_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_dwa_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_infiltratievoorziening_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_infiltratievoorziening_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_infiltratievoorziening_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_infiltratievoorziening_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_open_water_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_open_water_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_open_water_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_open_water_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_maaiveld_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_maaiveld_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_maaiveld_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_maaiveld_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_gemengd_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_gemengd_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_gemengd_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_gemengd_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_hwa_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_hwa_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_hwa_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_hwa_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_vgs_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_vgs_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_vgs_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_vgs_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_dwa_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_dwa_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_dwa_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_dwa_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_infiltratievoorziening_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_infiltratievoorziening_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_infiltratievoorziening_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_infiltratievoorziening_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_open_water_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_open_water_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_open_water_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_open_water_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_maaiveld_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_maaiveld_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_maaiveld_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_maaiveld_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_groen_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_waterpas_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "opp_water", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_gesl_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_open_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_onverhard", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_groen_dak", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_waterpas_verh", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + }, + { + "name" : "perc_water", + "type" : "esriFieldTypeDouble", + "isNullable" : true, + "length" : 8, + "precision" : 0, + "scale" : 0, + "dbmsType" : 4 + } + ], + "spatialStorageType" : 11, + "isTableBased" : true, + "mappedOIDFieldLength" : "OID64Bit" + }, + "studyAreaSpatialRel" : "esriSpatialRelUndefined", + "searchOrder" : "esriSearchOrderSpatial" + }, + "htmlPopupEnabled" : true, + "selectable" : true, + "featureCacheType" : "Session", + "displayFiltersType" : "ByScale", + "featureBlendingMode" : "Alpha", + "labelClasses" : [ + { + "type" : "CIMLabelClass", + "expressionTitle" : "Custom", + "expression" : "var id = $feature.OBJECTID;\r\nvar perc_gemengd = $feature.perc_gemengd;\r\nvar perc_hwa = $feature.perc_hwa;\r\nvar perc_vgs = $feature.perc_vgs;\r\nvar perc_dwa = $feature.perc_dwa;\r\nvar perc_infiltratievoorziening = $feature.perc_infiltratievoorziening;\r\nvar perc_open_water = $feature.perc_open_water;\r\nvar perc_maaiveld = $feature.perc_maaiveld;\r\n\r\nvar label_string = 'Gebied: ' + Text(id) + '\\n' +\r\n 'Gemengd riool: ' + Text(perc_gemengd) + '%' + '\\n' +\r\n 'Hemelwaterriool: ' + Text(perc_hwa) + '%' + '\\n' +\r\n 'VGS hemelwateriool: ' + Text(perc_vgs) + '%' + '\\n' +\r\n 'Vuilwaterriool: ' + Text(perc_dwa) + '%' + '\\n' +\r\n 'Infiltratievoorziening: ' + Text(perc_infiltratievoorziening) + '%' + '\\n' +\r\n 'Open water : ' + Text(perc_open_water) + '%' + '\\n' +\r\n 'Maaiveld: ' + Text(perc_maaiveld) + '%';\r\n\r\nreturn label_string;", + "expressionEngine" : "Arcade", + "featuresToLabel" : "AllVisibleFeatures", + "maplexLabelPlacementProperties" : { + "type" : "CIMMaplexLabelPlacementProperties", + "featureType" : "Polygon", + "avoidPolygonHoles" : true, + "canOverrunFeature" : true, + "canPlaceLabelOutsidePolygon" : true, + "canRemoveOverlappingLabel" : true, + "canStackLabel" : true, + "centerLabelAnchorType" : "Symbol", + "connectionType" : "Unambiguous", + "constrainOffset" : "NoConstraint", + "contourAlignmentType" : "Page", + "contourLadderType" : "Straight", + "contourMaximumAngle" : 90, + "enableConnection" : true, + "featureWeight" : 0, + "fontHeightReductionLimit" : 4, + "fontHeightReductionStep" : 0.5, + "fontWidthReductionLimit" : 90, + "fontWidthReductionStep" : 5, + "graticuleAlignmentType" : "Straight", + "keyNumberGroupName" : "Default", + "labelBuffer" : 15, + "labelLargestPolygon" : true, + "labelPriority" : -1, + "labelStackingProperties" : { + "type" : "CIMMaplexLabelStackingProperties", + "stackAlignment" : "ChooseBest", + "maximumNumberOfLines" : 3, + "minimumNumberOfCharsPerLine" : 3, + "maximumNumberOfCharsPerLine" : 24, + "separators" : [ + { + "type" : "CIMMaplexStackingSeparator", + "separator" : " ", + "splitAfter" : true + }, + { + "type" : "CIMMaplexStackingSeparator", + "separator" : ",", + "visible" : true, + "splitAfter" : true + } + ], + "trimStackingSeparators" : true + }, + "lineFeatureType" : "General", + "linePlacementMethod" : "OffsetCurvedFromLine", + "maximumLabelOverrun" : 80, + "maximumLabelOverrunUnit" : "Point", + "measureFromClippedFeatureGeometry" : true, + "minimumFeatureSizeUnit" : "Map", + "multiPartOption" : "OneLabelPerPart", + "offsetAlongLineProperties" : { + "type" : "CIMMaplexOffsetAlongLineProperties", + "placementMethod" : "BestPositionAlongLine", + "labelAnchorPoint" : "CenterOfLabel", + "distanceUnit" : "Percentage", + "useLineDirection" : true + }, + "pointExternalZonePriorities" : { + "type" : "CIMMaplexExternalZonePriorities", + "aboveLeft" : 4, + "aboveCenter" : 2, + "aboveRight" : 1, + "centerRight" : 3, + "belowRight" : 5, + "belowCenter" : 7, + "belowLeft" : 8, + "centerLeft" : 6 + }, + "pointPlacementMethod" : "AroundPoint", + "polygonAnchorPointType" : "GeometricCenter", + "polygonBoundaryWeight" : 0, + "polygonExternalZones" : { + "type" : "CIMMaplexExternalZonePriorities", + "aboveLeft" : 4, + "aboveCenter" : 2, + "aboveRight" : 1, + "centerRight" : 3, + "belowRight" : 5, + "belowCenter" : 7, + "belowLeft" : 8, + "centerLeft" : 6 + }, + "polygonFeatureType" : "General", + "polygonInternalZones" : { + "type" : "CIMMaplexInternalZonePriorities", + "center" : 1 + }, + "polygonPlacementMethod" : "HorizontalInPolygon", + "primaryOffset" : 1, + "primaryOffsetUnit" : "Point", + "removeAmbiguousLabels" : "All", + "removeExtraWhiteSpace" : true, + "repetitionIntervalUnit" : "Point", + "rotationProperties" : { + "type" : "CIMMaplexRotationProperties", + "rotationType" : "Arithmetic", + "alignmentType" : "Straight" + }, + "secondaryOffset" : 100, + "secondaryOffsetUnit" : "Percentage", + "strategyPriorities" : { + "type" : "CIMMaplexStrategyPriorities", + "stacking" : 1, + "overrun" : 2, + "fontCompression" : 3, + "fontReduction" : 4, + "abbreviation" : 5 + }, + "thinningDistanceUnit" : "Point", + "truncationMarkerCharacter" : ".", + "truncationMinimumLength" : 1, + "truncationPreferredCharacters" : "aeiou", + "truncationExcludedCharacters" : "0123456789", + "polygonAnchorPointPerimeterInsetUnit" : "Point" + }, + "name" : "Class 1", + "priority" : -1, + "standardLabelPlacementProperties" : { + "type" : "CIMStandardLabelPlacementProperties", + "featureType" : "Line", + "featureWeight" : "None", + "labelWeight" : "High", + "numLabelsOption" : "OneLabelPerName", + "lineLabelPosition" : { + "type" : "CIMStandardLineLabelPosition", + "above" : true, + "inLine" : true, + "parallel" : true + }, + "lineLabelPriorities" : { + "type" : "CIMStandardLineLabelPriorities", + "aboveStart" : 3, + "aboveAlong" : 3, + "aboveEnd" : 3, + "centerStart" : 3, + "centerAlong" : 3, + "centerEnd" : 3, + "belowStart" : 3, + "belowAlong" : 3, + "belowEnd" : 3 + }, + "pointPlacementMethod" : "AroundPoint", + "pointPlacementPriorities" : { + "type" : "CIMStandardPointPlacementPriorities", + "aboveLeft" : 2, + "aboveCenter" : 2, + "aboveRight" : 1, + "centerLeft" : 3, + "centerRight" : 2, + "belowLeft" : 3, + "belowCenter" : 3, + "belowRight" : 2 + }, + "rotationType" : "Arithmetic", + "polygonPlacementMethod" : "AlwaysHorizontal" + }, + "textSymbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMTextSymbol", + "blockProgression" : "TTB", + "depth3D" : 1, + "extrapolateBaselines" : true, + "fontEffects" : "Normal", + "fontEncoding" : "Unicode", + "fontFamilyName" : "Tahoma", + "fontStyleName" : "Regular", + "fontType" : "Unspecified", + "haloSize" : 1, + "height" : 10, + "hinting" : "Default", + "horizontalAlignment" : "Left", + "kerning" : true, + "letterWidth" : 100, + "ligatures" : true, + "lineGapType" : "ExtraLeading", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 0, + 0, + 0, + 100 + ] + } + } + ], + "angleAlignment" : "Map" + }, + "textCase" : "Normal", + "textDirection" : "LTR", + "verticalAlignment" : "Bottom", + "verticalGlyphOrientation" : "Right", + "wordSpacing" : 100, + "billboardMode3D" : "FaceNearPlane" + } + }, + "useCodedValue" : true, + "visibility" : true, + "iD" : -1 + } + ], + "labelVisibility" : true, + "renderer" : { + "type" : "CIMSimpleRenderer", + "sampleSize" : 10000, + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "effects" : [ + { + "type" : "CIMGeometricEffectAddControlPoints", + "angleTolerance" : 120 + } + ], + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "effects" : [ + { + "type" : "CIMGeometricEffectDashes", + "dashTemplate" : [ + 6, + 6 + ], + "lineDashEnding" : "HalfPattern", + "controlPointEnding" : "HalfPattern" + } + ], + "enable" : true, + "capStyle" : "Butt", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 1, + "height3D" : 1, + "anchor3D" : "Center", + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 0, + 0, + 0, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 130, + 130, + 130, + 0 + ] + } + } + ], + "angleAlignment" : "Map" + } + } + }, + "scaleSymbols" : true, + "snappable" : true + } + ], + "rGBColorProfile" : "sRGB IEC61966-2.1", + "cMYKColorProfile" : "U.S. Web Coated (SWOP) v2", + "elevationSurfaceLayerDefinitions" : [ + { + "type" : "CIMElevationSurfaceLayer", + "name" : "Ground", + "uRI" : "CIMPATH=Map/2bcac69cf5ff4c5bb5c5ba351952a8da.json", + "useSourceMetadata" : true, + "description" : "Ground", + "expanded" : true, + "layerType" : "Operational", + "showLegends" : false, + "visibility" : true, + "displayCacheType" : "Permanent", + "maxDisplayCacheAge" : 5, + "showPopups" : true, + "serviceLayerID" : -1, + "refreshRate" : -1, + "refreshRateUnit" : "esriTimeUnitsSeconds", + "blendingMode" : "Alpha", + "allowDrapingOnIntegratedMesh" : true, + "elevationMode" : "BaseGlobeSurface", + "verticalExaggeration" : 1, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 255, + 255, + 255, + 100 + ] + }, + "surfaceTINShadingMode" : "Smooth" + } + ] +} \ No newline at end of file diff --git a/ArcGIS_plugin/bgt_inlooptool/layers/template_output.gpkg b/ArcGIS_plugin/bgt_inlooptool/layers/template_output.gpkg new file mode 100644 index 0000000..6a4f0f7 Binary files /dev/null and b/ArcGIS_plugin/bgt_inlooptool/layers/template_output.gpkg differ diff --git a/ArcGIS_plugin/bgt_inlooptool/layers/template_output_hidden_fields.gpkg b/ArcGIS_plugin/bgt_inlooptool/layers/template_output_hidden_fields.gpkg new file mode 100644 index 0000000..ecb33e0 Binary files /dev/null and b/ArcGIS_plugin/bgt_inlooptool/layers/template_output_hidden_fields.gpkg differ diff --git a/ArcGIS_plugin/bgt_inlooptool/layers/waterpasserende_verharding_en_groen_daken.lyrx b/ArcGIS_plugin/bgt_inlooptool/layers/waterpasserende_verharding_en_groen_daken.lyrx new file mode 100644 index 0000000..77935ae --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/layers/waterpasserende_verharding_en_groen_daken.lyrx @@ -0,0 +1,396 @@ +{ + "type": "CIMLayerDocument", + "build": 15850, + "version": "2.3.0", + "layerDefinitions": [ + { + "type": "CIMFeatureLayer", + "useSourceMetadata": false, + "sourceModifiedTime": { + "type": "TimeInstant" + }, + "uRI": "CIMPATH=1__Waterpasserende_verharding_en_groene_daken__optionele_input__fd50ac41_c4e2_4a7d_94ed_54a246d1d12a.xml", + "name": "v1_BGT_inlooptabel \u2014 1. Waterpasserende verharding en groene daken [optionele input]", + "enableLayerEffects": false, + "useVisibilityTimeExtent": false, + "rasterizeOnExport": false, + "layerScaleVisibilityOptions": { + "type": "CIMLayerScaleVisibilityOptions", + "showLayerAtAllScales": true, + "savedMinScale": 100000000.0, + "savedMaxScale": 0.0 + }, + "allowDrapingOnIntegratedMesh": false, + "blendingMode": "Alpha", + "showMapTips": false, + "refreshRateUnit": "esriTimeUnitsSeconds", + "refreshRate": -1, + "searchable": false, + "serviceLayerID": -1, + "showPopups": false, + "maxDisplayCacheAge": 5, + "displayCacheType": "Permanent", + "visibility": true, + "transparency": 0.0, + "showLegends": true, + "layerType": "Operational", + "expanded": true, + "description": "", + "attribution": "", + "layerEffectsMode": "Layer", + "featureBlendingMode": "Alpha", + "displayFiltersType": "ByChoice", + "enableDisplayFilters": false, + "featureCacheType": "None", + "useSelectionSymbol": false, + "selectable": true, + "isFlattened": true, + "htmlPopupEnabled": false, + "featureTable": { + "type": "CIMFeatureTable", + "isLicensedDataSource": false, + "searchOrder": "esriSearchOrderSpatial", + "studyAreaSpatialRel": "esriSpatialRelUndefined", + "dataConnection": { + "type": "CIMSqlQueryDataConnection", + "datasetType": "esriDTFeatureClass", + "dataset": "main.%\"1. Waterpasserende verharding en groene daken [optionele input]\"", + "workspaceFactory": "Sql", + "workspaceConnectionString": "AUTHENTICATION_MODE=OSA;DATABASE=..\\inlooptool_test\\v1_BGT_inlooptabel.gpkg", + "mappedOIDFieldLength": "OID64Bit", + "isTableBased": true, + "spatialStorageType": 11, + "queryFields": [ + { + "name": "fid", + "type": "esriFieldTypeBigInteger", + "isNullable": false, + "length": 8, + "precision": 0, + "scale": 0, + "required": true, + "editable": false, + "dbmsType": 11 + }, + { + "name": "geom", + "type": "esriFieldTypeGeometry", + "isNullable": true, + "length": 8, + "precision": 0, + "scale": 0, + "geometryDef": { + "avgNumPoints": 0, + "geometryType": "esriGeometryPoint", + "hasM": false, + "hasZ": false, + "spatialReference": { + "latestWkid": 28992, + "wkid": 28992 + } + }, + "dbmsType": 8 + }, + { + "name": "type", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + }, + { + "name": "jaar_aanleg", + "type": "esriFieldTypeBigInteger", + "isNullable": true, + "length": 8, + "precision": 0, + "scale": 0, + "dbmsType": 11 + }, + { + "name": "omschrijving", + "type": "esriFieldTypeString", + "isNullable": true, + "length": 2147483647, + "precision": 0, + "scale": 0, + "dbmsType": 13 + } + ], + "geometryType": "esriGeometryPoint", + "oIDFields": "fid", + "spatialReference": { + "latestWkid": 28992, + "wkid": 28992 + }, + "srid": "28992", + "sqlQuery": "select fid,geom,\"type\",\"jaar_aanleg\",\"omschrijving\" from main.\"1. Waterpasserende verharding en groene daken [optionele input]\"" + }, + "useSubtypeValue": false, + "selectRelatedData": false, + "timeDisplayDefinition": { + "type": "CIMTimeDisplayDefinition", + "timeOffsetUnits": "esriTimeUnitsYears", + "timeIntervalUnits": "esriTimeUnitsHours", + "timeInterval": 0, + "cumulative": false + }, + "timeDefinition": { + "type": "CIMTimeDataDefinition", + "timeExtentCanChange": false, + "hasLiveData": true, + "useTime": false + }, + "timeFields": { + "type": "CIMTimeTableDefinition" + }, + "editable": true + }, + "autoGenerateFeatureTemplates": true, + "showTracks": false, + "showPreviousObservations": false, + "useRealWorldSymbolSizes": false, + "snappable": true, + "scaleSymbols": true, + "renderer": { + "type": "CIMSimpleRenderer", + "symbol": { + "type": "CIMSymbolReference", + "symbol": { + "type": "CIMPointSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMVectorMarker", + "overprint": false, + "colorLocked": false, + "enable": true, + "billboardMode3D": "None", + "size": 1.9842507185822245, + "rotation": -0.0, + "rotateClockwise": false, + "offsetY": 0, + "offsetX": 0, + "dominantSizeAxis3D": "Z", + "anchorPointUnits": "Relative", + "anchorPoint": { + "KnownSimple": false, + "hasM": false, + "hasZ": false, + "hasId": false, + "y": 0, + "x": 0 + }, + "scaleStrokesAndFills": false, + "respectFrame": true, + "scaleSymbolsProportionally": false, + "verticalOrientation3D": false, + "markerGraphics": [ + { + "type": "CIMMarkerGraphic", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 1.133857553475557, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Butt", + "color": { + "type": "CIMRGBColor", + "values": [ + 0, + 0, + 0, + 100.0 + ] + } + }, + { + "type": "CIMSolidFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "color": { + "type": "CIMRGBColor", + "values": [ + 0, + 0, + 0, + 100.0 + ] + } + } + ], + "angleAlignment": "Display" + }, + "geometry": { + "KnownSimple": false, + "hasM": false, + "hasZ": false, + "hasId": false, + "curveRings": [ + [ + [ + -1, + 1 + ], + { + "a": [ + [ + -1, + 1 + ], + [ + 0.0, + 0.0 + ], + 0, + 1 + ] + } + ] + ] + } + } + ], + "frame": { + "ymin": -1, + "ymax": 1, + "xmin": -1, + "xmax": 1 + } + }, + { + "type": "CIMVectorMarker", + "overprint": false, + "colorLocked": false, + "enable": true, + "billboardMode3D": "None", + "size": 9.070860427804456, + "rotation": -0.0, + "rotateClockwise": false, + "offsetY": 0, + "offsetX": 0, + "dominantSizeAxis3D": "Z", + "anchorPointUnits": "Relative", + "anchorPoint": { + "KnownSimple": false, + "hasM": false, + "hasZ": false, + "hasId": false, + "y": 0, + "x": 0 + }, + "scaleStrokesAndFills": false, + "respectFrame": true, + "scaleSymbolsProportionally": false, + "verticalOrientation3D": false, + "markerGraphics": [ + { + "type": "CIMMarkerGraphic", + "symbol": { + "type": "CIMPolygonSymbol", + "useRealWorldSymbolSizes": false, + "symbolLayers": [ + { + "type": "CIMSolidStroke", + "overprint": false, + "colorLocked": false, + "enable": true, + "anchor3D": "Center", + "closeCaps3D": false, + "width": 0.5669287767377785, + "miterLimit": 10, + "lineStyle3D": "Tube", + "joinStyle": "Bevel", + "capStyle": "Butt", + "color": { + "type": "CIMRGBColor", + "values": [ + 0, + 0, + 0, + 100.0 + ] + } + }, + { + "type": "CIMSolidFill", + "overprint": false, + "colorLocked": false, + "enable": true, + "color": { + "type": "CIMRGBColor", + "values": [ + 255, + 255, + 255, + 100.0 + ] + } + } + ], + "angleAlignment": "Display" + }, + "geometry": { + "KnownSimple": false, + "hasM": false, + "hasZ": false, + "hasId": false, + "curveRings": [ + [ + [ + -1, + 1 + ], + { + "a": [ + [ + -1, + 1 + ], + [ + 0.0, + 0.0 + ], + 0, + 1 + ] + } + ] + ] + } + } + ], + "frame": { + "ymin": -1, + "ymax": 1, + "xmin": -1, + "xmax": 1 + } + } + ], + "angleAlignment": "Display", + "scaleX": 1 + } + }, + "patch": "Default" + }, + "labelVisibility": false + } + ], + "layers": [ + "CIMPATH=1__Waterpasserende_verharding_en_groene_daken__optionele_input__fd50ac41_c4e2_4a7d_94ed_54a246d1d12a.xml" + ] +} \ No newline at end of file diff --git a/ArcGIS_plugin/bgt_inlooptool/pyt_bgt_inlooptool_arcgis.py b/ArcGIS_plugin/bgt_inlooptool/pyt_bgt_inlooptool_arcgis.py new file mode 100644 index 0000000..0a350c8 --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/pyt_bgt_inlooptool_arcgis.py @@ -0,0 +1,777 @@ +""" +Script Name: bgt inloop tool voor ArcGIS +Description: bgt inloop tool voor ArcGIS +Created By: Sjoerd Hoekstra +Date: 29/09/2020 +""" + +import os +import sys + +import arcpy + +# Relative imports don't work well in arcgis, therefore paths are appended to sys +bgt_inlooptool_dir = os.path.dirname(__file__) +sys.path.append(bgt_inlooptool_dir) +sys.path.append(os.path.join(bgt_inlooptool_dir, "core")) + +# Set path to Generic modules +from helper_functions.cls_general_use import GeneralUse +from helper_functions.common import ( + BaseTool, + add_bgt_inlooptabel_symbologyfield, + add_gwsw_symbologyfield, + get_wkt_extent, + layers_to_gdb, + parameter, +) +from helper_functions.constants import VisualizeLayer +from helper_functions.visualize_layers import VisualizeLayers +from bgt_inlooptool.rtree_installer import ensure_rtree_install + +ensure_rtree_install() + +from core.defaults import ( + AFKOPPELEN_HELLENDE_DAKEN, + BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, + MAX_AFSTAND_AFGEKOPPELD, + MAX_AFSTAND_DRIEVOUDIG, + MAX_AFSTAND_PAND_OPPWATER, + MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, + MAX_AFSTAND_VLAK_KOLK, + MAX_AFSTAND_VLAK_OPPWATER, + VERHARDINGSGRAAD_ERF, + VERHARDINGSGRAAD_HALF_VERHARD, +) + +# import bgt inlooptool +from core.inlooptool import InloopTool, InputParameters + +GPKG_TEMPLATE = os.path.join( + os.path.dirname(__file__), "layers", "template_output.gpkg" +) +GPKG_TEMPLATE_HIDDEN = os.path.join( + os.path.dirname(__file__), "layers", "template_output_hidden_fields.gpkg" +) + + +class BGTInloopToolArcGIS(BaseTool): + def __init__(self): + """ + Initialization. + """ + self.label = "2. BGT Inlooptool" + self.description = """BGT inlooptool voor ArcGIS""" + self.canRunInBackground = True + self.arcgis_com = GeneralUse(sys, arcpy) + + self.parameter_names = [ + "previous_results", + "bgt", + "leidingen", + "bag", + "kolken_file", + "input_extent_mask_wkt", + "input_statistics_shape", + "output_folder", + "max_vlak_afwatervoorziening", + "max_vlak_oppwater", + "max_pand_opwater", + "max_vlak_kolk", + "max_afgekoppeld", + "max_drievoudig", + "afkoppelen_daken", + "bouwjaar_riool", + "verhardingsgraaf_erf", + "verhardingsgraad_half_verhard", + "copy_pipe_codes", + "reset_input", + "water_passerende_verharding_symb", + "controles_symb", + "bgt_oppervlakken_symb", + "bgt_inlooptabel_symb", + "gwsw_lijn_symb", + "statistieken_symb", + "rekeninstellingen_symb", + ] + + self.previous_results_idx = self.parameter_names.index("previous_results") + self.bgt_idx = self.parameter_names.index("bgt") + self.leidingen_idx = self.parameter_names.index("leidingen") + self.bag_idx = self.parameter_names.index("bag") + self.kolken_file_idx = self.parameter_names.index("kolken_file") + self.input_extent_mask_wkt_idx = self.parameter_names.index( + "input_extent_mask_wkt" + ) + self.input_statistics_shape_idx = self.parameter_names.index( + "input_statistics_shape" + ) + self.output_folder_idx = self.parameter_names.index("output_folder") + self.max_vlak_afwatervoorziening_idx = self.parameter_names.index( + "max_vlak_afwatervoorziening" + ) + self.max_vlak_oppwater_idx = self.parameter_names.index("max_vlak_oppwater") + self.max_pand_opwater_idx = self.parameter_names.index("max_pand_opwater") + self.max_vlak_kolk_idx = self.parameter_names.index("max_vlak_kolk") + self.max_afgekoppeld_idx = self.parameter_names.index("max_afgekoppeld") + self.max_drievoudig_idx = self.parameter_names.index("max_drievoudig") + self.afkoppelen_daken_idx = self.parameter_names.index("afkoppelen_daken") + self.bouwjaar_riool_idx = self.parameter_names.index("bouwjaar_riool") + self.verhardingsgraaf_erf_idx = self.parameter_names.index( + "verhardingsgraaf_erf" + ) + self.verhardingsgraad_half_verhard_idx = self.parameter_names.index( + "verhardingsgraad_half_verhard" + ) + self.water_passerende_verharding_symb_idx = self.parameter_names.index( + "water_passerende_verharding_symb" + ) + self.controles_symb_idx = self.parameter_names.index("controles_symb") + self.bgt_oppervlakken_symb_idx = self.parameter_names.index( + "bgt_oppervlakken_symb" + ) + self.bgt_inlooptabel_symb_idx = self.parameter_names.index( + "bgt_inlooptabel_symb" + ) + self.statistieken_symb_idx = self.parameter_names.index("statistieken_symb") + self.gwsw_lijn_symb_idx = self.parameter_names.index("gwsw_lijn_symb") + self.rekeninstellingen_symb_idx = self.parameter_names.index( + "rekeninstellingen_symb" + ) + self.copy_pipe_codes_idx = self.parameter_names.index("copy_pipe_codes") + self.reset_input_idx = self.parameter_names.index("reset_input") + + def getParameterInfo(self): + """Create your parameters here using the paramater function. + Make sure you leave the enclosing brackets and separate your + parameters using commas. + parameter(displayName, name, datatype, defaultValue=None, parameterType='Required', direction='Input') + """ + layers = os.path.join(os.path.dirname(__file__), "layers") + + previous_results = parameter( + displayName="Vorige tooluitkomsten (als geopackage)", + name="previous_results", + datatype="DEDatasetType", + parameterType="Optional", + direction="Input", + ) + bgt = parameter( + displayName="BGT (als zipfile)", + name="bgt", + datatype="DEFile", + parameterType="Required", + direction="Input", + ) + leidingen = parameter( + displayName="GWSW Leidingen (als geopackage)", + name="leidingen", + datatype="DEDatasetType", + parameterType="Required", + direction="Input", + ) + bag = parameter( + displayName="BAG (als geopackage)", + name="bag", + datatype="DEDatasetType", + parameterType="Optional", + direction="Input", + ) + kolken_file = parameter( + displayName="Kolken", + name="kolken_file", + datatype="GPFeatureLayer", + parameterType="Optional", + direction="Input", + ) + input_extent_mask_wkt = parameter( + displayName="Analysegebied", + name="input_extent_mask_wkt", + datatype="GPFeatureLayer", + parameterType="Optional", + direction="Input", + ) + input_statistics_shape = parameter( + displayName="Statistiekgebieden", + name="input_statistics_shape", + datatype="GPFeatureLayer", + parameterType="Optional", + direction="Input", + ) + output_folder = parameter( + displayName="Opslaglocatie gpkg", + name="output_folder", + datatype="DEFolder", + parameterType="Required", + direction="Input", + ) + max_vlak_afwatervoorziening = parameter( + displayName="maximale afstand vlak afwateringsvoorziening", + name="max_vlak_afwatervoorziening", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, + ) + max_vlak_oppwater = parameter( + displayName="maximale afstand vlak oppervlaktewater", + name="max_vlak_oppwater", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=MAX_AFSTAND_VLAK_OPPWATER, + ) + max_pand_opwater = parameter( + displayName="maximale afstand pand oppervlaktewater", + name="max_pand_opwater", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=MAX_AFSTAND_PAND_OPPWATER, + ) + max_vlak_kolk = parameter( + displayName="maximale afstand vlak kolk", + name="max_vlak_kolk", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=MAX_AFSTAND_VLAK_KOLK, + ) + max_afgekoppeld = parameter( + displayName="maximale afstand afgekoppeld", + name="max_afgekoppeld", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=MAX_AFSTAND_AFGEKOPPELD, + ) + max_drievoudig = parameter( + displayName="maximale afstand drievoudig", + name="max_drievoudig", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=MAX_AFSTAND_DRIEVOUDIG, + ) + afkoppelen_daken = parameter( + displayName="afkoppelen hellende daken", + name="afkoppelen_daken", + datatype="GPBoolean", + parameterType="Required", + direction="Input", + defaultValue=AFKOPPELEN_HELLENDE_DAKEN, + ) + bouwjaar_riool = parameter( + displayName="bouwjaar gescheiden binnenhuisriolering", + name="bouwjaar_riool", + datatype="GPLong", + parameterType="Required", + direction="Input", + defaultValue=BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, + ) + verhardingsgraaf_erf = parameter( + displayName="verhardingsgraad erf", + name="verhardingsgraaf_erf", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=VERHARDINGSGRAAD_ERF, + ) + verhardingsgraad_half_verhard = parameter( + displayName="verhardingsgraad half verhard", + name="verhardingsgraad_half_verhard", + datatype="GPDouble", + parameterType="Required", + direction="Input", + defaultValue=VERHARDINGSGRAAD_HALF_VERHARD, + ) + copy_pipe_codes = parameter( + displayName="Leidingcodes koppelen", + name="copy_pipe_codes", + datatype="GPBoolean", + parameterType="Required", + direction="Input", + ) + copy_pipe_codes.value = False + + reset_input = parameter( + displayName="Vink aan om alle rekeningstellingen naar default te resetten", + name="reset_input", + datatype="GPBoolean", + parameterType="Optional", + direction="Input", + ) + reset_input.value = False + + # Set symbology + water_passerende_verharding_symb = parameter( + displayName="Waterpasserende lagen en groene daken symbology", + name="water_passerende_verharding_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=os.path.join( + layers, "waterpasserende_verharding_en_groen_daken.lyrx" + ), + ) + controles_symb = parameter( + displayName="Controles symbology", + name="controles_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=os.path.join(layers, "controles.lyrx"), + ) + bgt_oppervlakken_symb = parameter( + displayName="BGT oppervlakken symbology", + name="bgt_oppervlakken_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=os.path.join(layers, "bgt_oppervlakken.lyrx"), + ) + bgt_inlooptabel_symb = parameter( + displayName="BGT Inlooptabel symbology", + name="bgt_inlooptabel_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=os.path.join(layers, "bgt_inlooptabel.lyrx"), + ) + gwsw_lijn_symb = parameter( + displayName="GWSW lijnen symbology", + name="gwsw_lijn_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=os.path.join(layers, "gwsw_lijn.lyrx"), + ) + statistieken_symb = parameter( + displayName="Statistieken symbology", + name="statistieken_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=os.path.join(layers, "statistieken.lyrx"), + ) + rekeninstellingen_symb = parameter( + displayName="rekeninstellingen symbology", + name="rekeninstellingen_symb", + datatype="GPLayer", + parameterType="Derived", + direction="Output", + symbology=None, + ) + + return [ + previous_results, + bgt, + leidingen, + bag, + kolken_file, + input_extent_mask_wkt, + input_statistics_shape, + output_folder, + max_vlak_afwatervoorziening, + max_vlak_oppwater, + max_pand_opwater, + max_vlak_kolk, + max_afgekoppeld, + max_drievoudig, + afkoppelen_daken, + bouwjaar_riool, + verhardingsgraaf_erf, + verhardingsgraad_half_verhard, + copy_pipe_codes, + reset_input, + water_passerende_verharding_symb, + controles_symb, + bgt_oppervlakken_symb, + bgt_inlooptabel_symb, + gwsw_lijn_symb, + statistieken_symb, + rekeninstellingen_symb, + ] + + def updateParameters(self, parameters): + """ + updates a parameter in the interface if specified + """ + # If reset is true, reset all calculation parameters + if parameters[self.reset_input_idx].value is True: + parameters[self.max_vlak_afwatervoorziening_idx].value = ( + MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING + ) + parameters[self.max_vlak_oppwater_idx].value = MAX_AFSTAND_VLAK_OPPWATER + parameters[self.max_pand_opwater_idx].value = MAX_AFSTAND_PAND_OPPWATER + parameters[self.max_vlak_kolk_idx].value = MAX_AFSTAND_VLAK_KOLK + parameters[self.max_afgekoppeld_idx].value = MAX_AFSTAND_AFGEKOPPELD + parameters[self.max_drievoudig_idx].value = MAX_AFSTAND_DRIEVOUDIG + parameters[self.afkoppelen_daken_idx].value = AFKOPPELEN_HELLENDE_DAKEN + parameters[self.bouwjaar_riool_idx].value = ( + BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING + ) + parameters[self.verhardingsgraaf_erf_idx].value = VERHARDINGSGRAAD_ERF + parameters[self.verhardingsgraad_half_verhard_idx].value = ( + VERHARDINGSGRAAD_HALF_VERHARD + ) + parameters[self.copy_pipe_codes_idx].value = False + parameters[self.reset_input_idx].value = False + + super(BGTInloopToolArcGIS, self).updateParameters(parameters) + + def updateMessages(self, parameters): + """ + returns messages in the interface the wrong paths are filled in for the different parameters + """ + bgt_file = parameters[self.bgt_idx] + pipe_file = parameters[self.leidingen_idx] + bag_file = parameters[self.bag_idx] + input_area = parameters[self.input_extent_mask_wkt_idx] + + if bgt_file.altered: + if bgt_file.valueAsText[-4:].lower() != ".zip": + bgt_file.setErrorMessage( + "De input voor bgt data moet een zip file zijn met .gml files" + ) + + if pipe_file.altered: + if pipe_file.valueAsText[-5:].lower() != ".gpkg": + pipe_file.setErrorMessage( + "De input voor leidingen data moet een geopackage (.gpkg) zijn" + ) + + if bag_file.altered: + if bag_file.valueAsText[-5:].lower() != ".gpkg": + bag_file.setErrorMessage( + "De input voor bag data moet een geopackage (.gpkg) zijn" + ) + + # Messages interesse gebied + if input_area.altered: + desc = arcpy.Describe(input_area.valueAsText) + if desc.dataType not in ["FeatureClass", "FeatureLayer", "ShapeFile"]: + input_area.setErrorMessage( + "De invoer is niet van het type featureclass/shapefile/gpkg layer!" + ) + else: + if desc.shapeType != "Polygon": + input_area.setErrorMessage( + "De featureclass/shapefile/gpkg layer is niet van het type polygoon!" + ) + else: + feature_count = int( + arcpy.management.GetCount(input_area.valueAsText).getOutput(0) + ) + if feature_count != 1: + input_area.setErrorMessage( + "Er is meer of minder dan 1 feature aanwezig of geselecteerd!" + ) + + super(BGTInloopToolArcGIS, self).updateMessages(parameters) + + def execute(self, parameters, messages): + """Execute the tool""" + try: + self.arcgis_com.StartAnalyse() + self.arcgis_com.AddMessage("Start BGT Inlooptool!") + + bgt_file = parameters[self.bgt_idx].valueAsText + pipe_file = parameters[self.leidingen_idx].valueAsText + building_file = parameters[self.bag_idx].valueAsText + kolken_file = parameters[self.kolken_file_idx].valueAsText + input_area = parameters[self.input_extent_mask_wkt_idx].valueAsText + output_folder = parameters[self.output_folder_idx].valueAsText + previous_results_file = parameters[self.previous_results_idx].valueAsText + statistics_area = parameters[self.input_statistics_shape_idx].valueAsText + + core_parameters = InputParameters( + max_afstand_vlak_afwateringsvoorziening=parameters[ + self.max_vlak_afwatervoorziening_idx + ].value, + max_afstand_vlak_oppwater=parameters[self.max_vlak_oppwater_idx].value, + max_afstand_pand_oppwater=parameters[self.max_pand_opwater_idx].value, + max_afstand_vlak_kolk=parameters[self.max_vlak_kolk_idx].value, + max_afstand_afgekoppeld=parameters[self.max_afgekoppeld_idx].value, + max_afstand_drievoudig=parameters[self.max_drievoudig_idx].value, + afkoppelen_hellende_daken=parameters[self.afkoppelen_daken_idx].value, + gebruik_bag=building_file is not None, + gebruik_kolken=kolken_file is not None, + gebruik_resultaten=previous_results_file is not None, + gebruik_statistieken=statistics_area is not None, + bouwjaar_gescheiden_binnenhuisriolering=parameters[ + self.bouwjaar_riool_idx + ].value, + verhardingsgraad_erf=parameters[self.verhardingsgraaf_erf_idx].value, + verhardingsgraad_half_verhard=parameters[ + self.verhardingsgraad_half_verhard_idx + ].value, + leidingcodes_koppelen=parameters[self.copy_pipe_codes_idx].value, + ) + + if input_area is not None: + # get the input extent as wkt from the input_area + input_extent_mask_wkt = get_wkt_extent(input_area) + + # start of the core + inlooptool = InloopTool(core_parameters) + + # Import surfaces and pipes + self.arcgis_com.AddMessage("Importeren van BGT bestanden") + inlooptool.import_surfaces(bgt_file, input_extent_mask_wkt) + self.arcgis_com.AddMessage("Importeren van GWSW bestanden") + inlooptool.import_pipes(pipe_file) + self.arcgis_com.AddMessage("Importeren van bestanden vorige run") + if previous_results_file: + inlooptool.import_results(previous_results_file) + + if core_parameters.gebruik_kolken: + self.arcgis_com.AddMessage("Importeren van kolken bestanden") + inlooptool.import_kolken(kolken_file) + inlooptool._database.add_index_to_inputs( + kolken=core_parameters.gebruik_kolken + ) + + if core_parameters.gebruik_bag: + self.arcgis_com.AddMessage("Importeren van BAG gebouw bestanden") + inlooptool._database.add_build_year_to_surface(file_path=building_file) + + if input_area is not None: + inlooptool._database.remove_input_features_outside_clip_extent( + input_extent_mask_wkt + ) + inlooptool._database.add_index_to_inputs( + kolken=core_parameters.gebruik_kolken + ) + + # Calculate results + self.arcgis_com.AddMessage("Afstanden aan het berekenen") + inlooptool.calculate_distances(parameters=core_parameters) + self.arcgis_com.AddMessage("Bereken Runoff targets") + inlooptool.calculate_runoff_targets() + if statistics_area is not None: + self.arcgis_com.AddMessage("Berekenen statistiek") + inlooptool.calculate_statistics(stats_path=statistics_area) + + # Export results + self.arcgis_com.AddMessage("Exporteren naar GPKG") + if parameters[self.copy_pipe_codes_idx].value: + gpkg_file = inlooptool._database._save_to_gpkg( + output_folder, GPKG_TEMPLATE + ) + else: + gpkg_file = inlooptool._database._save_to_gpkg( + output_folder, GPKG_TEMPLATE_HIDDEN + ) + + # Export layers to gdb amd add layers to the map + self.arcgis_com.AddMessage("Visualiseren van resultaten!") + out_gdb = os.path.join(output_folder, "output.gdb") + layers_to_visualize = [] + + # 1. Water passerende verharding en groene daken + layers_to_gdb( + input_dataset=os.path.join( + gpkg_file, "main.1_Waterpasserende_verharding_en_groene_daken" + ), + output_gdb=out_gdb, + ) + parameters[self.water_passerende_verharding_symb_idx].value = os.path.join( + gpkg_file, "main.1_Waterpasserende_verharding_en_groene_daken" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[ + self.water_passerende_verharding_symb_idx + ], + visualize_field=None, + layer_name="1. Waterpasserende verharding en groene daken", + params_idx=self.water_passerende_verharding_symb_idx, + has_symbology=True, + ) + ) + + # 2. controles + layers_to_gdb( + input_dataset=os.path.join(gpkg_file, "main.2_Te_controleren"), + output_gdb=out_gdb, + ) + parameters[self.controles_symb_idx].value = os.path.join( + gpkg_file, "main.2_Te_controleren" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[self.controles_symb_idx], + visualize_field="error_code", + layer_name="2. Controles", + params_idx=self.controles_symb_idx, + has_symbology=True, + ) + ) + + # 3. GWSW pipes + add_gwsw_symbologyfield(os.path.join(gpkg_file, "main.3_GWSW_leidingen")) + layers_to_gdb( + input_dataset=os.path.join(gpkg_file, "main.3_GWSW_leidingen"), + output_gdb=out_gdb, + ) + parameters[self.gwsw_lijn_symb_idx].value = os.path.join( + gpkg_file, "main.3_GWSW_leidingen" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[self.gwsw_lijn_symb_idx], + visualize_field="pipe_type", + layer_name="3. GWSW leidingen", + params_idx=self.gwsw_lijn_symb_idx, + has_symbology=True, + ) + ) + + # 4. add symbology field for bgt_inlooptabel + add_bgt_inlooptabel_symbologyfield( + os.path.join(gpkg_file, "main.4_BGT_inlooptabel") + ) + layers_to_gdb( + input_dataset=os.path.join(gpkg_file, "main.4_BGT_inlooptabel"), + output_gdb=out_gdb, + ) + parameters[self.bgt_inlooptabel_symb_idx].value = os.path.join( + gpkg_file, "main.4_BGT_inlooptabel" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[self.bgt_inlooptabel_symb_idx], + visualize_field="categorie", + layer_name="4. BGT inlooptabel", + params_idx=self.bgt_inlooptabel_symb_idx, + has_symbology=True, + ) + ) + + # 5. add symbology field for bgt_ppervlakken + layers_to_gdb( + input_dataset=os.path.join(gpkg_file, "main.5_BGT_oppervlakken"), + output_gdb=out_gdb, + ) + parameters[self.bgt_oppervlakken_symb_idx].value = os.path.join( + gpkg_file, "main.5_BGT_oppervlakken" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[self.bgt_oppervlakken_symb_idx], + visualize_field=None, + layer_name="5. BGT Oppervlakken", + params_idx=self.bgt_oppervlakken_symb_idx, + has_symbology=True, + ) + ) + + # 6. add symbology field for statistieken + if statistics_area is not None: + layers_to_gdb( + input_dataset=os.path.join(gpkg_file, "main.6_Statistieken"), + output_gdb=out_gdb, + ) + parameters[self.statistieken_symb_idx].value = os.path.join( + out_gdb, "main_6_Statistieken" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[self.statistieken_symb_idx], + visualize_field=None, + layer_name="6. Statistieken", + params_idx=self.statistieken_symb_idx, + has_symbology=True, + ) + ) + + # 7. add symbology field for calculation parameters + layers_to_gdb( + input_dataset=os.path.join(gpkg_file, "main.7_Rekeninstellingen"), + output_gdb=out_gdb, + ) + parameters[self.rekeninstellingen_symb_idx].value = os.path.join( + gpkg_file, "main.7_Rekeninstellingen" + ) + layers_to_visualize.append( + VisualizeLayer( + symbology_param=parameters[self.rekeninstellingen_symb_idx], + visualize_field=None, + layer_name="7. Rekeninstellingen", + params_idx=self.rekeninstellingen_symb_idx, + has_symbology=False, + ) + ) + + visualize_layers = VisualizeLayers() + layers_to_visualize.reverse() + for layer_parameter in layers_to_visualize: + arcpy.AddMessage(f"Adding layer: {layer_parameter.layer_name}") + layer = visualize_layers.add_layer_to_map(layer_parameter) + if layer_parameter.has_symbology: + arcpy.AddMessage("- Applying symbology") + visualize_layers.apply_symbology(layer_parameter, layer) + + visualize_layers.save() + + except Exception: + self.arcgis_com.Traceback() + finally: + self.arcgis_com.AddMessage("Klaar") + return + + +if __name__ == "__main__": + # This is used for debugging. Using this separated structure makes it much + # easier to debug using standard Python development tools. + + try: + tool = BGTInloopToolArcGIS() + params = tool.getParameterInfo() + + main_path = r"C:\GitHub\bgt-inlooptool\test-data\akersloot" + # bgt_file + params[1].value = os.path.join(main_path, "BGT_Akersloot.zip") + # pipe_file + params[2].value = os.path.join(main_path, "getGeoPackage_1934.gpkg") + # bag_file + params[3].value = os.path.join(main_path, "BAG_Akersloot.gpkg") + # kolken_file + params[4].value = os.path.join( + main_path, "kolken_Castricum_Limmen_Akersloot.shp" + ) + # area_file + params[5].value = os.path.join( + main_path, "extent_Akersloot.shp" + ) # os.path.join(main_path, r"polyoon_centrum.gdb\Polygoon_centrum") + # statistics area + params[6].value = os.path.join(main_path, "statistiek_gebieden_buurten.shp") + # output_location + params[7].value = r"C:\Users\vdi\Downloads\test_inlooptool" + + # # maximale afstand vlak afwateringsvoorziening + # params[6].value = 40 + # # maximale afstand vlak oppervlaktewater + # params[7].value = 2 + # # maximale afstand pand oppervlaktewater + # params[8].value = 6 + # # 'maximale afstand vlak kolk + # params[9].value = 30 + # # maximale afstand afgekoppeld + # params[10].value = 3 + # # maximale afstand drievoudig + # params[11].value = 4 + # # afkoppelen hellende daken + # params[12].value = True + # # bouwjaar gescheiden binnenhuisriolering + # params[13].value = 1992 + # # verhardingsgraad erf + # params[14].value = 50 + # # verhardingsgraad half verhard + # params[15].value = 50 + + tool.execute(parameters=params, messages=None) + + except Exception as ex: + print("iets ging fout!") diff --git a/ArcGIS_plugin/bgt_inlooptool/pyt_download_basis_data.py b/ArcGIS_plugin/bgt_inlooptool/pyt_download_basis_data.py new file mode 100644 index 0000000..946f729 --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/pyt_download_basis_data.py @@ -0,0 +1,307 @@ +""" +Script Name: Download de BGT vlakken van PDOK +Description: Download de BGT vlakken van PDOK +Created By: Sjoerd Hoekstra +Date: 29/09/2020 +""" + +import os +import sys + +import arcpy +from typing import List + +# Relative imports don't work well in arcgis, therefore paths are appended to sys +bgt_inlooptool_dir = os.path.dirname(__file__) +sys.path.append(bgt_inlooptool_dir) +sys.path.append(os.path.join(bgt_inlooptool_dir, "core")) + +# Set path to Generic modules +from helper_functions.cls_general_use import GeneralUse +from helper_functions.common import BaseTool, get_wkt_extent, parameter +from helper_functions.download_apis import ( + get_bag_features, + get_bgt_features, + get_gwsw_features, +) + + +def enable_disable_options( + parameters: List[arcpy.Parameter], bool_idx: int, input_field_idx: int +): + """Enable or disable options based on another boolean field + + Args: + parameters (List[arcpy.Parameter]): A list of all parameters used in the tool + bool_idx (int): The index of the bool field in the parameters list + input_field_idx (int): The index of the field to update in the parameters list + """ + if parameters[bool_idx].value is True: + parameters[input_field_idx].enabled = True + # parameters[input_field_idx].parameterType = "Required" + else: + parameters[input_field_idx].enabled = False + # parameters[input_field_idx].parameterType = None + + +def add_extension_to_path( + parameters: List[arcpy.Parameter], input_field_idx: int, extension: str +): + """Update and file input with the correct extension + + Args: + parameters (List[arcpy.Parameter]): A list of all parameters used in the tool + input_field_idx (int): The index of the parameter to update + extension (str): the expected extension + """ + if parameters[input_field_idx].altered: + if "." in parameters[input_field_idx].valueAsText: + parameters[input_field_idx].value = ( + parameters[input_field_idx].valueAsText.split(".")[0] + extension + ) + else: + parameters[input_field_idx].value = ( + parameters[input_field_idx].valueAsText + extension + ) + + +def check_if_file_already_exists( + parameters: List[arcpy.Parameter], input_field_idx: int +): + """Check if the indicated output file already exists and give an error + + Args: + parameters (List[arcpy.Parameter]): A list of all parameters used in the tool + input_field_idx (int): The index of the parameter to check + """ + if parameters[input_field_idx].altered: + if os.path.exists(parameters[input_field_idx].valueAsText): + parameters[input_field_idx].setWarningMessage( + "Het outputbestand bestaat al, kies een nieuwe naam!" + ) + else: + parameters[input_field_idx].clearMessage() + + +class DownloadBasisData(BaseTool): + def __init__(self): + """ + Initialization. + + """ + self.label = "1. Download de basis data" + self.description = """Download de basis data benodigd voor de tool""" + self.canRunInBackground = True + + parameter_names = [ + "interesse_gebied", + "bgt_download_bool", + "bgt_zip_path", + "gwsw_download_bool", + "gwsw_zip_path", + "bag_download_bool", + "bag_zip_path", + ] + + self.search_area_idx = parameter_names.index("interesse_gebied") + self.bgt_download_bool_idx = parameter_names.index("bgt_download_bool") + self.bgt_storage_path_idx = parameter_names.index("bgt_zip_path") + self.gwsw_download_bool_idx = parameter_names.index("gwsw_download_bool") + self.gwsw_storage_path_idx = parameter_names.index("gwsw_zip_path") + self.bag_download_bool_idx = parameter_names.index("bag_download_bool") + self.bag_storage_path_idx = parameter_names.index("bag_zip_path") + + def getParameterInfo(self): + """Create your parameters here using the paramater function. + Make sure you leave the enclosing brackets and separate your + parameters using commas. + parameter(displayName, name, datatype, defaultValue=None, parameterType='Required', direction='Input') + """ + + search_area = parameter( + displayName="Interesse gebied als polygon", + name="interesse_gebied", + datatype="GPFeatureLayer", + parameterType="Required", + direction="Input", + ) + + bgt_download_bool = parameter( + displayName="Download BGT", + name="bgt_download_bool", + datatype="GPBoolean", + parameterType="Required", + direction="Input", + ) + bgt_download_bool.value = True + + bgt_storage_path = parameter( + displayName="BGT download als zipfile van PDOK", + name="bgt_zip_path", + datatype="DEFile", + parameterType="Optional", + direction="Output", + ) + + gwsw_download_bool = parameter( + displayName="Download GWSW leidingen", + name="gwsw_download_bool", + datatype="GPBoolean", + parameterType="Required", + direction="Input", + ) + gwsw_download_bool.value = True + + gwsw_storage_path = parameter( + displayName="GWSW download als .gpkg van PDOK", + name="gwsw_zip_path", + datatype="DEFile", + parameterType="Optional", + direction="Output", + ) + + bag_download_bool = parameter( + displayName="Download BAG panden", + name="bag_download_bool", + datatype="GPBoolean", + parameterType="Required", + direction="Input", + ) + bag_download_bool.value = True + + bag_storage_path = parameter( + displayName="BAG panden download als .gpkg van PDOK", + name="bag_zip_path", + datatype="DEFile", + parameterType="Optional", + direction="Output", + ) + + return [ + search_area, + bgt_download_bool, + bgt_storage_path, + gwsw_download_bool, + gwsw_storage_path, + bag_download_bool, + bag_storage_path, + ] + + def updateParameters(self, parameters): + """ + updates a parameter in the interface if specified + """ + + # Set correct path + add_extension_to_path(parameters, self.bgt_storage_path_idx, ".zip") + add_extension_to_path(parameters, self.gwsw_storage_path_idx, ".gpkg") + add_extension_to_path(parameters, self.bag_storage_path_idx, ".gpkg") + + # Enable/disable BGT parameters + enable_disable_options( + parameters, self.bgt_download_bool_idx, self.bgt_storage_path_idx + ) + + # Enable/disable GWSW parameters + enable_disable_options( + parameters, self.gwsw_download_bool_idx, self.gwsw_storage_path_idx + ) + + # Enable/disable BAG parameters + enable_disable_options( + parameters, self.bag_download_bool_idx, self.bag_storage_path_idx + ) + + super(DownloadBasisData, self).updateParameters(parameters) + + def updateMessages(self, parameters): + """ + returns messages in the interface the wrong paths are filled in for the different parameters + """ + # Messages interesse gebied + if parameters[self.search_area_idx].altered: + desc = arcpy.Describe(parameters[self.search_area_idx].valueAsText) + if desc.dataType not in ["FeatureClass", "FeatureLayer", "ShapeFile"]: + parameters[self.search_area_idx].setErrorMessage( + "De invoer is niet van het type featureclass/shapefile/gpkg layer!" + ) + else: + if desc.shapeType != "Polygon": + parameters[self.search_area_idx].setErrorMessage( + "De featureclass/shapefile/gpkg layer is niet van het type polygoon!" + ) + else: + feature_count = int( + arcpy.management.GetCount( + parameters[self.search_area_idx].valueAsText + ).getOutput(self.search_area_idx) + ) + if feature_count != 1: + parameters[self.search_area_idx].setErrorMessage( + "Er is meer of minder dan 1 feature aanwezig of geselecteerd!" + ) + + # Validate zip files + check_if_file_already_exists(parameters, self.bgt_storage_path_idx) + check_if_file_already_exists(parameters, self.gwsw_storage_path_idx) + check_if_file_already_exists(parameters, self.bag_storage_path_idx) + + super(DownloadBasisData, self).updateMessages(parameters) + + def execute(self, parameters, messages): + try: + self.arcgis_com = GeneralUse(sys, arcpy) + self.arcgis_com.StartAnalyse() + + # get the input extent as wkt from the input_area + input_area = parameters[self.search_area_idx].valueAsText + extent_wkt = get_wkt_extent(input_area) + + if parameters[self.bgt_download_bool_idx].value: + self.arcgis_com.AddMessage("Start downloading BGT!") + bgt_output = parameters[self.bgt_storage_path_idx].valueAsText + get_bgt_features(extent_wkt, bgt_output) + + if parameters[self.gwsw_download_bool_idx].value: + self.arcgis_com.AddMessage("Start downloading GWSW!") + gwsw_output = parameters[self.gwsw_storage_path_idx].valueAsText + get_gwsw_features(extent_wkt, gwsw_output) + + if parameters[self.bag_download_bool_idx].value: + self.arcgis_com.AddMessage("Start downloading BAG!") + bag_output = parameters[self.bag_storage_path_idx].valueAsText + get_bag_features(extent_wkt, bag_output) + + except Exception: + self.arcgis_com.Traceback() + finally: + self.arcgis_com.AddMessage("Klaar") + return + + +if __name__ == "__main__": + # This is used for debugging. Using this separated structure makes it much + # easier to debug using standard Python development tools. + + try: + tool = DownloadBasisData() + params = tool.getParameterInfo() + + params[0].value = r"C:\Users\vdi\Downloads\test_inlooptool\testdata.gdb\extent" + + # BGT + params[1].value = True + params[2].value = r"C:\Users\vdi\Downloads\test_inlooptool\brondata\bgt.zip" + + # GWSW + params[3].value = False + params[4].value = r"C:\Users\vdi\Downloads\test_inlooptool\brondata\gwsw.gpkg" + + # BAG + params[5].value = False + params[6].value = r"C:\Users\vdi\Downloads\test_inlooptool\brondata\bag.gpkg" + + tool.execute(parameters=params, messages=None) + + except Exception as ex: + print("iets ging fout!") diff --git a/ArcGIS_plugin/bgt_inlooptool/rtree_installer.py b/ArcGIS_plugin/bgt_inlooptool/rtree_installer.py new file mode 100644 index 0000000..37707ee --- /dev/null +++ b/ArcGIS_plugin/bgt_inlooptool/rtree_installer.py @@ -0,0 +1,33 @@ +import sys +from pathlib import Path + +def ensure_rtree_install(): + current_dir = Path(__file__).parent + custom_lib_dir = current_dir / "custom_libs" + custom_lib_dir.mkdir(exist_ok=True) + if not str(custom_lib_dir) in sys.path: + sys.path.insert(0, str(custom_lib_dir)) # Note: prepend, not append! + + try: + import rtree + return + except ImportError: + from core import rtree_installer + search_path = current_dir / "core" / "whls" + wheel_filename = rtree_installer.get_wheel_filename( + search_path=search_path, + distribution="Rtree", + python_tag_prefix="cp", + abi_tag_suffix="m", + ) + rtree_installer.unpack_whl( + wheel_filename, + package_name="rtree", + extract_dir=custom_lib_dir + ) + # Re-try import + try: + import rtree + return + except ImportError: + raise \ No newline at end of file diff --git a/ArcGIS_plugin/bgt_inlooptool/visualize_layers.py b/ArcGIS_plugin/bgt_inlooptool/visualize_layers.py deleted file mode 100644 index 3bad1b6..0000000 --- a/ArcGIS_plugin/bgt_inlooptool/visualize_layers.py +++ /dev/null @@ -1,44 +0,0 @@ -import arcpy -from cls_general_use import GeneralUse - - -class VisualizeLayers: - def __init__(self, arcgis_project=None) -> None: - - if arcgis_project is None: - self.arcgis_project = arcpy.mp.ArcGISProject("CURRENT") - self.map = self.arcgis_project.activeMap - else: - self.arcgis_project = arcpy.mp.ArcGISProject(arcgis_project) - self.map = self.arcgis_project.listMaps()[0] - - self.arcgis_com = GeneralUse() - - def save(self): - self.arcgis_project.save() - - def add_layer_to_map( - self, in_param, in_dataset=None, param_nr=None, symbology_layer=None - ): - """ - Add layers to map with symbology if a symbology layer is specified - """ - try: - # add data to the map - output_layer = self.map.addDataFromPath(in_param.valueAsText) - - # add symbology if it is available - if in_param.symbology is not None: - layer_file = arcpy.mp.LayerFile(in_param.symbology) - for layer in layer_file.listLayers(): - sym_layer = layer - break - else: - sym_layer = layer_file - output_layer.name = sym_layer.name - arcpy.ApplySymbologyFromLayer_management(output_layer, sym_layer) - arcpy.SetParameterAsText(param_nr, output_layer) - # https://support.esri.com/en/bugs/nimbus/QlVHLTAwMDExOTkwNw== - # workaround works when parameter 16 is defined as a layer and as parameterType Derived - except Exception: - self.arcgis_com.Traceback() diff --git a/QGIS_plugin/bgtinlooptool/BGTInloopTool.py b/QGIS_plugin/bgtinlooptool/BGTInloopTool.py index e2d862e..1fa3e47 100644 --- a/QGIS_plugin/bgtinlooptool/BGTInloopTool.py +++ b/QGIS_plugin/bgtinlooptool/BGTInloopTool.py @@ -9,7 +9,8 @@ begin : 2020-08-12 git sha : $Format:%H$ copyright : (C) 2020 by Leendert van Wolfswinkel, Emile de Badts - email : emile.debadts@nelen-schuurmans.nl + update : (C) 2025 by Ruben van der Zaag + email : bgtinlooptool@nelen-schuurmans.nl ***************************************************************************/ /*************************************************************************** @@ -23,28 +24,30 @@ """ import os.path -import sys +#import sys import json -from PyQt5.QtCore import QUrl, QByteArray -from PyQt5.QtNetwork import QNetworkRequest -from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication +from PyQt5.QtCore import Qt, QUrl, QByteArray, QEventLoop +from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager#, QNetworkReply from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtWidgets import QAction from qgis.core import ( QgsProject, + QgsVectorLayer, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsBlockingNetworkRequest, -) -from qgis.core import ( + QgsWkbTypes, QgsTask, Qgis, QgsApplication, QgsMessageLog, + QgsLayerTreeLayer, ) + from qgis.utils import iface +from osgeo import ogr, osr # Initialize Qt resources from file resources.py from .resources import * @@ -55,17 +58,36 @@ # Import the BGT Inlooptool core -sys.path.append(os.path.dirname(os.path.realpath(__file__))) -from core.inlooptool import * -from core.constants import * -from .ogr2qgis import * +from bgtinlooptool.core.inlooptool import * +from bgtinlooptool.core.defaults import ( + MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, + MAX_AFSTAND_VLAK_OPPWATER, + MAX_AFSTAND_PAND_OPPWATER, + MAX_AFSTAND_VLAK_KOLK, + MAX_AFSTAND_AFGEKOPPELD, + MAX_AFSTAND_DRIEVOUDIG, + AFKOPPELEN_HELLENDE_DAKEN, + KOPPEL_LEIDINGCODES, + BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, + VERHARDINGSGRAAD_ERF, + VERHARDINGSGRAAD_HALF_VERHARD, + ) +from bgtinlooptool.ogr2qgis import * from bgtinlooptool.constants import ( MESSAGE_CATEGORY, BGT_API_URL, + BAG_API_URL, + CBS_GEMEENTES_API_URL, INLOOPTABEL_STYLE, + INLOOPTABEL_STYLE_HIDDEN, PIPES_STYLE, BGT_STYLE, + STATS_STYLE, + CHECKS_STYLE, + GPKG_TEMPLATE, + GPKG_TEMPLATE_HIDDEN, + NOT_FOUND_GEMEENTES, ) @@ -79,6 +101,10 @@ def __init__( building_file, kolken_file, input_extent_mask_wkt, + stats_file, + results_file, + temp_QGIS_layers, + output_folder, ): super().__init__(description, QgsTask.CanCancel) @@ -94,17 +120,27 @@ def __init__( self.pipe_file = pipe_file self.building_file = building_file self.kolken_file = kolken_file + self.results_file = results_file + self.stats_file = stats_file + self.output_folder = output_folder + self.temp_QGIS_layers = temp_QGIS_layers self.input_extent_mask_wkt = input_extent_mask_wkt self.exception = None self.setProgress(0) - self.total_progress = 5 + self.total_progress = 7 if self.parameters.gebruik_kolken: self.total_progress += 1 if self.parameters.gebruik_bag: self.total_progress += 1 if self.input_extent_mask_wkt is not None: self.total_progress += 1 - + if not self.temp_QGIS_layers: + self.total_progress += 1 + if self.parameters.gebruik_resultaten: + self.total_progress += 1 + if self.parameters.gebruik_statistieken: + self.total_progress += 1 + def increase_progress(self): self.setProgress(self.progress() + 100 / self.total_progress) @@ -113,15 +149,30 @@ def run(self): QgsMessageLog.logMessage( "Started inlooptool task", MESSAGE_CATEGORY, level=Qgis.Info ) + self.it = InloopTool(self.parameters) self.increase_progress() - + + if self.parameters.gebruik_resultaten: + QgsMessageLog.logMessage( + "Importing the results of the previous run", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.import_results(self.results_file) + + QgsMessageLog.logMessage( + "Saving the settings of the run", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.set_settings_start(self.bgt_file,self.pipe_file, self.building_file, self.kolken_file) + + self.increase_progress() + QgsMessageLog.logMessage( "Importing surfaces", MESSAGE_CATEGORY, level=Qgis.Info ) - self.it.import_surfaces(self.bgt_file) + self.it.import_surfaces(self.bgt_file,self.input_extent_mask_wkt) self.increase_progress() + QgsMessageLog.logMessage( "Importing pipes", MESSAGE_CATEGORY, level=Qgis.Info ) @@ -169,7 +220,7 @@ def run(self): self.it._database.add_index_to_inputs( kolken=self.parameters.gebruik_kolken ) - + QgsMessageLog.logMessage( "Calculating distances", MESSAGE_CATEGORY, level=Qgis.Info ) @@ -180,38 +231,93 @@ def run(self): "Calculating runoff targets", MESSAGE_CATEGORY, level=Qgis.Info ) self.it.calculate_runoff_targets() + + QgsMessageLog.logMessage( + "Keeping manual edit on BGT ID", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.overwrite_by_manual_edits() + + QgsMessageLog.logMessage( + "Updating type verharding for infiltrating pavement and green roofs if provided", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.intersect_inf_pavement_green_roofs() + self.increase_progress() + + if self.parameters.gebruik_statistieken: + QgsMessageLog.logMessage( + "Calculating statistics", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.calculate_statistics(self.stats_file) + self.increase_progress() + + QgsMessageLog.logMessage( + "Saving the end time of the analysis in the settings", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.set_settings_end() + + QgsMessageLog.logMessage( + "Generating warning messages", MESSAGE_CATEGORY, level=Qgis.Info + ) + self.it.generate_warnings() + + if not self.temp_QGIS_layers: + QgsMessageLog.logMessage( + "Saving as gpkg", MESSAGE_CATEGORY, level=Qgis.Info + ) + if self.parameters.leidingcodes_koppelen: + self.it._database._save_to_gpkg(self.output_folder,GPKG_TEMPLATE) + else: + self.it._database._save_to_gpkg(self.output_folder,GPKG_TEMPLATE_HIDDEN) + self.increase_progress() QgsMessageLog.logMessage("Finished", MESSAGE_CATEGORY, level=Qgis.Success) + return True + except Exception as e: self.exception = e return False def finished(self, result): - if result: - root = QgsProject.instance().layerTreeRoot() - layer_group = root.insertGroup(0, MESSAGE_CATEGORY) - - self.add_to_layer_group( - db_layer_name=SURFACES_TABLE_NAME, - layer_tree_layer_name="BGT Oppervlakken", - qml=BGT_STYLE, - layer_group=layer_group, - ) - self.add_to_layer_group( - db_layer_name=RESULT_TABLE_NAME, - layer_tree_layer_name="BGT Inlooptabel", - qml=INLOOPTABEL_STYLE, - layer_group=layer_group, - ) - self.add_to_layer_group( - db_layer_name=PIPES_TABLE_NAME, - layer_tree_layer_name="GWSW Leidingen", - qml=PIPES_STYLE, - layer_group=layer_group, - ) + if self.temp_QGIS_layers: + file_name = "BGT_inlooptabel" + layer_group = QgsProject.instance().layerTreeRoot().addGroup(file_name) + self.temp_to_layer_group(db_layer_name=STATISTICS_TABLE_NAME,layer_tree_layer_name="Statistieken", qml=STATS_STYLE,layer_group=layer_group) + self.temp_to_layer_group(db_layer_name=SURFACES_TABLE_NAME, layer_tree_layer_name="BGT Oppervlakken",qml=BGT_STYLE,layer_group=layer_group) + if self.parameters.leidingcodes_koppelen: + self.temp_to_layer_group(db_layer_name=RESULT_TABLE_NAME, layer_tree_layer_name="BGT Inlooptabel",qml=INLOOPTABEL_STYLE,layer_group=layer_group) + else: + self.temp_to_layer_group(db_layer_name=RESULT_TABLE_NAME, layer_tree_layer_name="BGT Inlooptabel",qml=INLOOPTABEL_STYLE_HIDDEN,layer_group=layer_group) + self.temp_to_layer_group(db_layer_name=PIPES_TABLE_NAME,layer_tree_layer_name="GWSW Leidingen", qml=PIPES_STYLE,layer_group=layer_group) + self.temp_to_layer_group(db_layer_name=CHECKS_TABLE_NAME,layer_tree_layer_name="Te_controleren", qml=CHECKS_STYLE,layer_group=layer_group) + + # Turn off visibility for "Statistieken" and "Te_controleren" layers + for child in layer_group.children(): + if isinstance(child, QgsLayerTreeLayer): + if child.name() in ["Te_controleren","Statistieken"]: + child.setItemVisibilityChecked(False) + + else: # Load from file + gpkg_files = [f for f in os.listdir(self.output_folder) if f.endswith(".gpkg")] + file_name = max(gpkg_files, key=lambda f: os.path.getmtime(os.path.join(self.output_folder, f))) + layer_group = QgsProject.instance().layerTreeRoot().addGroup(file_name[:-5]) + gpkg_path = os.path.join(self.output_folder, file_name) + self.gpkg_to_layer_group(gpkg_path, "7_Rekeninstellingen", layer_group) + self.gpkg_to_layer_group(gpkg_path, "6_Statistieken", layer_group) + self.gpkg_to_layer_group(gpkg_path, "5_BGT_oppervlakken", layer_group) + self.gpkg_to_layer_group(gpkg_path, "4_BGT_inlooptabel", layer_group) + self.gpkg_to_layer_group(gpkg_path, "3_GWSW_leidingen", layer_group) + self.gpkg_to_layer_group(gpkg_path, "2_Te_controleren", layer_group) + self.gpkg_to_layer_group(gpkg_path, "1_Waterpasserende_verharding_en_groene_daken", layer_group) + + # Turn off visibility for "Statistieken" and "Te_controleren" layers + for child in layer_group.children(): + if isinstance(child, QgsLayerTreeLayer): + if child.name() in ["1_Waterpasserende_verharding_en_groene_daken","2_Te_controleren","6_Statistieken"]: + child.setItemVisibilityChecked(False) + iface.messageBar().pushMessage( MESSAGE_CATEGORY, "Afwateringskenmerken BGT bepaald!", @@ -244,7 +350,7 @@ def cancel(self): ) super().cancel() - def add_to_layer_group( + def temp_to_layer_group( self, db_layer_name: str, layer_tree_layer_name: str, qml: str, layer_group ): ogr_lyr = self.it._database.mem_database.GetLayerByName(db_layer_name) @@ -255,7 +361,312 @@ def add_to_layer_group( project.addMapLayer(qgs_lyr, addToLegend=False) layer_group.insertLayer(0, qgs_lyr) qgs_lyr.loadNamedStyle(qml) - qgs_lyr.triggerRepaint() + qgs_lyr.triggerRepaint() + + def gpkg_to_layer_group(self,gpkg_path: str, gpkg_layer_name: str, layer_group): + # Construct the data source URI for the GeoPackage + uri = f"{gpkg_path}|layername={gpkg_layer_name}" + + # Create a QgsVectorLayer object + qgs_lyr = QgsVectorLayer(uri, gpkg_layer_name, "ogr") + + if qgs_lyr.isValid(): + project = QgsProject.instance() + project.addMapLayer(qgs_lyr, addToLegend=False) + layer_group.insertLayer(0, qgs_lyr) + else: + print(f"Failed to load layer '{gpkg_layer_name}' from '{gpkg_path}'.") + +class NetworkTask(QgsTask): + def __init__(self, url, output_gpkg,extent_bbox,extent_geometry_wkt,layer_name): + super().__init__("Download and Convert Data") + self.url = url + self.output_gpkg = output_gpkg + self.extent_bbox = extent_bbox + self.extent_geometry_wkt = extent_geometry_wkt + self.layer_name = layer_name + self.nam = QNetworkAccessManager() # Create a network access manager + self.setProgress(0) + if layer_name != "bag_panden": + self.total_progress = 4 + else: + self.total_progress = 10 + + def increase_progress(self): + self.setProgress(self.progress() + 100 / self.total_progress) + + def run(self): + extent_geometry = ogr.CreateGeometryFromWkt(self.extent_geometry_wkt).Buffer(-0.5) # Give the extent geometry a negative buffer of 0.5m, so that the intersect function works properly (when equal, no neighbouring geometries are used) + shrunk_extent_geometry_wkt = extent_geometry.ExportToWkt() + shrunk_extent_geometry_coordinates = shrunk_extent_geometry_wkt[shrunk_extent_geometry_wkt.find('((')+2:shrunk_extent_geometry_wkt.find('))')] + bbox = self.wkt_to_bbox() + if self.layer_name != "bag_panden": #GWSW download: looks for names of municipalities first. Then uses these to download the right data. + self.increase_progress() + all_features = self.fetch_all_features_gwsw(shrunk_extent_geometry_coordinates) + + else: + all_features = self.fetch_all_features_bag(bbox) + self.increase_progress() + self.save_features_to_gpkg(all_features, extent_geometry) + return True + + def fetch_all_features_gwsw(self, extent_geometry): + not_all_features_found = True + index = 0 + all_features = [] + + print("Fetching features within extent") + while not_all_features_found: + request_url = self.url + f"&startIndex={index}" + f"&Intersects={extent_geometry}" + print(request_url) + response_text = self.load_api_data(request_url, "") + data = json.loads(response_text) + + all_features.extend(data['features']) + + if len(data['features']) < 1000: + not_all_features_found = False + else: + index += 1000 + + return all_features + + def fetch_all_features_bag(self, bbox): + not_all_features_found = True + index = 0 + all_features = [] + + print("Fetching features within BBox") + while not_all_features_found: + request_url = self.url + f"&startIndex={index}" + f"&BBOX={bbox}" + response_text = self.load_api_data(request_url, "") + data = json.loads(response_text) + + all_features.extend(data['features']) + + if len(data['features']) < 1000: + not_all_features_found = False + else: + index += 1000 + + return all_features + + def load_api_data(self, url,gemeente): + request = QNetworkRequest(QUrl(url)) + reply = self.nam.get(request) + + loop = QEventLoop() + reply.finished.connect(loop.quit) + loop.exec_() + + response_text = reply.readAll().data().decode("utf-8") + if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 404: + print(f"Error 404: {gemeente} not found.") + return None + + return response_text + + def save_features_to_gpkg(self, all_features, extent_geometry): + print("Saving features to GeoPackage") + + driver = ogr.GetDriverByName("GPKG") + if os.path.exists(self.output_gpkg): + driver.DeleteDataSource(self.output_gpkg) + datasource = driver.CreateDataSource(self.output_gpkg) + + srs = osr.SpatialReference() + srs.ImportFromEPSG(28992) + + if self.layer_name != "bag_panden": + all_features = self.filter_features_by_extent(all_features, extent_geometry) + all_features = self.fetch_gwsw_data(all_features) + all_features = self.remove_duplicate_gwsw_features(all_features) + self.num_features_per_step = round(len(all_features)/(self.total_progress-2),0) + else: + self.num_features_per_step = round(len(all_features)/(self.total_progress-1),0) + + + layer_out = self.create_layer(datasource, srs) + self.add_features_to_layer(layer_out, all_features, extent_geometry) + datasource = None + + def filter_features_by_extent(self, all_features, extent_geometry): + selection_gemeentes = [] + + for feature in all_features: + geometry_wkt = self.geojson_to_wkt(feature['geometry']) + geojson_geom = ogr.CreateGeometryFromWkt(geometry_wkt) + if extent_geometry.Intersects(geojson_geom): + selection_gemeentes.append(feature['properties']['naam']) + + return selection_gemeentes + + def fetch_gwsw_data(self, selection_gemeentes): + all_features = [] + + for gemeente_name in selection_gemeentes: + gemeente_name = gemeente_name.title().replace(" ", "").replace("-", "") + gemeente_name = gemeente_name[0].upper() + gemeente_name[1:].lower() + not_all_features_found = True + index = 0 + print(f"Extracting data for gemeente {gemeente_name}") + + while not_all_features_found: + request_url = f"https://geodata.gwsw.nl/geoserver/{gemeente_name}-default/wfs/?&request=GetFeature&typeName={gemeente_name}-default:default_lijn&srsName=epsg:28992&OutputFormat=application/json" + (f"&startIndex={index}" if index > 0 else "") + response_text = self.load_api_data(request_url,gemeente_name) + if response_text is None: + NOT_FOUND_GEMEENTES.append(gemeente_name) + break + + data = json.loads(response_text) + all_features.extend(data['features']) + + if len(data['features']) < 1000: + not_all_features_found = False + else: + index += 1000 + + return all_features + + def remove_duplicate_gwsw_features(self, gwsw_features): + seen = set() # Set to keep track of already encountered (uri, name) pairs + unique_features = [] + + for feature in gwsw_features: + uri = feature['properties'].get('uri') # Extract URI + name = feature['properties'].get('naam') # Extract name + + # Check if both 'uri' and 'name' exist and are unique + if uri and name and (uri, name) not in seen: + seen.add((uri, name)) # Mark this (uri, name) as seen + unique_features.append(feature) # Keep the feature + + return unique_features + + def create_layer(self, datasource, srs): + if self.layer_name == "bag_panden": + return datasource.CreateLayer(self.layer_name, geom_type=ogr.wkbPolygon, srs=srs) + else: + return datasource.CreateLayer(self.layer_name, geom_type=ogr.wkbMultiLineString, srs=srs) + + def add_features_to_layer(self, layer_out, all_features, extent_geometry): + if not all_features: + return + + feature_example = all_features[0] + feature_fields = list(feature_example['properties'].keys()) + + for field_name in feature_fields: + field_defn = ogr.FieldDefn(field_name, ogr.OFTString) # Adjust field type as needed + layer_out.CreateField(field_defn) + + layer_defn = layer_out.GetLayerDefn() + + print("Writing features to GeoPackage") + feature_count = 0 + for feature_data in all_features: + feature_count += 1 + if feature_count == self.num_features_per_step: + self.increase_progress() + feature_count = 0 + geometry_wkt = self.geojson_to_wkt(feature_data['geometry']) + geojson_geom = ogr.CreateGeometryFromWkt(geometry_wkt) + if extent_geometry.Intersects(geojson_geom): + out_feature = ogr.Feature(layer_defn) + geometry = ogr.CreateGeometryFromJson(json.dumps(feature_data['geometry'])) + out_feature.SetGeometry(geometry) + + for field_name, field_value in feature_data['properties'].items(): + field_index = layer_defn.GetFieldIndex(field_name) + if field_index != -1: + out_feature.SetField(field_name, field_value) + layer_out.CreateFeature(out_feature) + out_feature = None + + def wkt_to_bbox(self): + # Format the BBOX string + bbox = f"{self.extent_bbox.xMinimum()},{self.extent_bbox.yMinimum()},{self.extent_bbox.xMaximum()},{self.extent_bbox.yMaximum()}" + return bbox + + def geojson_to_wkt(self,geojson): + geom = ogr.CreateGeometryFromJson(str(geojson)) + return geom.ExportToWkt() + + +class DownloadBGTTask(QgsTask): + def __init__(self, dlg, extent_layer, output_zip, extent_geometry_wkt): + super().__init__("Download BGT Data") + self.dlg = dlg + self.total_progress = 3 + self.setProgress(0) + self.extent_layer = extent_layer + self.output_zip = output_zip + self.extent_geometry_wkt = extent_geometry_wkt + + def increase_progress(self): + self.setProgress(self.progress() + 100 / self.total_progress) + + def run(self): + nam = QgsBlockingNetworkRequest() + networkrequest = QNetworkRequest(QUrl.fromUserInput(BGT_API_URL)) + networkrequest.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") + + data = { + "featuretypes": list(ALL_USED_SURFACE_TYPES), + "format": "gmllight", + "geofilter": self.extent_geometry_wkt, + } + + data_array = QByteArray() + data_array.append(json.dumps(data)) + + # Step 1: Send initial API request + response = nam.post(networkrequest, data_array) + + if response > 0: # In case of a response error (0 = valid response) + self.extent_geometry_wkt = self.get_bounding_box_from_wkt(self.extent_geometry_wkt) + data["geofilter"] = self.extent_geometry_wkt # Update the data with the new geometry + + data_array.clear() # Clear previous data + data_array.append(json.dumps(data)) # Append new data with the bounding box + + # Send the new request + response = nam.post(networkrequest, data_array) + + # Update progress + self.increase_progress() + + # Step 2: Poll for download status + response_bytes = bytes(nam.reply().content()) + response_json = json.loads(response_bytes.decode("ascii")) + download_id = response_json["downloadRequestId"] + status_link = BGT_API_URL + "/" + download_id + "/status" + + status = "PENDING" + while status != "COMPLETED": + status_request = QNetworkRequest(QUrl.fromUserInput(status_link)) + status_response = nam.get(status_request) + status_response_bytes = bytes(nam.reply().content()) + status_response_json = json.loads(status_response_bytes.decode("ascii")) + status = status_response_json["status"] + time.sleep(5) + + # Update progress + self.increase_progress() + + # Step 3: Download the data + download_url_extract = status_response_json["_links"]["download"]["href"] + download_url = "https://api.pdok.nl" + download_url_extract + + download_request = QNetworkRequest(QUrl.fromUserInput(download_url)) + download_response = nam.get(download_request) + with open(self.output_zip, "wb") as f: + f.write(nam.reply().content()) + + # Update progress + self.increase_progress() + + return True class BGTInloopTool: @@ -381,7 +792,25 @@ def unload(self): for action in self.actions: self.iface.removePluginMenu("&BGT Inlooptool", action) self.iface.removeToolBarIcon(action) - + + def reset_parameters(self): + """ Resetting Setting to defaults""" + self.dlg.max_afstand_vlak_afwateringsvoorziening.setValue( + MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING + ) + self.dlg.max_afstand_vlak_oppwater.setValue(MAX_AFSTAND_VLAK_OPPWATER) + self.dlg.max_afstand_pand_oppwater.setValue(MAX_AFSTAND_PAND_OPPWATER) + self.dlg.max_afstand_vlak_kolk.setValue(MAX_AFSTAND_VLAK_KOLK) + self.dlg.max_afstand_afgekoppeld.setValue(MAX_AFSTAND_AFGEKOPPELD) + self.dlg.max_afstand_drievoudig.setValue(MAX_AFSTAND_DRIEVOUDIG) + self.dlg.bouwjaar_gescheiden_binnenhuisriolering.setValue( + BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING + ) + self.dlg.verhardingsgraad_erf.setValue(VERHARDINGSGRAAD_ERF) + self.dlg.verhardingsgraad_half_verhard.setValue(VERHARDINGSGRAAD_HALF_VERHARD) + self.dlg.afkoppelen_hellende_daken.setChecked(AFKOPPELEN_HELLENDE_DAKEN) + self.dlg.leidingcodes_koppelen.setChecked(KOPPEL_LEIDINGCODES) + def validate_extent_layer(self, extent_layer): # Check feature count in the selected layer @@ -413,14 +842,20 @@ def validate_extent_layer(self, extent_layer): selected_feature = extent_layer.selectedFeatures()[0] extent_geometry = selected_feature.geometry() elif extent_feature_count > 1: - self.iface.messageBar().pushMessage( - MESSAGE_CATEGORY, - "Laag voor gebiedsselectie bevat meer dan één polygoon / feature. " - "Selecteer er maximaal één en probeer opnieuw.", - level=Qgis.Warning, - duration=10, - ) - return False + geometries = [] + for feat in extent_layer.getFeatures(): + geometries.append(feat.geometry()) + + # Use QgsGeometry.unaryUnion to dissolve the geometries + if geometries: + dissolved_geometry = QgsGeometry.unaryUnion(geometries) + extent_geometry = dissolved_geometry + QgsMessageLog.logMessage( + f"Dissolved {extent_feature_count} features into one multipolygon.", + MESSAGE_CATEGORY, + level=Qgis.Info, + ) + elif extent_feature_count == 0: self.iface.messageBar().pushMessage( MESSAGE_CATEGORY, @@ -444,7 +879,15 @@ def validate_extent_layer(self, extent_layer): level=Qgis.Warning, ) return False - + + if QgsWkbTypes.hasZ(extent_geometry.wkbType()): + self.iface.messageBar().pushMessage( + MESSAGE_CATEGORY, + "Laag voor gebiedsselectie is een 3D geometrie (MultipolygonZ). " + "Converteer het naar een 2D geometrie en probeer opnieuw.", + level=Qgis.Warning, + ) + if reproject: out_crs = QgsCoordinateReferenceSystem("EPSG:28992") transform = QgsCoordinateTransform( @@ -457,80 +900,187 @@ def validate_extent_layer(self, extent_layer): return extent_geometry_wkt + def get_bounding_box_from_wkt(self,wkt_string): + # Create a QgsGeometry from the WKT + geometry = QgsGeometry.fromWkt(wkt_string) + + # Check if the geometry is a valid MultiPolygon + if geometry.isMultipart(): + # Get the bounding box of the geometry (this works for MultiPolygon too) + bbox = geometry.boundingBox() + + # Convert the bounding box into a WKT string (as a polygon with 1 ring) + bbox_wkt = f"POLYGON(({bbox.xMinimum()} {bbox.yMinimum()}, {bbox.xMaximum()} {bbox.yMinimum()}, {bbox.xMaximum()} {bbox.yMaximum()}, {bbox.xMinimum()} {bbox.yMaximum()}, {bbox.xMinimum()} {bbox.yMinimum()}))" + + return bbox_wkt + else: + return wkt_string # If it's not a MultiPolygon, return the original WKT + def download_bgt_from_api(self): - + # Step 1: Validate extent layer extent_layer = self.dlg.BGTExtentCombobox.currentLayer() output_zip = self.dlg.bgtApiOutput.filePath() extent_geometry_wkt = self.validate_extent_layer(extent_layer) if not extent_geometry_wkt: - return - + return False + + # Notify user and initialize network request self.iface.messageBar().pushMessage( MESSAGE_CATEGORY, f"Begonnen met downloaden van BGT lagen naar {output_zip}", level=Qgis.Info, duration=5, ) - self.iface.mainWindow().repaint() # to show the message before the task starts - - # Use the extent geometry to extract surfaces for the given extent - nam = QgsBlockingNetworkRequest() - - networkrequest = QNetworkRequest(QUrl.fromUserInput(BGT_API_URL)) - networkrequest.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") - - data = { - "featuretypes": list(ALL_USED_SURFACE_TYPES), - "format": "gmllight", - "geofilter": extent_geometry_wkt, - } - - data_array = QByteArray() - data_array.append(json.dumps(data)) - - response = nam.post(networkrequest, data_array) - - response_bytes = bytes(nam.reply().content()) - response_json = json.loads(response_bytes.decode("ascii")) - - download_id = response_json["downloadRequestId"] - status_link = BGT_API_URL + "/" + download_id + "/status" - - status = "PENDING" - while status != "COMPLETED": - status_request = QNetworkRequest(QUrl.fromUserInput(status_link)) - status_response = nam.get(status_request) - status_response_bytes = bytes(nam.reply().content()) - status_response_json = json.loads(status_response_bytes.decode("ascii")) - status = status_response_json["status"] - time.sleep(5) - - download_url_extract = status_response_json["_links"]["download"]["href"] - download_url = "https://api.pdok.nl" + download_url_extract - - download_request = QNetworkRequest(QUrl.fromUserInput(download_url)) - download_response = nam.get(download_request) - with open(output_zip, "wb") as f: - f.write(nam.reply().content()) + + download_task = DownloadBGTTask(self.dlg, extent_layer, output_zip, extent_geometry_wkt) + + # Add the task to the task manager + QgsApplication.taskManager().addTask(download_task) + + # Update UI self.iface.messageBar().pushMessage( MESSAGE_CATEGORY, f'BGT lagen gedownload naar {output_zip}', level=Qgis.Info, - duration=20, # wat langer zodat gebruiker tijd heeft om op linkje te klikken + duration=20, # Longer duration so the user has time to click the link ) self.dlg.bgt_file.setFilePath(output_zip) self.dlg.inputExtentComboBox.setLayer(extent_layer) self.dlg.inputExtentComboBox.setEnabled(True) self.dlg.inputExtentGroupBox.setChecked(True) + self.download_bgt = True + + + def download_gwsw_from_api(self): + # Input settings + extent_layer = self.dlg.BGTExtentCombobox.currentLayer() + extent_geometry_wkt = self.validate_extent_layer(extent_layer) + extent_bbox = extent_layer.extent() + output_gpkg = self.dlg.gwswApiOutput.filePath() + + # Initial message for download start + self.iface.messageBar().pushMessage( + MESSAGE_CATEGORY, + f"Begonnen met downloaden van GWSW leidingen naar {output_gpkg}", + level=Qgis.Info, + duration=5, + ) + + # Perform download: first lookup the municipality name(s) based on the location, then download the GWSW dataset based on the municipality name(s) + task = NetworkTask(CBS_GEMEENTES_API_URL, output_gpkg, extent_bbox, extent_geometry_wkt, "default_lijn") + + # Connect the task's finished signal to a custom slot to handle completion + task.taskCompleted.connect(self.on_task_finished_gwsw) + + # Start the task via the QGIS Task Manager + QgsApplication.taskManager().addTask(task) + + # Change UI + output_file = self.dlg.gwswApiOutput.filePath() + self.dlg.pipe_file.setFilePath(output_file) + self.dlg.inputExtentComboBox.setLayer(extent_layer) + self.dlg.inputExtentComboBox.setEnabled(True) + self.dlg.inputExtentGroupBox.setChecked(True) + + # Save download in settings of run + self.download_gwsw = True + + def on_task_finished_gwsw(self, exception=None): + """ + This method is called when the task finishes. + It pushes a message to the message bar indicating the completion. + """ + output_gpkg = self.dlg.gwswApiOutput.filePath() + if exception is None: + # Task finished successfully + self.iface.messageBar().pushMessage( + "Info", + f'GWSW leidingen gedownload naar {output_gpkg}', + level=Qgis.Info, + duration=30, # Longer so the user has time to click the link + ) + else: + # Task failed + self.iface.messageBar().pushMessage( + "Error", + f"Er is een fout opgetreden tijdens het downloaden van GWSW leidingen: {exception}", + level=Qgis.Critical, + duration=20, + ) + + # Display a warning if some municipalities don't have a GWSW dataset + if NOT_FOUND_GEMEENTES: + self.iface.messageBar().pushMessage( + "Warning", + f'De gemeente(s) {NOT_FOUND_GEMEENTES} heeft/hebben geen GWSW dataset. Download de waterschapsdata via de GWSW website of neem contact op met de beheerder', + level=Qgis.Warning, + duration=15, + ) + + def download_bag_from_api(self): + # Input settings + extent_layer = self.dlg.BGTExtentCombobox.currentLayer() + extent_geometry_wkt = self.validate_extent_layer(extent_layer) + extent_bbox = extent_layer.extent() + output_gpkg = self.dlg.bagApiOutput.filePath() + + self.iface.messageBar().pushMessage( + MESSAGE_CATEGORY, + f"Begonnen met downloaden van BAG panden naar {output_gpkg}", + level=Qgis.Info, + duration=5, + ) + + # Perform download + task = NetworkTask(BAG_API_URL, output_gpkg,extent_bbox,extent_geometry_wkt,"bag_panden") + # Connect the task's finished signal to a custom slot to handle completion + task.taskCompleted.connect(self.on_task_finished_bag) + QgsApplication.taskManager().addTask(task) + + # Change UI + output_file = self.dlg.bagApiOutput.filePath() + self.dlg.building_file.setFilePath(output_file) + self.dlg.inputExtentComboBox.setLayer(extent_layer) + self.dlg.inputExtentComboBox.setEnabled(True) + self.dlg.inputExtentGroupBox.setChecked(True) + + # Save download in settings of run + self.download_bag = True + + def on_task_finished_bag(self, exception=None): + """ + This method is called when the task finishes. + It pushes a message to the message bar indicating the completion. + """ + output_gpkg = self.dlg.bagApiOutput.filePath() + if exception is None: + # Task finished successfully + self.iface.messageBar().pushMessage( + MESSAGE_CATEGORY, + f'BAG panden gedownload naar {output_gpkg}', + level=Qgis.Info, + duration=20, # wat langer zodat gebruiker tijd heeft om op linkje te klikken + ) + else: + # Task failed + self.iface.messageBar().pushMessage( + "Error", + f"Er is een fout opgetreden tijdens het downloaden van BAG panden: {exception}", + level=Qgis.Critical, + duration=20, + ) + def on_run(self): # input files + results_file = self.dlg.results_file.filePath() bgt_file = self.dlg.bgt_file.filePath() pipe_file = self.dlg.pipe_file.filePath() building_file = self.dlg.building_file.filePath() kolken_file = self.dlg.kolken_file.filePath() + stats_file = self.dlg.stats_file.filePath() if self.dlg.inputExtentGroupBox.isChecked(): extent_layer = self.dlg.inputExtentComboBox.currentLayer() @@ -540,6 +1090,13 @@ def on_run(self): else: extent_geometry_wkt = None + if self.dlg.outputFileGroupBox.isChecked(): + output_folder = self.dlg.output_folder.filePath() + temp_QGIS_layers = False + else: + temp_QGIS_layers = True + output_folder = None + # Iniate bgt inlooptool class with parameters parameters = InputParameters( max_afstand_vlak_afwateringsvoorziening=self.dlg.max_afstand_vlak_afwateringsvoorziening.value(), @@ -549,8 +1106,14 @@ def on_run(self): max_afstand_afgekoppeld=self.dlg.max_afstand_afgekoppeld.value(), max_afstand_drievoudig=self.dlg.max_afstand_drievoudig.value(), afkoppelen_hellende_daken=self.dlg.afkoppelen_hellende_daken.isChecked(), + leidingcodes_koppelen=self.dlg.leidingcodes_koppelen.isChecked(), gebruik_bag=building_file != "", gebruik_kolken=kolken_file != "", + gebruik_resultaten=results_file != "", + gebruik_statistieken=stats_file != "", + download_bgt=self.download_bgt, + download_gwsw=self.download_gwsw, + download_bag=self.download_bag, bouwjaar_gescheiden_binnenhuisriolering=self.dlg.bouwjaar_gescheiden_binnenhuisriolering.value(), verhardingsgraad_erf=self.dlg.verhardingsgraad_erf.value(), verhardingsgraad_half_verhard=self.dlg.verhardingsgraad_half_verhard.value(), @@ -564,6 +1127,10 @@ def on_run(self): building_file=building_file, kolken_file=kolken_file, input_extent_mask_wkt=extent_geometry_wkt, + stats_file = stats_file, + results_file = results_file, + temp_QGIS_layers = temp_QGIS_layers, + output_folder = output_folder, ) self.tm.addTask(inlooptooltask) @@ -574,13 +1141,20 @@ def run(self): # 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 is True: + #print(self.first_start) self.first_start = False self.dlg = BGTInloopToolDialog() - + + self.download_bgt = False + self.download_gwsw = False + self.download_bag = False # Initiating the tool in 'on_run' self.dlg.pushButtonRun.clicked.connect(self.on_run) self.dlg.pushButtonDownloadBGT.clicked.connect(self.download_bgt_from_api) + self.dlg.pushButtonDownloadGWSW.clicked.connect(self.download_gwsw_from_api) + self.dlg.pushButtonDownloadBAG.clicked.connect(self.download_bag_from_api) + self.dlg.pushButtonReset.clicked.connect(self.reset_parameters) # Create a mask layer for clipping and extracting bgt surfaces # mask_polygon = QgsVectorLayer("Polygon?crs=epsg:28992", "Extent layer", "memory") diff --git a/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog.py b/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog.py index 43350be..5a97a85 100644 --- a/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog.py +++ b/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog.py @@ -70,6 +70,19 @@ def __init__(self, parent=None): self.pipe_file.fileChanged.connect(self.validate) self.building_file.fileChanged.connect(self.validate) self.kolken_file.fileChanged.connect(self.validate) + self.results_file.fileChanged.connect(self.validate) + self.stats_file.fileChanged.connect(self.validate) + self.output_folder.fileChanged.connect(self.validate) + self.outputFileGroupBox.clicked.connect(self.validate) + + self.bgtApiOutput.fileChanged.connect(self.validate_bgt) + self.BGTExtentCombobox.layerChanged.connect(self.validate_bgt) + + self.bagApiOutput.fileChanged.connect(self.validate_bag) + self.BGTExtentCombobox.layerChanged.connect(self.validate_bag) + + self.gwswApiOutput.fileChanged.connect(self.validate_gwsw) + self.BGTExtentCombobox.layerChanged.connect(self.validate_gwsw) # Setting defaults self.max_afstand_vlak_afwateringsvoorziening.setValue( @@ -87,13 +100,22 @@ def __init__(self, parent=None): self.verhardingsgraad_erf.setValue(VERHARDINGSGRAAD_ERF) self.verhardingsgraad_half_verhard.setValue(VERHARDINGSGRAAD_HALF_VERHARD) self.afkoppelen_hellende_daken.setChecked(AFKOPPELEN_HELLENDE_DAKEN) - + self.leidingcodes_koppelen.setChecked(KOPPEL_LEIDINGCODES) + # Run button default disable self.pushButtonRun.setEnabled(False) + self.pushButtonDownloadBGT.setEnabled(False) + self.pushButtonDownloadGWSW.setEnabled(False) + self.pushButtonDownloadBAG.setEnabled(False) self.validate() + self.validate_bgt() + self.validate_bag() + self.validate_gwsw() - # BGT Api extract settings + # Api's extract settings self.bgtApiOutput.setStorageMode(QgsFileWidget.SaveFile) + self.gwswApiOutput.setStorageMode(QgsFileWidget.SaveFile) + self.bagApiOutput.setStorageMode(QgsFileWidget.SaveFile) self.BGTExtentCombobox.setFilters(QgsMapLayerProxyModel.PolygonLayer) @@ -101,16 +123,14 @@ def __init__(self, parent=None): self.inputExtentGroupBox.clicked.connect(self.inputExtentGroupBoxChanged) self.inputExtentComboBox.setEnabled(False) self.inputExtentComboBox.setFilters(QgsMapLayerProxyModel.PolygonLayer) - - # TESTING - # self.bgt_file.setFilePath('C:/Users/Emile.deBadts/Documents/Projecten/v0099_bgt_inlooptool/test-data/extract.zip') - # self.pipe_file.setFilePath('C:/Users/Emile.deBadts/Documents/Projecten/v0099_bgt_inlooptool/test-data/getGeoPackage_1134.gpkg') - # self.building_file.setFilePath('C:/Users/Emile.deBadts/Documents/Projecten/v0099_bgt_inlooptool/test-data/bag.gpkg') + + # Saving results settings + self.output_folder.setStorageMode(QgsFileWidget.GetDirectory) def inputExtentGroupBoxChanged(self): state = self.inputExtentGroupBox.isChecked() self.inputExtentComboBox.setEnabled(state) - + def validate(self): valid = True @@ -126,17 +146,90 @@ def validate(self): pipe_file = self.pipe_file.filePath() if not is_valid_ogr_file(pipe_file, optional=False): valid = False - if os.path.splitext(pipe_file)[1] != ".gpkg": + elif os.path.splitext(pipe_file)[1] != ".gpkg": valid = False # Check building (BAG) file (optional) building_file = self.building_file.filePath() if not is_valid_ogr_file(building_file, optional=True): valid = False + elif building_file != "": + if os.path.splitext(building_file)[1] not in [".gpkg", ".shp"]: #To do: kan BAG al gpkg en shp aan? + valid = False # Check kolken file (optional) kolken_file = self.kolken_file.filePath() if not is_valid_ogr_file(kolken_file, optional=True): valid = False - + elif kolken_file != "": + if os.path.splitext(kolken_file)[1] not in [".gpkg", ".shp"]: #To do: wat is het input formaat voor kolken? + valid = False + + # Check results file previous analysis (optional) + results_file = self.results_file.filePath() + if not is_valid_ogr_file(results_file, optional=True): + valid = False + elif results_file != "": + if os.path.splitext(results_file)[1] != ".gpkg": + valid = False + + # Check stats file (optional) + stats_file = self.stats_file.filePath() + if not is_valid_ogr_file(stats_file, optional=True): + valid = False + elif stats_file != "": + if os.path.splitext(stats_file)[1] not in [".gpkg", ".shp"]: #To do: zorgen dat het ook gpkg slikt als input + valid = False + + # Check output_folder (optional) + output_folder = self.output_folder.filePath() + if self.outputFileGroupBox.isChecked(): + if output_folder == "": + valid = False + self.pushButtonRun.setEnabled(valid) + + def validate_bgt(self): + valid = True + + extent_file = self.BGTExtentCombobox.currentText() + if extent_file == "": + valid = False + + bgt_file = self.bgtApiOutput.filePath() + if bgt_file == "": + valid = False + elif os.path.splitext(bgt_file)[1] != ".zip": + valid = False + + self.pushButtonDownloadBGT.setEnabled(valid) + + def validate_bag(self): + valid = True + + extent_file = self.BGTExtentCombobox.currentText() + if extent_file == "": + valid = False + + bag_file = self.bagApiOutput.filePath() + if bag_file == "": + valid = False + elif os.path.splitext(bag_file)[1] != ".gpkg": + valid = False + + self.pushButtonDownloadBAG.setEnabled(valid) + + def validate_gwsw(self): + valid = True + + extent_file = self.BGTExtentCombobox.currentText() + if extent_file == "": + valid = False + + gwsw_file = self.gwswApiOutput.filePath() + if gwsw_file == "": + valid = False + elif os.path.splitext(gwsw_file)[1] != ".gpkg": + valid = False + + self.pushButtonDownloadGWSW.setEnabled(valid) diff --git a/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog_base.ui b/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog_base.ui index 3b9bab8..9b1d48e 100644 --- a/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog_base.ui +++ b/QGIS_plugin/bgtinlooptool/BGTInloopTool_dialog_base.ui @@ -6,8 +6,8 @@ 0 0 - 954 - 642 + 952 + 635 @@ -26,29 +26,6 @@ Bereken afwateringskenmerken - - - - 600 - 50 - 341 - 581 - - - - - - - 600 - 20 - 55 - 16 - - - - Info - - true @@ -57,7 +34,7 @@ 20 30 - 561 + 931 551 @@ -68,19 +45,19 @@ - 0 + 2 - + - Input + Brondata 10 - 10 + 110 531 - 151 + 81 @@ -90,9 +67,9 @@ 9 - 19 + 10 511 - 81 + 31 @@ -109,44 +86,92 @@ 0 - + - Gebiedsgrens + Opslaan als... - + + + BGT Download Opslaan Als ZIP + + + *.zip + + - - + + + + + + 390 + 50 + 131 + 20 + + + + Download + + + + + + + 10 + 230 + 531 + 81 + + + + Download GWSW leidingen (optioneel) + + + + + 9 + 10 + 511 + 31 + + + + + 14 + + + 7 + + + Opslaan als... - - - - BGT Download Opslaan Als ZIP - - - *.zip + + + + GWSW Download Opslaan Als GPKG - - QgsFileWidget::SaveFile + + *.gpkg - + - 420 - 110 - 93 - 28 + 390 + 50 + 131 + 20 @@ -154,90 +179,287 @@ - + 10 - 170 + 350 531 - 231 + 81 - Invoerbestanden + Download BAG panden (optioneel) - + 10 - 20 + 10 511 - 201 + 31 - + 14 - + 7 + + 0 + + + + + Opslaan als... + + + - - - *.zip + + + BAG Download Opslaan Als GPKG + + + *.gpkg - - + + + + + + 390 + 50 + 131 + 20 + + + + Download + + + + + + + 10 + 10 + 531 + 61 + + + + Gebiedsgrens voor brondata downloads + + + + + 9 + 10 + 511 + 34 + + + + + 14 + + + 7 + + + - GWSW leidingen + Gebiedsgrens + + + + + + + + + + 560 + 10 + 361 + 501 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Brondata downloaden</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In dit tabblad kunnen BGT-vlakken, GWSW-leidingen en BAG-panden worden gedownload. Hiervoor is alleen een gebiedsgrens nodig. Nadat de gewenste bestandslocatie is gespecificeerd, wordt de data gedownload op basis van deze gebiedsgrenzen.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">De gebiedsgrens moet een laag zijn die in het QGIS-project is geladen waarin de BGT Inlooptool is geopend. Dit moet een vectorbestand zijn; rasterdata kan niet worden gebruikt als gebiedsgrens.</p></body></html> + + + + + + Input + + + + + 10 + 320 + 531 + 91 + + + + Beperk analyse tot opgegeven gebied + + + true + + + false + + + + + 10 + 30 + 511 + 51 + + + + + 14 + + + + Gebiedsafbakening: + + + + + + + + + + + + + 10 + 10 + 531 + 301 + + + + Invoerbestanden + + + + + 10 + 20 + 511 + 271 + + + + + 14 + + + 7 + + - BGT vlakken + Gebieden voor statistiekberekening (optioneel) - - - *.gpkg + + + *.zip + + + + + + + BAG panden (optioneel) - - - + + + *.gpkg + + + + + + + BGT vlakken - + - BAG panden (optioneel) + GWSW leidingen - - + + + + + + + + + Kolken (optioneel) - - + + + + + + + Resultaten vorige analyse (optioneel) + + + + + + + *.gpkg + + + + + - + 10 @@ -247,39 +469,90 @@ - Beperk analyse tot opgegeven gebied + Resultaten opslaan (optioneel) true - - false - - + - 10 - 30 + 9 + 20 511 - 51 + 31 - + 14 + + 7 + - + - Gebiedsafbakening: + Opslaan in map... - + + + *.zip + + + + + + 10 + 50 + 351 + 16 + + + + + 7 + true + + + + Tip voor revisiebeheer: selecteer dezelfde map als waar de vorige revisie is opgeslagen. + + + + + + + 560 + 10 + 361 + 501 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Input bestanden</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In dit tabblad wordt alle benodigde data voor de analyse gespecificeerd. De BGT-vlakken en GWSW-leidingen zijn verplichte invoerbestanden. De overige bestanden zijn optioneel, afhankelijk van het doel van de analyse. Hieronder volgt een overzicht van de verschillende invoerbestanden:</p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Resultaten vorige analyse</span>: Een GPKG-bestand met de resultaten van de vorige analyse. Het is sterk aanbevolen om dit bestand mee te geven aan de analyse, indien beschikbaar. Dit zorgt ervoor dat handmatige wijzigingen behouden blijven, rekeninstellingen kunnen worden vergeleken en dat waterpasserende verharding en groene daken (indien gespecificeerd) worden meegenomen.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BGT-vlakken</span>: Een ZIP-bestand met de BGT-vlakken. Het is aanbevolen om dit te downloaden in het tabblad <span style=" font-weight:600;">&quot;Brondata&quot;</span>, omdat andere methoden mogelijk niet worden ondersteund.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">GWSW-leidingen</span>: Een GPKG-bestand met de GWSW-leidingen. Downloaden via het tabblad <span style=" font-weight:600;">&quot;Brondata&quot;</span> is aanbevolen, maar het kan ook via de GWSW-website. In het laatste geval ondersteunt de de tool momenteel alleen het Geo-thema Default. Let op: de tool werkt niet met GWSW-leidingen uit PDOK.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BAG-panden</span>: Een GPKG- of SHP-bestand met panden uit de BAG. Dit bestand wordt alleen gebruikt om het bouwjaar te koppelen aan de panden uit de BGT.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Kolken</span>: Een GPKG- of SHP-puntenbestand met de locaties van de kolken. Dit bestand specificeert waar verharde oppervlakken kunnen afstromen naar de riolering. Als dit bestand niet wordt opgegeven, wordt aangenomen dat uitwisseling altijd mogelijk is met de riolering, mits dit binnen de opgegeven rekeninstellingen valt.</li> +<li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Gebieden voor statistiekberekening</span>: Een GPKG- of SHP-bestand met één of meerdere gebieden. De resultaten van de BGT Inlooptool kunnen worden geaggregeerd per bemalingsgebied, gemeente, buurt of wijk. Voor elk polygoon in het invoerbestand worden statistieken berekend, zoals de percentuele afwatering naar verschillende stelsels en het type verharding.</li></ol> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Het wordt aanbevolen om de analyse te beperken tot een klein interessegebied (bijvoorbeeld een wijk of een buurt) om de snelheid van de tool te verhogen. Hoe kleiner het gebied, des te sneller de analyse. <span style=" font-weight:600;">De</span> <span style=" font-weight:600;">gebiedsafbakening</span> moet een vectorlaag zijn die in het QGIS-project is geladen; rasterdata kan niet worden gebruikt als gebiedsafbakening.</p> +<p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Resultaten opslaan</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">De resultaten kunnen worden opgeslagen als een GPKG-bestand. Hiervoor hoeft alleen de bestandsmap te worden gespecificeerd. De bestandsnaam wordt bepaald door het revisienummer en de datum van de analyse. Als er geen resultaten van een eerdere analyse zijn meegegeven, wordt dit aangeduid met &quot;v1&quot;. Als er wel een vorige versie is, wordt in de laag <span style=" font-weight:600;">&quot;</span>7.<span style=" font-weight:600;"> </span>Rekeninstellingen<span style=" font-weight:600;">&quot;</span> gekeken welke versie het nieuwe bestand krijgt. Voor revisiebeheer is het verstandig om dezelfde map te selecteren als waar de vorige revisie is opgeslagen.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Het opslaan van resultaten is optioneel. Door het vinkje bij <span style=" font-weight:600;">&quot;Resultaten opslaan&quot;</span> uit te zetten, worden de resultaten als een tijdelijke QGIS-laag ingeladen. Dit versnelt de analyse, maar de resultaten gaan verloren als QGIS wordt afgesloten. Wanneer de resultaten worden opgeslagen als GPKG, worden de styling en eventuele handmatige wijzigingen automatisch bijgehouden.</p></body></html> + @@ -296,25 +569,22 @@ - - + + - Max. afstand afwateringsvoorziening [m] + Max. afstand verhardingsvlak - kolk [m] - - - - - + + - Max. afstand verhardingsvlak - opp. water [m] + Max. afstand afwateringsvoorziening [m] - - + + @@ -323,18 +593,18 @@ - - + + - - + + - Max. afstand verhardingsvlak - kolk [m] + Max. afstand verhardingsvlak - opp. water [m] - - + + @@ -343,18 +613,21 @@ + + + - Max. afstand drievoudig stelsel [m] + <html><head/><body><p>Max. afstand drievoudig stelsel [m]<br/><span style=" font-style:italic;">(nog niet functioneel)</span></p></body></html> - - + + @@ -363,9 +636,6 @@ - - - @@ -373,16 +643,29 @@ - - + + + + + + + + + + Bouwjaar gescheiden binnenhuisriolering [-] + + - Afkoppelen hellende daken [ja/nee] + Koppeling daken [ja/nee] + + + @@ -390,18 +673,54 @@ - - + + - Bouwjaar gescheiden binnenhuisriolering [-] + - - + + + + Leidingcodes koppelen [ja/nee] + + + + + + 240 + 470 + 131 + 20 + + + + Reset instellingen + + + + + + 560 + 10 + 361 + 501 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Instellingen</span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">De instellingen beïnvloeden de koppeling tussen BGT-vlakken en GWSW-leidingen. Voor meer details over specifieke instellingen, zie de handleiding van de BGT Inlooptool. Elke instelling heeft een 'default-waarde' en kan worden gereset met de resetknop.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Als ervoor wordt gekozen om leidingcodes te koppelen, worden de kolommen met codes gevuld op basis van het rioleringstype waar het vlak naar afwatert. De kolom 'naam' uit het leidingenbestand wordt gebruikt als leidingcode. Als deze optie niet wordt gebruikt, blijven deze kolommen leeg en verborgen in de inlooptabel.</p></body></html> + + diff --git a/QGIS_plugin/bgtinlooptool/__init__.py b/QGIS_plugin/bgtinlooptool/__init__.py index c2be45b..124e9da 100644 --- a/QGIS_plugin/bgtinlooptool/__init__.py +++ b/QGIS_plugin/bgtinlooptool/__init__.py @@ -22,6 +22,54 @@ ***************************************************************************/ This script initializes the plugin, making it known to QGIS. """ +import logging +import sys + +from pathlib import Path + +from .utils.qlogging import setup_logging + + +logger = logging.getLogger(__name__) + + +def ensure_rtree_install(): + current_dir = Path(__file__).parent + custom_lib_dir = current_dir / "custom_libs" + custom_lib_dir.mkdir(exist_ok=True) + logger.info("Using %s for custom library installs (=rtree)", custom_lib_dir) + if not str(custom_lib_dir) in sys.path: + sys.path.insert(0, str(custom_lib_dir)) # Note: prepend, not append! + logger.debug("sys.path: %s", sys.path) + + try: + import rtree + logger.info("Rtree is importable at %s", rtree.__file__) + return + except ImportError: + logger.info("Rtree is not importable, we're installing it") + from .core import rtree_installer + search_path = current_dir / "core" / "whls" + wheel_filename = rtree_installer.get_wheel_filename( + search_path=search_path, + distribution="Rtree", + python_tag_prefix="cp", + abi_tag_suffix="m", + ) + logger.info("Found %s to be the best matching package file", wheel_filename) + rtree_installer.unpack_whl( + wheel_filename, + package_name="rtree", + extract_dir=custom_lib_dir + ) + # Re-try import + try: + import rtree + logger.info("Rtree is now importable at %s", rtree.__file__) + return + except ImportError: + logger.info("Rtree is not importable, our install failed sadly") + raise # noinspection PyPep8Naming @@ -32,5 +80,7 @@ def classFactory(iface): # pylint: disable=invalid-name :param iface: A QGIS interface instance. :type iface: QgsInterface """ + setup_logging() + ensure_rtree_install() from .BGTInloopTool import BGTInloopTool return BGTInloopTool(iface) diff --git a/QGIS_plugin/bgtinlooptool/bgtinlooptool.zip b/QGIS_plugin/bgtinlooptool/bgtinlooptool.zip index afff484..80e4520 100644 Binary files a/QGIS_plugin/bgtinlooptool/bgtinlooptool.zip and b/QGIS_plugin/bgtinlooptool/bgtinlooptool.zip differ diff --git a/QGIS_plugin/bgtinlooptool/constants.py b/QGIS_plugin/bgtinlooptool/constants.py index f2650cc..9de4c32 100644 --- a/QGIS_plugin/bgtinlooptool/constants.py +++ b/QGIS_plugin/bgtinlooptool/constants.py @@ -1,10 +1,21 @@ import os MESSAGE_CATEGORY = "BGT Inlooptool" -BGT_API_URL = "https://api.pdok.nl/lv/bgt/download/v1_0/full/custom" INLOOPTABEL_STYLE = os.path.join( os.path.dirname(__file__), "style", "bgt_inlooptabel.qml" ) PIPES_STYLE = os.path.join(os.path.dirname(__file__), "style", "gwsw_lijn.qml") -BGT_STYLE = os.path.join(os.path.dirname(__file__), "style", "bgt_oppervlakken.qml") \ No newline at end of file +BGT_STYLE = os.path.join(os.path.dirname(__file__), "style", "bgt_oppervlakken.qml") +INLOOPTABEL_STYLE_HIDDEN = os.path.join(os.path.dirname(__file__), "style", "bgt_inlooptabel_hidden.qml") +STATS_STYLE = os.path.join(os.path.dirname(__file__), "style", "stats.qml") +CHECKS_STYLE = os.path.join(os.path.dirname(__file__), "style", "checks.qml") +GPKG_TEMPLATE = os.path.join(os.path.dirname(__file__), "style", "template_output.gpkg") +GPKG_TEMPLATE_HIDDEN = os.path.join(os.path.dirname(__file__), "style", "template_output_hidden_fields.gpkg") + +BGT_API_URL = "https://api.pdok.nl/lv/bgt/download/v1_0/full/custom" +BAG_API_URL = "https://service.pdok.nl/lv/bag/wfs/v2_0?service=WFS&version=2.0.0&request=GetFeature&typeName=bag:pand&outputFormat=application/json" +CBS_GEMEENTES_API_URL = "https://service.pdok.nl/kadaster/bestuurlijkegebieden/wfs/v1_0?service=WFS&version=1.0.0&request=GetFeature&typeName=Gemeentegebied&outputFormat=application/json" + +NOT_FOUND_GEMEENTES = [] # Initialize the list for not found gemeentes (GWSW server) + diff --git a/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel.qml b/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel.qml index 8dc16c2..9d8f570 100644 --- a/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel.qml +++ b/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel.qml @@ -1,383 +1,693 @@ - + 1 1 1 + 0 - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + + 0 0 1 - - - + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -385,276 +695,270 @@ - + - + - - + - + + + + + + + + - - + + - + - - + + - - - - - - - - + - - + + - - + + - - - - + - - + + - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + @@ -663,113 +967,164 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - @@ -777,7 +1132,7 @@ - L:/Extern/Projecten U (2019)/U0087 - Pilot samenwerken in AWK Rijnland/Gegevens/Layout + 0 @@ -795,114 +1150,239 @@ An example follows: from qgis.PyQt.QtWidgets import QWidget def my_form_open(dialog, layer, feature): - geom = feature.geometry() - control = dialog.findChild(QWidget, "MyLineEdit") + geom = feature.geometry() + control = dialog.findChild(QWidget, "MyLineEdit") ]]> 0 tablayout - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - <p style="font-family:'MS Shell Dlg 2';font-size:10px"> <b> Totaal oppervlak: <script> document.write( expression.evaluate( "format_number($area,2)" ) ); </script> m<sup>2</sup> </b> <br> <br><table style="width:100%; font-size:10px"> <tr> <td><b>Voert af naar</b></td> <td><b>m<sup>2</sup></b></td> <td><b>%</b></td> </tr> <tr> <td>Gemengd riool</td> <td> <script> document.write( expression.evaluate( "format_number(\"gemengd_riool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"gemengd_riool\"" ) ); </script> </td> </tr> <tr> <td>Hemelwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"hemelwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"hemelwaterriool\"" ) ); </script> </td> </tr> <tr> <td>VGS Hemelwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"vgs_hemelwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"vgs_hemelwaterriool\"" ) ); </script> </td> </tr> <tr> <td>Vuilwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"vuilwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"vuilwaterriool\"" ) ); </script> </td> </tr> <tr> <td>Infiltratievoorziening</td> <td> <script> document.write( expression.evaluate( "format_number(\"infiltratievoorziening\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"infiltratievoorziening\"" ) ); </script> </td> </tr> <tr> <td>Open water</td> <td> <script> document.write( expression.evaluate( "format_number(\"open_water\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"open_water\"" ) ); </script> </td> </tr> <tr> <td>Maaiveld</td> <td> <script> document.write( expression.evaluate( "format_number(\"maaiveld\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"maaiveld\"" ) ); </script> </td> </tr> <tr> <td><b>TOTAAL</b></td> <td> <b><script> document.write( expression.evaluate( "format_number((gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + vuilwaterriool + open_water + maaiveld) /100*$area,2)" ) ); </script></b> </td> <td> <b><script> document.write( expression.evaluate( "(gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + vuilwaterriool + open_water + maaiveld)" ) ); </script></b> </td> </tr> </table> </p> + + + + + + + + <p style="font-family:'MS Shell Dlg 2';font-size:10px"> <b> Totaal oppervlak: <script> document.write( expression.evaluate( "format_number($area,2)" ) ); </script> m<sup>2</sup> </b> <br> <br><table style="width:100%; font-size:10px"> <tr> <td><b>Voert af naar</b></td> <td><b>m<sup>2</sup></b></td> <td><b>%</b></td> </tr> <tr> <td>Gemengd riool</td> <td> <script> document.write( expression.evaluate( "format_number(\"gemengd_riool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"gemengd_riool\"" ) ); </script> </td> </tr> <tr> <td>Hemelwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"hemelwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"hemelwaterriool\"" ) ); </script> </td> </tr> <tr> <td>VGS Hemelwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"vgs_hemelwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"vgs_hemelwaterriool\"" ) ); </script> </td> </tr> <tr> <td>Vuilwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"vuilwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"vuilwaterriool\"" ) ); </script> </td> </tr> <tr> <td>Infiltratievoorziening</td> <td> <script> document.write( expression.evaluate( "format_number(\"infiltratievoorziening\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"infiltratievoorziening\"" ) ); </script> </td> </tr> <tr> <td>Open water</td> <td> <script> document.write( expression.evaluate( "format_number(\"open_water\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"open_water\"" ) ); </script> </td> </tr> <tr> <td>Maaiveld</td> <td> <script> document.write( expression.evaluate( "format_number(\"maaiveld\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"maaiveld\"" ) ); </script> </td> </tr> <tr> <td><b>TOTAAL</b></td> <td> <b><script> document.write( expression.evaluate( "format_number((gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + vuilwaterriool + open_water + maaiveld) /100*$area,2)" ) ); </script></b> </td> <td> <b><script> document.write( expression.evaluate( "(gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + vuilwaterriool + open_water + maaiveld)" ) ); </script></b> </td> </tr> </table> </p> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "lokaalid" - display_name + "laatste_wijziging" + 2 diff --git a/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel_hidden.qml b/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel_hidden.qml new file mode 100644 index 0000000..d7a3d12 --- /dev/null +++ b/QGIS_plugin/bgtinlooptool/style/bgt_inlooptabel_hidden.qml @@ -0,0 +1,1368 @@ + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + tablayout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <p style="font-family:'MS Shell Dlg 2';font-size:10px"> <b> Totaal oppervlak: <script> document.write( expression.evaluate( "format_number($area,2)" ) ); </script> m<sup>2</sup> </b> <br> <br><table style="width:100%; font-size:10px"> <tr> <td><b>Voert af naar</b></td> <td><b>m<sup>2</sup></b></td> <td><b>%</b></td> </tr> <tr> <td>Gemengd riool</td> <td> <script> document.write( expression.evaluate( "format_number(\"gemengd_riool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"gemengd_riool\"" ) ); </script> </td> </tr> <tr> <td>Hemelwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"hemelwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"hemelwaterriool\"" ) ); </script> </td> </tr> <tr> <td>VGS Hemelwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"vgs_hemelwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"vgs_hemelwaterriool\"" ) ); </script> </td> </tr> <tr> <td>Vuilwaterriool</td> <td> <script> document.write( expression.evaluate( "format_number(\"vuilwaterriool\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"vuilwaterriool\"" ) ); </script> </td> </tr> <tr> <td>Infiltratievoorziening</td> <td> <script> document.write( expression.evaluate( "format_number(\"infiltratievoorziening\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"infiltratievoorziening\"" ) ); </script> </td> </tr> <tr> <td>Open water</td> <td> <script> document.write( expression.evaluate( "format_number(\"open_water\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"open_water\"" ) ); </script> </td> </tr> <tr> <td>Maaiveld</td> <td> <script> document.write( expression.evaluate( "format_number(\"maaiveld\"/100*$area,2)" ) ); </script> </td> <td> <script> document.write( expression.evaluate( "\"maaiveld\"" ) ); </script> </td> </tr> <tr> <td><b>TOTAAL</b></td> <td> <b><script> document.write( expression.evaluate( "format_number((gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + vuilwaterriool + open_water + maaiveld) /100*$area,2)" ) ); </script></b> </td> <td> <b><script> document.write( expression.evaluate( "(gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + vuilwaterriool + open_water + maaiveld)" ) ); </script></b> </td> </tr> </table> </p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "laatste_wijziging" + + 2 + diff --git a/QGIS_plugin/bgtinlooptool/style/bgt_oppervlakken.qml b/QGIS_plugin/bgtinlooptool/style/bgt_oppervlakken.qml index d4ac41f..95b5934 100644 --- a/QGIS_plugin/bgtinlooptool/style/bgt_oppervlakken.qml +++ b/QGIS_plugin/bgtinlooptool/style/bgt_oppervlakken.qml @@ -1,265 +1,472 @@ - + 1 1 1 + 0 - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + - - - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - + + + - @@ -267,47 +474,63 @@ - - - - + 0 0 1 - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -315,174 +538,202 @@ - + - + - + - - + + - + - - + - - + - - - + + - - - - - - - + - - + + - - + + - - + - - + - - + - - + - - + - - + - - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -492,66 +743,66 @@ - - - - + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + + @@ -559,7 +810,7 @@ - L:/Extern/Projecten U (2019)/U0087 - Pilot samenwerken in AWK Rijnland/Gegevens/Layout + 0 @@ -577,277 +828,62 @@ An example follows: from qgis.PyQt.QtWidgets import QWidget def my_form_open(dialog, layer, feature): - geom = feature.geometry() - control = dialog.findChild(QWidget, "MyLineEdit") + geom = feature.geometry() + control = dialog.findChild(QWidget, "MyLineEdit") ]]> 0 generatedlayout - - - - - - - - - - - - - - - - - - - - - <p style="font-family:'MS Shell Dlg 2';font-size:10px"> - <b> - Totaal oppervlak: - <script> - document.write( - expression.evaluate( - "format_number($area,2)" - ) - ); - </script> - m<sup>2</sup> - </b> - <br> - <br> - - -<table style="width:100%; font-size:10px"> - <tr> - <td><b>Voert af naar</b></td> - <td><b>m<sup>2</sup></b></td> - <td><b>%</b></td> - </tr> - <tr> - <td>Gemengd riool</td> - <td> - <script> - document.write( - expression.evaluate( - "format_number(\"gemengd_riool\"/100*$area,2)" - ) - ); - </script> - </td> - <td> - <script> - document.write( - expression.evaluate( - "\"gemengd_riool\"" - ) - ); - </script> - </td> - </tr> - <tr> - <td>Hemelwaterriool</td> - <td> - <script> - document.write( - expression.evaluate( - "format_number(\"hemelwaterriool\"/100*$area,2)" - ) - ); - </script> - </td> - <td> - <script> - document.write( - expression.evaluate( - "\"hemelwaterriool\"" - ) - ); - </script> - </td> - </tr> - <tr> - <td>VGS Hemelwaterriool</td> - <td> - <script> - document.write( - expression.evaluate( - "format_number(\"vgs_hemelwaterriool\"/100*$area,2)" - ) - ); - </script> - </td> - <td> - <script> - document.write( - expression.evaluate( - "\"vgs_hemelwaterriool\"" - ) - ); - </script> - </td> - </tr> - <tr> - <td>Infiltratievoorziening</td> - <td> - <script> - document.write( - expression.evaluate( - "format_number(\"infiltratievoorziening\"/100*$area,2)" - ) - ); - </script> - </td> - <td> - <script> - document.write( - expression.evaluate( - "\"infiltratievoorziening\"" - ) - ); - </script> - </td> - </tr> - <tr> - <td>Niet aangesloten</td> - <td> - <script> - document.write( - expression.evaluate( - "format_number(\"niet_aangesloten\"/100*$area,2)" - ) - ); - </script> - </td> - <td> - <script> - document.write( - expression.evaluate( - "\"niet_aangesloten\"" - ) - ); - </script> - </td> - </tr> - <tr> - <td><b>TOTAAL</b></td> - <td> - <b><script> - document.write( - expression.evaluate( - "format_number((gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + niet_aangesloten) /100*$area,2)" - ) - ); - </script></b> - </td> - <td> - <b><script> - document.write( - expression.evaluate( - "(gemengd_riool + hemelwaterriool + vgs_hemelwaterriool + infiltratievoorziening + niet_aangesloten)" - ) - ); - </script></b> - </td> - </tr> -</table> - -</p> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - "lokaalid" - display_name + "identificatie_lokaalid" + 2 diff --git a/QGIS_plugin/bgtinlooptool/style/checks.qml b/QGIS_plugin/bgtinlooptool/style/checks.qml new file mode 100644 index 0000000..fabccbd --- /dev/null +++ b/QGIS_plugin/bgtinlooptool/style/checks.qml @@ -0,0 +1,1303 @@ + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "niveau" + + 2 + diff --git a/QGIS_plugin/bgtinlooptool/style/gwsw_lijn.qml b/QGIS_plugin/bgtinlooptool/style/gwsw_lijn.qml index 13b4c96..fb09d70 100644 --- a/QGIS_plugin/bgtinlooptool/style/gwsw_lijn.qml +++ b/QGIS_plugin/bgtinlooptool/style/gwsw_lijn.qml @@ -1,267 +1,64 @@ - + 1 1 1 + 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + 0 + 0 + 1 + + + + + + - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - 0 - 0 - 1 - - - + + + + + + - + diff --git a/QGIS_plugin/bgtinlooptool/style/stats.qml b/QGIS_plugin/bgtinlooptool/style/stats.qml new file mode 100644 index 0000000..5306984 --- /dev/null +++ b/QGIS_plugin/bgtinlooptool/style/stats.qml @@ -0,0 +1,2751 @@ + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + tablayout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "gebied_id" + + 2 + diff --git a/QGIS_plugin/bgtinlooptool/style/template_output.gpkg b/QGIS_plugin/bgtinlooptool/style/template_output.gpkg new file mode 100644 index 0000000..6a4f0f7 Binary files /dev/null and b/QGIS_plugin/bgtinlooptool/style/template_output.gpkg differ diff --git a/QGIS_plugin/bgtinlooptool/style/template_output_hidden_fields.gpkg b/QGIS_plugin/bgtinlooptool/style/template_output_hidden_fields.gpkg new file mode 100644 index 0000000..ecb33e0 Binary files /dev/null and b/QGIS_plugin/bgtinlooptool/style/template_output_hidden_fields.gpkg differ diff --git a/QGIS_plugin/bgtinlooptool/utils/__init__.py b/QGIS_plugin/bgtinlooptool/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/QGIS_plugin/bgtinlooptool/utils/log_traceback_monkeypatch.py b/QGIS_plugin/bgtinlooptool/utils/log_traceback_monkeypatch.py new file mode 100644 index 0000000..b8a47e7 --- /dev/null +++ b/QGIS_plugin/bgtinlooptool/utils/log_traceback_monkeypatch.py @@ -0,0 +1,19 @@ +"""Monkeypatch sys.excepthook with one that logs the exception.""" +import logging +import sys + + +root_logger = logging.getLogger("") + + +original_excepthook = sys.excepthook + + +def _excepthook_with_logging(exc_type, exc_value, exc_traceback): + root_logger.error( + "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback) + ) + return original_excepthook(exc_type, exc_value, exc_traceback) + + +sys.excepthook = _excepthook_with_logging diff --git a/QGIS_plugin/bgtinlooptool/utils/qlogging.py b/QGIS_plugin/bgtinlooptool/utils/qlogging.py new file mode 100644 index 0000000..6f0d9b0 --- /dev/null +++ b/QGIS_plugin/bgtinlooptool/utils/qlogging.py @@ -0,0 +1,125 @@ +"""Module for setting up both python and qgis logging. + +In our plugin code, we just want to use ``logger.info()`` and so. This ought +to end up in a logfile we can look at for debug purposes. Ideally, customers +can mail it to us. + +Log messages also ought to end up in qgis's ``QgsMessageLog`` at the bottom of +the screen (if you've enabled it). We should set this up only for our own +messages, btw. + +TODO: there probably needs to be some tweaking of log levels. Perhaps the +verbosity ought to be made configurable. + +""" +from os.path import join +import logging + +from qgis.core import Qgis +from qgis.core import QgsApplication +from qgis.core import QgsMessageLog +from bgtinlooptool.utils import log_traceback_monkeypatch # noqa + + +LOGFILE_NAME = "bgtinlooptool-log.txt" +PYTHON_FORMAT = "%(name)s %(levelname)s %(message)s" +QGIS_FORMAT = "%(name)s\n%(message)s" # Note: split over two lines. + + +logger = logging.getLogger(__name__) + + +def has_handler(logger, handler_class): + """ Somehow isinstance() does not do the trick. """ + def path(cls): + return ".".join([cls.__module__, cls.__name__]) + return path(handler_class) in (path(h.__class__) for h in logger.handlers) + + +class ConsoleHandler(logging.StreamHandler): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setLevel(logging.DEBUG) + self.setFormatter(logging.Formatter(PYTHON_FORMAT)) + + +class FileHandler(logging.FileHandler): + + @staticmethod + def get_filename(): + return join(QgsApplication.qgisSettingsDirPath(), LOGFILE_NAME) + + def __init__(self, *args, **kwargs): + """ + We place the logfile (called :py:data:`LOGFILE_NAME`) inside our qgis + profile's directory. + """ + filename = self.__class__.get_filename() + super().__init__(filename, mode="w", encoding="utf-8") + self.setLevel(logging.DEBUG) + self.setFormatter(logging.Formatter(PYTHON_FORMAT)) + + +class QgisHandler(logging.Handler): + """logging handler to get python log messages into the qgis MessageLog.""" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setLevel(logging.INFO) + self.setFormatter(logging.Formatter(QGIS_FORMAT)) + + def emit(self, record): + """Show log message in the message area + + We map the python log level to qgis' levels. Note: qgis doesn't + distinguish between ERROR and WARNING. Normally, we use WARNING for + stuff that might be wrong and ERROR for stuff that really is wrong. We + hardly use CRITICAL. So it is best to treat python's ERROR level as + ``qgis.Critical``, as that's the most useful distinction. + + We don't do popups or messagebar stuff: that kind of UI decisions is + best left to the actual UI code. Some logger.error() messages should + be shown to the user in the message bar, but others not. We cannnot + make a generic decision here. + + """ + msg = self.format(record) + + if record.levelno >= logging.ERROR: + level = Qgis.Critical + elif record.levelno >= logging.WARNING: + level = Qgis.Warning + else: + level = Qgis.Info + + QgsMessageLog.logMessage(msg, level=level) + + +def setup_logging(): + """ + Set up python and QGIS logging. + + Set the root logger level to DEBUG. + Add file and console handlers to the root logger. + Add a QGIS handler to loggers within plugin. + Set level of PyQt5 loggers to INFO + """ + root_logger = logging.getLogger("") + # Python's default log level is WARN, but we also want to see DEBUG + # messages. + root_logger.setLevel(logging.DEBUG) + if not has_handler(root_logger, ConsoleHandler): + root_logger.addHandler(ConsoleHandler()) + if not has_handler(root_logger, FileHandler): + root_logger.addHandler(FileHandler()) + logger.info("Started logfile: %s", FileHandler.get_filename()) + + # QGIS handler for all "__name__" loggers in the plugin package + our_plugin_logger = logging.getLogger("bgtinlooptool") + if not has_handler(root_logger, QgisHandler): + our_plugin_logger.addHandler(QgisHandler()) + + # We don't want all the "PyQt5.uic.properties DEBUG setting property text" + # messages. + verbose_pyqt_logger = logging.getLogger("PyQt5.uic") + verbose_pyqt_logger.setLevel(logging.INFO) diff --git a/QGIS_plugin/bgtinlooptool/zip.py b/QGIS_plugin/bgtinlooptool/zip.py index 634e539..fb03746 100644 --- a/QGIS_plugin/bgtinlooptool/zip.py +++ b/QGIS_plugin/bgtinlooptool/zip.py @@ -16,7 +16,7 @@ "resources.qrc", ] -DIRECTORIES = ["core", "style", "processing"] +DIRECTORIES = ["core", "style", "processing", "utils"] IGNORE = ["core/__pycache__", "core/.gitignore"] @@ -67,4 +67,4 @@ def zipdir(path, zipfile_handle, path_in_zip, ignore: List = None): try: remove_tree("core") except FileNotFoundError: - pass \ No newline at end of file + pass diff --git a/core/constants.py b/core/constants.py index 141d9f8..5475865 100644 --- a/core/constants.py +++ b/core/constants.py @@ -73,6 +73,8 @@ VERHARDINGSTYPE_ONVERHARD = "onverhard" VERHARDINGSTYPE_OPEN_VERHARD = "open verhard" VERHARDINGSTYPE_GESLOTEN_VERHARD = "gesloten verhard" +VERHARDINGSTYPE_WATERPASSEREND_VERHARD = "waterpasserende verharding" +VERHARDINGSTYPE_GROEN_DAK = "groen(blauw) dak" SOURCE_PIPES_TABLE_NAME = "default_lijn" @@ -109,6 +111,7 @@ INTERNAL_PIPE_TYPE_GEMENGD_RIOOL = "gemengd_riool" INTERNAL_PIPE_TYPE_HEMELWATERRIOOL = "hemelwaterriool" INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL = "vgs_hemelwaterriool" +INTERNAL_PIPE_TYPE_VUILWATERRIOOL = "vuilwaterriool" INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING = "infiltratievoorziening" PIPE_MAP = { @@ -130,7 +133,7 @@ GWSW_PIPE_TYPE_PERCEELAANSLUITLEIDING: INTERNAL_PIPE_TYPE_IGNORE, GWSW_PIPE_TYPE_PERSLEIDING: INTERNAL_PIPE_TYPE_IGNORE, GWSW_PIPE_TYPE_TRANSPORTRIOOLLEIDING: INTERNAL_PIPE_TYPE_IGNORE, - GWSW_PIPE_TYPE_VUILWATERRIOOL: INTERNAL_PIPE_TYPE_IGNORE, + GWSW_PIPE_TYPE_VUILWATERRIOOL: INTERNAL_PIPE_TYPE_VUILWATERRIOOL, GWSW_PIPE_TYPE_DITRIOOL: INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, } @@ -140,6 +143,7 @@ BUILDINGS_TABLE_NAME = "buildings" KOLKEN_TABLE_NAME = "kolken" RESULT_TABLE_NAME = "bgt_inlooptabel" +RESULT_TABLE_NAME_PREV = "bgt_inlooptabel_oud" RESULT_TABLE_FIELD_ID = "id" RESULT_TABLE_FIELD_LAATSTE_WIJZIGING = "laatste_wijziging" @@ -151,9 +155,11 @@ # RESULT_TABLE_FIELD_BERGING_DAK = 'berging_dak' RESULT_TABLE_FIELD_TYPE_PRIVATE_VOORZIENING = "type_private_voorziening" RESULT_TABLE_FIELD_BERGING_PRIVATE_VOORZIENING = "berging_private_voorziening" -RESULT_TABLE_FIELD_PUTCODE = "putcode" -RESULT_TABLE_FIELD_LEIDINGCODE = "leidingcode" -RESULT_TABLE_FIELD_CODE_VOORZIENING = "code_voorziening" +RESULT_TABLE_FIELD_CODE_GEMENGD = "leidingcode_gemengd" +RESULT_TABLE_FIELD_CODE_HWA = "leidingcode_hwa" +RESULT_TABLE_FIELD_CODE_DWA = "leidingcode_dwa" +RESULT_TABLE_FIELD_CODE_INFILTRATIE = "leidingcode_infiltratie" +RESULT_TABLE_FIELD_WIJZIGING = "wijziging" TARGET_TYPE_GEMENGD_RIOOL = "gemengd_riool" TARGET_TYPE_HEMELWATERRIOOL = "hemelwaterriool" @@ -177,7 +183,142 @@ INTERNAL_PIPE_TYPE_GEMENGD_RIOOL, INTERNAL_PIPE_TYPE_HEMELWATERRIOOL, INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL, + INTERNAL_PIPE_TYPE_VUILWATERRIOOL, INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, KOLK, OPEN_WATER, } + +SETTINGS_TABLE_NAME = "rekeninstellingen" +SETTINGS_TABLE_NAME_PREV = "rekeninstellingen_oud" +INF_PAVEMENT_TABLE_NAME_PREV = "waterpasserende_verharding_oud" + +SETTINGS_TABLE_FIELD_ID = "run_id" +SETTINGS_TABLE_FIELD_TIJD_START = "tijd_start" +SETTINGS_TABLE_FIELD_TIJD_EIND = "tijd_eind" +SETTINGS_TABLE_FIELD_DOWNLOAD_BGT = "download_bgt" +SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW = "download_gwsw" +SETTINGS_TABLE_FIELD_DOWNLOAD_BAG = "download_bag" +SETTINGS_TABLE_FIELD_PAD_BGT = "pad_bgt" +SETTINGS_TABLE_FIELD_PAD_GWSW = "pad_gwsw" +SETTINGS_TABLE_FIELD_PAD_BAG = "pad_bag" +SETTINGS_TABLE_FIELD_PAD_KOLKEN = "pad_kolken" +SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING = "afstand_afwateringsvoorziening" +SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER = "afstand_verhard_opp_water" +SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER = "afstand_pand_opp_water" +SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK = "afstand_verhard_kolk" +SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD = "afstand_afgekoppeld" +SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG = "afstand_drievoudig" +SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF = "verhardingsgraad_erf" +SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD = "verhardingsgraad_half_verhard" +SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND = "afkoppelen_hellend" +SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS = "bouwjaar_gescheiden_binnenhuis" +SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN = "leidingcodes_koppelen" + +STATISTICS_TABLE_NAME = "statistieken" + +STATISTICS_TABLE_FIELD_ID = "id" +STATISTICS_TABLE_FIELD_OPP_TOTAAL = "opp_totaal" +STATISTICS_TABLE_FIELD_OPP_GEMENGD = "opp_gemengd" +STATISTICS_TABLE_FIELD_OPP_HWA = "opp_hwa" +STATISTICS_TABLE_FIELD_OPP_VGS = "opp_vgs" +STATISTICS_TABLE_FIELD_OPP_DWA = "opp_dwa" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING = "opp_infiltratievoorziening" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER = "opp_open_water" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD = "opp_maaiveld" +STATISTICS_TABLE_FIELD_PERC_GEMENGD = "perc_gemengd" +STATISTICS_TABLE_FIELD_PERC_HWA = "perc_hwa" +STATISTICS_TABLE_FIELD_PERC_VGS = "perc_vgs" +STATISTICS_TABLE_FIELD_PERC_DWA = "perc_dwa" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING = "perc_infiltratievoorziening" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER = "perc_open_water" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD = "perc_maaiveld" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_DAK = "opp_totaal_dak" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_GESL_VERH = "opp_totaal_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_OPEN_VERH = "opp_totaal_open_verh" +STATISTICS_TABLE_FIELD_OPP_TOTAAL_ONVERHARD = "opp_totaal_onverhard" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_DAK = "opp_gemengd_dak" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_GESL_VERH = "opp_gemengd_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_OPEN_VERH = "opp_gemengd_open_verh" +STATISTICS_TABLE_FIELD_OPP_GEMENGD_ONVERHARD = "opp_gemengd_onverhard" +STATISTICS_TABLE_FIELD_OPP_HWA_DAK = "opp_hwa_dak" +STATISTICS_TABLE_FIELD_OPP_HWA_GESL_VERH = "opp_hwa_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_HWA_OPEN_VERH = "opp_hwa_open_verh" +STATISTICS_TABLE_FIELD_OPP_HWA_ONVERHARD = "opp_hwa_onverhard" +STATISTICS_TABLE_FIELD_OPP_VGS_DAK = "opp_vgs_dak" +STATISTICS_TABLE_FIELD_OPP_VGS_GESL_VERH = "opp_vgs_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_VGS_OPEN_VERH = "opp_vgs_open_verh" +STATISTICS_TABLE_FIELD_OPP_VGS_ONVERHARD = "opp_vgs_onverhard" +STATISTICS_TABLE_FIELD_OPP_DWA_DAK = "opp_dwa_dak" +STATISTICS_TABLE_FIELD_OPP_DWA_GESL_VERH = "opp_dwa_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_DWA_OPEN_VERH = "opp_dwa_open_verh" +STATISTICS_TABLE_FIELD_OPP_DWA_ONVERHARD = "opp_dwa_onverhard" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_DAK = "opp_infiltratievoorziening_dak" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_GESL_VERH = "opp_infiltratievoorziening_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_OPEN_VERH = "opp_infiltratievoorziening_open_verh" +STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_ONVERHARD = "opp_infiltratievoorziening_onverhard" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_DAK = "opp_open_water_dak" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_GESL_VERH = "opp_open_water_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_OPEN_VERH = "opp_open_water_open_verh" +STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_ONVERHARD = "opp_open_water_onverhard" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_DAK = "opp_maaiveld_dak" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_GESL_VERH = "opp_maaiveld_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_OPEN_VERH = "opp_maaiveld_open_verh" +STATISTICS_TABLE_FIELD_OPP_MAAIVELD_ONVERHARD = "opp_maaiveld_onverhard" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_DAK = "perc_gemengd_dak" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_GESL_VERH = "perc_gemengd_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_OPEN_VERH = "perc_gemengd_open_verh" +STATISTICS_TABLE_FIELD_PERC_GEMENGD_ONVERHARD = "perc_gemengd_onverhard" +STATISTICS_TABLE_FIELD_PERC_HWA_DAK = "perc_hwa_dak" +STATISTICS_TABLE_FIELD_PERC_HWA_GESL_VERH = "perc_hwa_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_HWA_OPEN_VERH = "perc_hwa_open_verh" +STATISTICS_TABLE_FIELD_PERC_HWA_ONVERHARD = "perc_hwa_onverhard" +STATISTICS_TABLE_FIELD_PERC_VGS_DAK = "perc_vgs_dak" +STATISTICS_TABLE_FIELD_PERC_VGS_GESL_VERH = "perc_vgs_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_VGS_OPEN_VERH = "perc_vgs_open_verh" +STATISTICS_TABLE_FIELD_PERC_VGS_ONVERHARD = "perc_vgs_onverhard" +STATISTICS_TABLE_FIELD_PERC_DWA_DAK = "perc_dwa_dak" +STATISTICS_TABLE_FIELD_PERC_DWA_GESL_VERH = "perc_dwa_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_DWA_OPEN_VERH = "perc_dwa_open_verh" +STATISTICS_TABLE_FIELD_PERC_DWA_ONVERHARD = "perc_dwa_onverhard" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_DAK = "perc_infiltratievoorziening_dak" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_GESL_VERH = "perc_infiltratievoorziening_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_OPEN_VERH = "perc_infiltratievoorziening_open_verh" +STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_ONVERHARD = "perc_infiltratievoorziening_onverhard" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_DAK = "perc_open_water_dak" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_GESL_VERH = "perc_open_water_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_OPEN_VERH = "perc_open_water_open_verh" +STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_ONVERHARD = "perc_open_water_onverhard" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_DAK = "perc_maaiveld_dak" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_GESL_VERH = "perc_maaiveld_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_OPEN_VERH = "perc_maaiveld_open_verh" +STATISTICS_TABLE_FIELD_PERC_MAAIVELD_ONVERHARD = "perc_maaiveld_onverhard" +STATISTICS_TABLE_FIELD_OPP_DAK = "opp_dak" +STATISTICS_TABLE_FIELD_OPP_GESL_VERH = "opp_gesl_verh" +STATISTICS_TABLE_FIELD_OPP_OPEN_VERH = "opp_open_verh" +STATISTICS_TABLE_FIELD_OPP_ONVERHARD = "opp_onverhard" +STATISTICS_TABLE_FIELD_OPP_GROEN_DAK = "opp_groen_dak" +STATISTICS_TABLE_FIELD_OPP_WATERPAS_VERH = "opp_waterpas_verh" +STATISTICS_TABLE_FIELD_OPP_WATER = "opp_water" +STATISTICS_TABLE_FIELD_PERC_DAK = "perc_dak" +STATISTICS_TABLE_FIELD_PERC_GESL_VERH = "perc_gesl_verh" +STATISTICS_TABLE_FIELD_PERC_OPEN_VERH = "perc_open_verh" +STATISTICS_TABLE_FIELD_PERC_ONVERHARD = "perc_onverhard" +STATISTICS_TABLE_FIELD_PERC_GROEN_DAK = "perc_groen_dak" +STATISTICS_TABLE_FIELD_PERC_WATERPAS_VERH = "perc_waterpas_verh" +STATISTICS_TABLE_FIELD_PERC_WATER = "perc_water" + + +CHECKS_TABLE_NAME = "controles" + +CHECKS_TABLE_FIELD_ID = "id" +CHECKS_TABLE_FIELD_LEVEL = "niveau" +CHECKS_TABLE_FIELD_CODE = "error_code" +CHECKS_TABLE_FIELD_TABLE = "tabel" +CHECKS_TABLE_FIELD_COLUMN = "kolom" +CHECKS_TABLE_FIELD_VALUE = "waarde" +CHECKS_TABLE_FIELD_DESCRIPTION = "omschrijving" + +CHECKS_LARGE_AREA = 5000 + + diff --git a/core/defaults.py b/core/defaults.py index 221e6fa..63e85ab 100644 --- a/core/defaults.py +++ b/core/defaults.py @@ -7,6 +7,12 @@ AFKOPPELEN_HELLENDE_DAKEN = True GEBRUIK_BAG = False GEBRUIK_KOLKEN = False +GEBRUIK_RESULTATEN = False +GEBRUIK_STATISTIEKEN = False +DOWNLOAD_BGT = False +DOWNLOAD_GWSW = False +DOWNLOAD_BAG = False +KOPPEL_LEIDINGCODES = False BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING = 1992 -VERHARDINGSGRAAD_ERF = 50 +VERHARDINGSGRAAD_ERF = 0 VERHARDINGSGRAAD_HALF_VERHARD = 50 diff --git a/core/inlooptool.py b/core/inlooptool.py index aea8845..05e5681 100644 --- a/core/inlooptool.py +++ b/core/inlooptool.py @@ -1,77 +1,77 @@ +""" +Last update on Tue Jan 28 11:47:10 2025 +By: Ruben van der Zaag +Email: bgtinlooptool@nelen-schuurmans.nl +""" + # System imports import os +import contextlib # Third-party imports from osgeo import osr from osgeo import gdal from osgeo import ogr from datetime import datetime +import rtree #rtree is installed using a wheel (0.9.7 in python 3.9) -try: # Rtree should be installed by the plugin for QGIS - import rtree -except ImportError: # For ArcGIS Pro the following is needed - import sys - from pathlib import Path - - try: - from .rtree_installer import unpack_rtree - if not str(Path(__file__).parent) in sys.path: # bgt_inlooptool\\core - rtree_path = unpack_rtree() - sys.path.append(str(rtree_path)) - except ImportError: - print("The 'rtree' package installation failed.") - # Local imports -from core.constants import ( - ALL_USED_SURFACE_TYPES, - BUILDINGS_TABLE_NAME, - DISTANCE_TYPES, - GWSW_PIPE_TYPE_FIELD, - GWSW_STELSEL_TYPE_FIELD, - GWSW_STELSEL_TYPE_VERBETERDHEMELWATERSTELSEL, - INTERNAL_PIPE_TYPE_FIELD, - INTERNAL_PIPE_TYPE_GEMENGD_RIOOL, - INTERNAL_PIPE_TYPE_HEMELWATERRIOOL, - INTERNAL_PIPE_TYPE_IGNORE, - INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, - INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL, - KOLK, - KOLK_CONNECTABLE_SURFACE_TYPES, - KOLKEN_TABLE_NAME, - MULTIPLE_GEOMETRY_SURFACE_TYPES, - NON_CONNECTABLE_SURFACE_TYPES, - OPEN_WATER, - PIPE_MAP, - PIPES_TABLE_NAME, - PSEUDO_INFINITE, - RESULT_TABLE_FIELD_BGT_IDENTIFICATIE, - RESULT_TABLE_FIELD_GRAAD_VERHARDING, - RESULT_TABLE_FIELD_ID, - RESULT_TABLE_FIELD_LAATSTE_WIJZIGING, - RESULT_TABLE_FIELD_TYPE_VERHARDING, - RESULT_TABLE_NAME, - SOURCE_PIPES_TABLE_NAME, - SURFACE_TYPE_GEBOUWINSTALLATIE, - SURFACE_TYPE_ONDERSTEUNENDWATERDEEL, - SURFACE_TYPE_PAND, - SURFACE_TYPE_WATERDEEL, - SURFACE_TYPES_MET_FYSIEK_VOORKOMEN, - SURFACES_TABLE_NAME, - TARGET_TYPE_GEMENGD_RIOOL, - TARGET_TYPE_HEMELWATERRIOOL, - TARGET_TYPE_INFILTRATIEVOORZIENING, - TARGET_TYPE_MAAIVELD, - TARGET_TYPE_OPEN_WATER, - TARGET_TYPE_VGS_HEMELWATERRIOOL, - TARGET_TYPE_VUILWATERRIOOL, - TARGET_TYPES, - VERHARDINGSTYPE_GESLOTEN_VERHARD, - VERHARDINGSTYPE_ONVERHARD, - VERHARDINGSTYPE_OPEN_VERHARD, - VERHARDINGSTYPE_PAND, - VERHARDINGSTYPE_WATER, +from bgtinlooptool.core.constants import ( + PSEUDO_INFINITE, SURFACE_TYPE_PAND, SURFACE_TYPE_WEGDEEL, SURFACE_TYPE_ONDERSTEUNENDWEGDEEL, + SURFACE_TYPE_BEGROEIDTERREINDEEL, SURFACE_TYPE_ONBEGROEIDTERREINDEEL, SURFACE_TYPE_WATERDEEL, SURFACE_TYPE_ONDERSTEUNENDWATERDEEL, + SURFACE_TYPE_OVERIGBOUWWERK, SURFACE_TYPE_GEBOUWINSTALLATIE, SURFACE_TYPE_OVERBRUGGINGSDEEL, ALL_USED_SURFACE_TYPES, + CONNECTABLE_SURFACE_TYPES, NON_CONNECTABLE_SURFACE_TYPES, KOLK_CONNECTABLE_SURFACE_TYPES, SURFACE_TYPES_MET_FYSIEK_VOORKOMEN, + MULTIPLE_GEOMETRY_SURFACE_TYPES, VERHARDINGSTYPE_PAND, VERHARDINGSTYPE_WATER, VERHARDINGSTYPE_ONVERHARD, + VERHARDINGSTYPE_OPEN_VERHARD, VERHARDINGSTYPE_GESLOTEN_VERHARD, VERHARDINGSTYPE_WATERPASSEREND_VERHARD, VERHARDINGSTYPE_GROEN_DAK, + SOURCE_PIPES_TABLE_NAME, SURFACES_TABLE_NAME, PIPES_TABLE_NAME, GWSW_PIPE_TYPE_FIELD, + GWSW_PIPE_TYPE_AANSLUITLEIDING, GWSW_PIPE_TYPE_BERGINGSLEIDING, GWSW_PIPE_TYPE_DRAIN, GWSW_PIPE_TYPE_DRUKLEIDING, + GWSW_PIPE_TYPE_DUIKER, GWSW_PIPE_TYPE_DWAPERCEELAANSLUITLEIDING, GWSW_PIPE_TYPE_GEMENGDEPERCEELAANSLUITLEIDING, GWSW_PIPE_TYPE_GEMENGDRIOOL, + GWSW_PIPE_TYPE_HEMELWATERRIOOL, GWSW_PIPE_TYPE_HWAPERCEELAANSLUITLEIDING, GWSW_PIPE_TYPE_INFILTRATIERIOOL, GWSW_PIPE_TYPE_LOZELEIDING, + GWSW_PIPE_TYPE_LUCHTPERSLEIDING, GWSW_PIPE_TYPE_MANTELBUIS, GWSW_PIPE_TYPE_OVERSTORTLEIDING, GWSW_PIPE_TYPE_PERCEELAANSLUITLEIDING, + GWSW_PIPE_TYPE_PERSLEIDING, GWSW_PIPE_TYPE_TRANSPORTRIOOLLEIDING, GWSW_PIPE_TYPE_VUILWATERRIOOL, GWSW_PIPE_TYPE_DITRIOOL, + GWSW_STELSEL_TYPE_FIELD, GWSW_STELSEL_TYPE_VERBETERDHEMELWATERSTELSEL, INTERNAL_PIPE_TYPE_FIELD, INTERNAL_PIPE_TYPE_IGNORE, + INTERNAL_PIPE_TYPE_GEMENGD_RIOOL, INTERNAL_PIPE_TYPE_HEMELWATERRIOOL, INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL, INTERNAL_PIPE_TYPE_VUILWATERRIOOL, + INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING, PIPE_MAP, KOLK, OPEN_WATER, + BUILDINGS_TABLE_NAME, KOLKEN_TABLE_NAME, RESULT_TABLE_NAME, RESULT_TABLE_NAME_PREV, + RESULT_TABLE_FIELD_ID, RESULT_TABLE_FIELD_LAATSTE_WIJZIGING, RESULT_TABLE_FIELD_BGT_IDENTIFICATIE, RESULT_TABLE_FIELD_TYPE_VERHARDING, + RESULT_TABLE_FIELD_GRAAD_VERHARDING, RESULT_TABLE_FIELD_HELLINGSTYPE, RESULT_TABLE_FIELD_HELLINGSPERCENTAGE, RESULT_TABLE_FIELD_TYPE_PRIVATE_VOORZIENING, + RESULT_TABLE_FIELD_BERGING_PRIVATE_VOORZIENING, RESULT_TABLE_FIELD_CODE_GEMENGD, RESULT_TABLE_FIELD_CODE_HWA, RESULT_TABLE_FIELD_CODE_DWA, + RESULT_TABLE_FIELD_CODE_INFILTRATIE, RESULT_TABLE_FIELD_WIJZIGING, TARGET_TYPE_GEMENGD_RIOOL, TARGET_TYPE_HEMELWATERRIOOL, + TARGET_TYPE_VGS_HEMELWATERRIOOL, TARGET_TYPE_VUILWATERRIOOL, TARGET_TYPE_INFILTRATIEVOORZIENING, TARGET_TYPE_OPEN_WATER, + TARGET_TYPE_MAAIVELD, TARGET_TYPES, DISTANCE_TYPES, SETTINGS_TABLE_NAME, + SETTINGS_TABLE_NAME_PREV, INF_PAVEMENT_TABLE_NAME_PREV, SETTINGS_TABLE_FIELD_ID, SETTINGS_TABLE_FIELD_TIJD_START, + SETTINGS_TABLE_FIELD_TIJD_EIND, SETTINGS_TABLE_FIELD_DOWNLOAD_BGT, SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW, SETTINGS_TABLE_FIELD_DOWNLOAD_BAG, + SETTINGS_TABLE_FIELD_PAD_BGT, SETTINGS_TABLE_FIELD_PAD_GWSW, SETTINGS_TABLE_FIELD_PAD_BAG, SETTINGS_TABLE_FIELD_PAD_KOLKEN, + SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING, SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER, SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER, SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK, + SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD, SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG, SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF, SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD, + SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND, SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS, SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN, STATISTICS_TABLE_NAME, + STATISTICS_TABLE_FIELD_ID, STATISTICS_TABLE_FIELD_OPP_TOTAAL, STATISTICS_TABLE_FIELD_OPP_GEMENGD, STATISTICS_TABLE_FIELD_OPP_HWA, + STATISTICS_TABLE_FIELD_OPP_VGS, STATISTICS_TABLE_FIELD_OPP_DWA, STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING, STATISTICS_TABLE_FIELD_OPP_OPEN_WATER, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD, STATISTICS_TABLE_FIELD_PERC_GEMENGD, STATISTICS_TABLE_FIELD_PERC_HWA, STATISTICS_TABLE_FIELD_PERC_VGS, + STATISTICS_TABLE_FIELD_PERC_DWA, STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING, STATISTICS_TABLE_FIELD_PERC_OPEN_WATER, STATISTICS_TABLE_FIELD_PERC_MAAIVELD, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_DAK, STATISTICS_TABLE_FIELD_OPP_TOTAAL_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_TOTAAL_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_TOTAAL_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_DAK, STATISTICS_TABLE_FIELD_OPP_GEMENGD_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_GEMENGD_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_GEMENGD_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_HWA_DAK, STATISTICS_TABLE_FIELD_OPP_HWA_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_HWA_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_HWA_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_VGS_DAK, STATISTICS_TABLE_FIELD_OPP_VGS_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_VGS_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_VGS_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_DWA_DAK, STATISTICS_TABLE_FIELD_OPP_DWA_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_DWA_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_DWA_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_DAK, STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_DAK, STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_DAK, STATISTICS_TABLE_FIELD_OPP_MAAIVELD_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_MAAIVELD_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_MAAIVELD_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_DAK, STATISTICS_TABLE_FIELD_PERC_GEMENGD_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_GEMENGD_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_GEMENGD_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_HWA_DAK, STATISTICS_TABLE_FIELD_PERC_HWA_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_HWA_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_HWA_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_VGS_DAK, STATISTICS_TABLE_FIELD_PERC_VGS_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_VGS_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_VGS_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_DWA_DAK, STATISTICS_TABLE_FIELD_PERC_DWA_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_DWA_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_DWA_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_DAK, STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_DAK, STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_ONVERHARD, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_DAK, STATISTICS_TABLE_FIELD_PERC_MAAIVELD_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_MAAIVELD_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_MAAIVELD_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_DAK, STATISTICS_TABLE_FIELD_OPP_GESL_VERH, STATISTICS_TABLE_FIELD_OPP_OPEN_VERH, STATISTICS_TABLE_FIELD_OPP_ONVERHARD, + STATISTICS_TABLE_FIELD_OPP_GROEN_DAK, STATISTICS_TABLE_FIELD_OPP_WATERPAS_VERH, STATISTICS_TABLE_FIELD_OPP_WATER, STATISTICS_TABLE_FIELD_PERC_DAK, + STATISTICS_TABLE_FIELD_PERC_GESL_VERH, STATISTICS_TABLE_FIELD_PERC_OPEN_VERH, STATISTICS_TABLE_FIELD_PERC_ONVERHARD, STATISTICS_TABLE_FIELD_PERC_GROEN_DAK, + STATISTICS_TABLE_FIELD_PERC_WATERPAS_VERH, STATISTICS_TABLE_FIELD_PERC_WATER,CHECKS_TABLE_NAME,CHECKS_TABLE_FIELD_ID,CHECKS_TABLE_FIELD_LEVEL, + CHECKS_TABLE_FIELD_CODE,CHECKS_TABLE_FIELD_TABLE,CHECKS_TABLE_FIELD_COLUMN,CHECKS_TABLE_FIELD_VALUE,CHECKS_TABLE_FIELD_DESCRIPTION,CHECKS_LARGE_AREA ) -from core.defaults import ( + +from bgtinlooptool.core.defaults import ( MAX_AFSTAND_VLAK_AFWATERINGSVOORZIENING, MAX_AFSTAND_VLAK_OPPWATER, MAX_AFSTAND_PAND_OPPWATER, @@ -83,11 +83,12 @@ GEBRUIK_KOLKEN, BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, VERHARDINGSGRAAD_ERF, - VERHARDINGSGRAAD_HALF_VERHARD, + VERHARDINGSGRAAD_HALF_VERHARD, KOPPEL_LEIDINGCODES, GEBRUIK_RESULTATEN, GEBRUIK_STATISTIEKEN, DOWNLOAD_BGT, + DOWNLOAD_GWSW, DOWNLOAD_BAG, ) -from core.table_schemas import ( +from bgtinlooptool.core.table_schemas import ( RESULT_TABLE_SCHEMA, - SURFACES_TABLE_SCHEMA, + SURFACES_TABLE_SCHEMA, SETTINGS_TABLE_SCHEMA, STATISTICS_TABLE_SCHEMA, CHECKS_TABLE_SCHEMA, ) # Globals @@ -127,8 +128,14 @@ def __init__( max_afstand_afgekoppeld=MAX_AFSTAND_AFGEKOPPELD, max_afstand_drievoudig=MAX_AFSTAND_DRIEVOUDIG, afkoppelen_hellende_daken=AFKOPPELEN_HELLENDE_DAKEN, + leidingcodes_koppelen=KOPPEL_LEIDINGCODES, gebruik_bag=GEBRUIK_BAG, gebruik_kolken=GEBRUIK_KOLKEN, + gebruik_resultaten=GEBRUIK_RESULTATEN, + gebruik_statistieken=GEBRUIK_STATISTIEKEN, + download_bgt=DOWNLOAD_BGT, + download_gwsw=DOWNLOAD_GWSW, + download_bag=DOWNLOAD_BAG, bouwjaar_gescheiden_binnenhuisriolering=BOUWJAAR_GESCHEIDEN_BINNENHUISRIOLERING, verhardingsgraad_erf=VERHARDINGSGRAAD_ERF, verhardingsgraad_half_verhard=VERHARDINGSGRAAD_HALF_VERHARD, @@ -142,8 +149,14 @@ def __init__( self.max_afstand_afgekoppeld = max_afstand_afgekoppeld self.max_afstand_drievoudig = max_afstand_drievoudig self.afkoppelen_hellende_daken = afkoppelen_hellende_daken + self.leidingcodes_koppelen = leidingcodes_koppelen self.gebruik_bag = gebruik_bag self.gebruik_kolken = gebruik_kolken + self.gebruik_resultaten = gebruik_resultaten + self.gebruik_statistieken = gebruik_statistieken + self.download_bgt = download_bgt + self.download_gwsw = download_gwsw + self.download_bag = download_bag self.bouwjaar_gescheiden_binnenhuisriolering = ( bouwjaar_gescheiden_binnenhuisriolering ) @@ -162,17 +175,153 @@ def __init__(self, parameters): """Constructor.""" self.parameters = parameters self._database = Database() + self.inf_pavements_green_roof_surfaces = [] + self.relative_hoogteligging_surfaces = [] + self.new_BGT_surfaces = [] + self.outdated_changed_surfaces = [] + + def set_settings_start(self, bgt_file, pipe_file,building_file, kolken_file): + settings_table = self._database.settings_table + feature_defn = settings_table.GetLayerDefn() + feature = ogr.Feature(feature_defn) + + # Copy settings from previous runs to the new settings table: + prev_settings = self._database.mem_database.GetLayerByName(SETTINGS_TABLE_NAME_PREV) + + if prev_settings is not None: + self._database.copy_features_with_matching_fields(prev_settings, settings_table,"run_id") + + max_fid = -1 + for feature in settings_table: + fid = feature.GetFID()+1 + if fid > max_fid: + max_fid = fid + + if feature is None: + new_fid = 1 + else: + new_fid = max_fid + 1 + + feature.SetField( + SETTINGS_TABLE_FIELD_ID, + new_fid, + ) + feature.SetField( + SETTINGS_TABLE_FIELD_TIJD_START, + datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + ) + feature.SetField( + SETTINGS_TABLE_FIELD_DOWNLOAD_BGT, self.parameters.download_bgt + ) + feature.SetField( + SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW, self.parameters.download_gwsw + ) + feature.SetField( + SETTINGS_TABLE_FIELD_DOWNLOAD_BAG, self.parameters.download_bag + ) + feature.SetField( + SETTINGS_TABLE_FIELD_PAD_BGT, bgt_file + ) + feature.SetField( + SETTINGS_TABLE_FIELD_PAD_GWSW, pipe_file + ) + feature.SetField( + SETTINGS_TABLE_FIELD_PAD_BAG, building_file + ) + feature.SetField( + SETTINGS_TABLE_FIELD_PAD_KOLKEN, kolken_file + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING, self.parameters.max_afstand_vlak_afwateringsvoorziening + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER, self.parameters.max_afstand_vlak_oppwater + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER, self.parameters.max_afstand_pand_oppwater + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK, self.parameters.max_afstand_vlak_kolk + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD, self.parameters.max_afstand_afgekoppeld + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG, self.parameters.max_afstand_drievoudig + ) + feature.SetField( + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF, self.parameters.verhardingsgraad_erf + ) + feature.SetField( + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD, self.parameters.verhardingsgraad_half_verhard + ) + feature.SetField( + SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND, self.parameters.afkoppelen_hellende_daken + ) + feature.SetField( + SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS, self.parameters.bouwjaar_gescheiden_binnenhuisriolering + ) + feature.SetField( + SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN, self.parameters.leidingcodes_koppelen + ) + + settings_table.CreateFeature(feature) + feature = None + settings_table = None + + def set_settings_end(self): + # Find the feature with the highest FID + max_fid = -1 + feature_to_update = None + + settings_table = self._database.settings_table + + for feature in settings_table: + fid = feature.GetFID() + if fid > max_fid: + max_fid = fid + feature_to_update = feature + + if feature_to_update is not None: + # Set the new value for the specified field + feature_to_update.SetField( + SETTINGS_TABLE_FIELD_TIJD_EIND, + datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + ) - def import_surfaces(self, file_path): + # Update the feature in the layer + settings_table.SetFeature(feature_to_update) + + # Clean up + feature_to_update = None + settings_table = None + print(f"Settings of run {max_fid} updated successfully.") + else: + print("No features found in the layer.") + + def import_results(self, file_path): + """ + Import results from previous run to _database + :param file_path: path to results gpkg of a previous run + :return: None + """ + self._database.import_settings_results(file_path) + self._database.import_inf_pavement_green_roofs(file_path) + self._database.import_it_results(file_path) + self._database.clean_it_results() + + def import_surfaces(self, file_path, extent_wkt): """ Import BGT Surfaces to _database :param file_path: path to bgt zip file + :param extent_wkt: exent of study area :return: None """ - self._database.import_surfaces_raw(file_path) + self._database.import_surfaces_raw(file_path, extent_wkt) self._database.clean_surfaces() self._database.merge_surfaces() self._database.classify_surfaces(self.parameters) + self.relative_hoogteligging_surfaces = self._database.identify_overlapping_surfaces() def import_pipes(self, file_path, relevant_only=True): """ @@ -215,7 +364,6 @@ def is_water(): def verhard(): """Is het oppervlak (mogelijk/deels) verhard?""" - a = surface.type_verharding if surface.surface_type in NON_CONNECTABLE_SURFACE_TYPES: return False elif surface.type_verharding in { @@ -449,12 +597,12 @@ def calculate_distances(self, parameters): surface_water_buffer_dist = max( [parameters.max_afstand_pand_oppwater, parameters.max_afstand_vlak_oppwater] ) - print(f"surface_water_buffer_dist: {surface_water_buffer_dist}") - + #print(f"surface_water_buffer_dist: {surface_water_buffer_dist}") + # Distance to pipes for surface in self._database.bgt_surfaces: if not surface: - print("surface kapoet") + print("surface invalid") continue surface_geom = surface.geometry().Clone() @@ -474,17 +622,16 @@ def calculate_distances(self, parameters): if ( internal_pipe_type not in distances.keys() ): # Leiding van dit type is nog niet langsgekomen - distances[internal_pipe_type] = pipe_geom.Distance( - surface_geom - ) + distances[internal_pipe_type] = {"distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"] + } else: - if distances[internal_pipe_type] > pipe_geom.Distance( + if distances[internal_pipe_type]["distance"] > pipe_geom.Distance( surface_geom ): - distances[internal_pipe_type] = pipe_geom.Distance( - surface_geom - ) - + distances[internal_pipe_type] = {"distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"] + } # Distance to water surface if surface.surface_type != SURFACE_TYPE_WATERDEEL: surface_geom_buffer_surface_water = surface_geom.Buffer( @@ -508,8 +655,9 @@ def calculate_distances(self, parameters): min_water_distance = dist_to_this_water_surface # add to dict - distances[OPEN_WATER] = min_water_distance - + distances[OPEN_WATER] = {"distance": min_water_distance, + "leidingcode": None + } # Distance to kolk if self.parameters.gebruik_kolken: if surface.surface_type in KOLK_CONNECTABLE_SURFACE_TYPES: @@ -529,19 +677,20 @@ def calculate_distances(self, parameters): min_kolk_distance = dist_to_this_kolk # add to dict - distances[KOLK] = min_kolk_distance - + distances[KOLK] = {"distance": min_kolk_distance, + "leidingcode": None + } # Write distances to surfaces layer for distance_type in DISTANCE_TYPES: if distance_type in distances: - if distances[distance_type] == PSEUDO_INFINITE: - distances[distance_type] = None - surface["distance_" + distance_type] = distances[distance_type] + if distances[distance_type]["distance"] == PSEUDO_INFINITE: + distances[distance_type]["distance"] = None + surface["distance_" + distance_type] = distances[distance_type]["distance"] + surface["code_"+ distance_type] = distances[distance_type]["leidingcode"] self._database.bgt_surfaces.SetFeature(surface) surface = None - self._database.bgt_surfaces.ResetReading() self._database.bgt_surfaces.SetSpatialFilter(None) @@ -580,6 +729,18 @@ def calculate_runoff_targets(self): feature.SetField( RESULT_TABLE_FIELD_GRAAD_VERHARDING, surface.graad_verharding ) + feature.SetField( + "surface_type", surface.surface_type + ) + feature.SetField( + "bgt_fysiek_voorkomen", surface.bgt_fysiek_voorkomen + ) + feature.SetField( + "build_year", surface.build_year + ) + feature.SetField( + RESULT_TABLE_FIELD_WIJZIGING, 0 + ) # feature.SetField(RESULT_TABLE_FIELD_HELLINGSTYPE, val) # not yet implemented # feature.SetField(RESULT_TABLE_FIELD_HELLINGSPERCENTAGE, val) # not yet implemented # feature.SetField(RESULT_TABLE_FIELD_BERGING_DAK, val) # not yet implemented @@ -587,9 +748,454 @@ def calculate_runoff_targets(self): # feature.SetField(RESULT_TABLE_FIELD_LEIDINGCODE, val) # not yet implemented for tt in TARGET_TYPES: feature.SetField(tt, afwatering[tt]) + if self.parameters.leidingcodes_koppelen: + if feature.GetField(TARGET_TYPE_GEMENGD_RIOOL) > 0: + feature.SetField(RESULT_TABLE_FIELD_CODE_GEMENGD, surface["code_" + INTERNAL_PIPE_TYPE_GEMENGD_RIOOL]) + if feature.GetField(TARGET_TYPE_HEMELWATERRIOOL) > 0 or feature.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL) > 0: + if feature.GetField(TARGET_TYPE_HEMELWATERRIOOL) >feature.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL): + feature.SetField(RESULT_TABLE_FIELD_CODE_HWA, surface["code_" + INTERNAL_PIPE_TYPE_HEMELWATERRIOOL]) + else: + feature.SetField(RESULT_TABLE_FIELD_CODE_HWA, surface["code_" + INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL]) + if feature.GetField(TARGET_TYPE_VUILWATERRIOOL) > 0: + feature.SetField(RESULT_TABLE_FIELD_CODE_DWA, surface["code_" + INTERNAL_PIPE_TYPE_VUILWATERRIOOL]) + if feature.GetField(TARGET_TYPE_INFILTRATIEVOORZIENING) > 0: + feature.SetField(RESULT_TABLE_FIELD_CODE_INFILTRATIE, surface["code_" + INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING]) + result_table.CreateFeature(feature) feature = None + def get_nearest_pipe_code(self,feature): + surface_geom = feature.geometry().Clone() + surface_geom_buffer_afwateringsvoorziening = surface_geom.Buffer( + self.parameters.max_afstand_vlak_afwateringsvoorziening + ) + + distances = {} + for pipe_id in self._database.pipes_idx.intersection( + surface_geom_buffer_afwateringsvoorziening.GetEnvelope() + ): + pipe = self._database.pipes.GetFeature(pipe_id) + pipe_geom = pipe.geometry().Clone() + if pipe_geom.Intersects(surface_geom_buffer_afwateringsvoorziening): + internal_pipe_type = pipe[INTERNAL_PIPE_TYPE_FIELD] + if internal_pipe_type != INTERNAL_PIPE_TYPE_IGNORE: + if ( + internal_pipe_type not in distances.keys() + ): # Leiding van dit type is nog niet langsgekomen + distances[internal_pipe_type] = {"distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"] + } + else: + if distances[internal_pipe_type]["distance"] > pipe_geom.Distance( + surface_geom + ): + distances[internal_pipe_type] = {"distance": pipe_geom.Distance(surface_geom), + "leidingcode": pipe["naam"] + } + pipe = None + return distances + + def overwrite_by_manual_edits(self): + result_table = self._database.result_table + manual_results_prev = self._database.mem_database.GetLayerByName(RESULT_TABLE_NAME_PREV) + bgt_surfaces = self._database.bgt_surfaces + + if manual_results_prev is None: + print("No manual edits to keep.") + return + + records_to_delete = [] + features_to_update = [] + + # Iterate over each feature in manual_results_prev + for count, prev_feat in enumerate(manual_results_prev, 1): + if self.parameters.leidingcodes_koppelen: + distances = self.get_nearest_pipe_code(prev_feat) + + # Assign the correct code based on the type of the pipe + if prev_feat.GetField(TARGET_TYPE_GEMENGD_RIOOL) > 0: + if INTERNAL_PIPE_TYPE_GEMENGD_RIOOL in distances: + prev_feat.SetField(RESULT_TABLE_FIELD_CODE_GEMENGD, distances[INTERNAL_PIPE_TYPE_GEMENGD_RIOOL]["leidingcode"]) + else: + print(f"No mixed sewerage pipe found for prev_feat {prev_feat.GetFID()}") + + elif (prev_feat.GetField(TARGET_TYPE_HEMELWATERRIOOL) > 0 or prev_feat.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL) > 0): + if prev_feat.GetField(TARGET_TYPE_HEMELWATERRIOOL) > prev_feat.GetField(TARGET_TYPE_VGS_HEMELWATERRIOOL): + if INTERNAL_PIPE_TYPE_HEMELWATERRIOOL in distances: + prev_feat.SetField(RESULT_TABLE_FIELD_CODE_HWA, distances[INTERNAL_PIPE_TYPE_HEMELWATERRIOOL]["leidingcode"]) + else: + print(f"No rainwater pipe found for prev_feat {prev_feat.GetFID()}") + elif INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL in distances: + prev_feat.SetField(RESULT_TABLE_FIELD_CODE_HWA, distances[INTERNAL_PIPE_TYPE_VGS_HEMELWATERRIOOL]["leidingcode"]) + else: + print(f"No VGS rainwater pipe found for prev_feat {prev_feat.GetFID()}") + + elif prev_feat.GetField(TARGET_TYPE_VUILWATERRIOOL) > 0: + if INTERNAL_PIPE_TYPE_VUILWATERRIOOL in distances: + prev_feat.SetField(RESULT_TABLE_FIELD_CODE_DWA, distances[INTERNAL_PIPE_TYPE_VUILWATERRIOOL]["leidingcode"]) + else: + print(f"No waste water pipe found for prev_feat {prev_feat.GetFID()}") + + elif prev_feat.GetField(TARGET_TYPE_INFILTRATIEVOORZIENING) > 0: + if INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING in distances: + prev_feat.SetField(RESULT_TABLE_FIELD_CODE_INFILTRATIE, distances[INTERNAL_PIPE_TYPE_INFILTRATIEVOORZIENING]["leidingcode"]) + else: + print(f"No infiltration pipe found for prev_feat {prev_feat.GetFID()}") + + # Collect the features for batch processing + features_to_update.append(prev_feat) + + # Mark records in result_table for deletion based on matching key field + key_value = prev_feat.GetField("bgt_identificatie") + result_table.SetAttributeFilter(f"bgt_identificatie = '{key_value}'") + for result_feat in result_table: + records_to_delete.append(result_feat.GetFID()) + result_table.SetAttributeFilter(None) # Clear the filter for next iteration + + # Batch delete records + if records_to_delete: + for fid in records_to_delete: + result_table.DeleteFeature(fid) + + # Batch update manual_results_prev in result_table + if features_to_update: + for feat in features_to_update: + manual_results_prev.SetFeature(feat) + + # Copy features from manual_results_prev to result_table + self._database.copy_features_with_matching_fields(manual_results_prev, result_table, "id") + + # Sync the changes to disk + result_table.SyncToDisk() + + # Check if the manual edits overlap with new BGT feature (for more than 50% of its own surface) + for prev_feat in manual_results_prev: + #intersecting_fids = [] + overlapping_area = 0 + #calculate area of prev_feat + prev_feat_geom = prev_feat.GetGeometryRef() + area_prev_feat = prev_feat_geom.GetArea() + for surface in bgt_surfaces: + surface_geom = surface.GetGeometryRef() + if surface_geom.Intersects(prev_feat_geom) and (prev_feat["bgt_identificatie"]!= surface["identificatie_lokaalid"]): + intersection = surface_geom.Intersection(prev_feat_geom) + if intersection: + overlapping_area += intersection.GetArea() + + if area_prev_feat > 0 and (overlapping_area/area_prev_feat > 0.5): + self.new_BGT_surfaces.append(prev_feat) + + # Check if the manual edits have an eindregistratie (and are therefor old BGT features) + surfaces_ids = [] + for surface in bgt_surfaces: + surfaces_ids.append(surface.GetField("identificatie_lokaalid")) + + if prev_feat["bgt_identificatie"] not in surfaces_ids: + self.outdated_changed_surfaces.append(prev_feat) + + + def intersect_inf_pavement_green_roofs(self): + result_table = self._database.result_table + points_layer = self._database.mem_database.GetLayerByName(INF_PAVEMENT_TABLE_NAME_PREV) + + # Iterate over features in the points_layer + if points_layer is None: + print("No infiltrating pavement or green roofs specified.") + else: + for point_feature in points_layer: + point_geom = point_feature.GetGeometryRef() # Get the geometry of the current point feature + + # Get the value of the 'type' field for the current point feature + feature_type = point_feature.GetField("type") + + # Iterate over features in the result_table + for result_feature in result_table: + result_geom = result_feature.GetGeometryRef() # Get the geometry of the current result feature + + # Check if the geometries intersect + if result_geom.Intersects(point_geom): + # Update the 'surface_type' field based on the 'type' field from the point layer + if feature_type == "Waterpasserende verharding": + result_feature.SetField(RESULT_TABLE_FIELD_TYPE_VERHARDING, VERHARDINGSTYPE_WATERPASSEREND_VERHARD) + elif feature_type == "Groen dak": + result_feature.SetField(RESULT_TABLE_FIELD_TYPE_VERHARDING, VERHARDINGSTYPE_GROEN_DAK) + + # Update the feature in the result table + result_table.SetFeature(result_feature) + self.inf_pavements_green_roof_surfaces.append(result_feature) + + def calculate_statistics(self, stats_path): + dest_layer = self._database.statistics_table + stats_abspath = os.path.abspath(stats_path) + it_layer = self._database.result_table + + if not os.path.isfile(stats_abspath): + raise FileNotFoundError(f"Shapefile met gebieden voor statistieken niet gevonden: {stats_abspath}") + + stats_ds = ogr.Open(stats_abspath) + stats_layer = stats_ds.GetLayer() + gebied_id = 0 + field_prefix = ["opp", "perc"] + field_middle = ["_totaal", "_gemengd", "_hwa", "_vgs", "_dwa", "_infiltratievoorziening", "_open_water", "_maaiveld"] + field_suffix = ["", "_dak", "_gesl_verh", "_open_verh", "_onverhard"] + field_suffix_verharding = ["_dak","_gesl_verh","_open_verh","_onverhard","_groen_dak","_waterpas_verh","_water"] + + for feature in stats_layer: + gebied_id += 1 + geom = feature.GetGeometryRef() + new_feature = ogr.Feature(dest_layer.GetLayerDefn()) + new_feature.SetGeometry(geom.Clone()) + new_feature.SetField(STATISTICS_TABLE_FIELD_ID, gebied_id) + + intersecting_it_features = self.find_indices_intersecting_features(it_layer,new_feature) + + intersection_areas = {} + + for prefix in field_prefix: + for middle in field_middle: + middle_key = middle[1:] + if prefix == "opp": + for suffix in field_suffix: + field_name = ("STATISTICS_TABLE_FIELD_" + prefix + middle + suffix).upper() + if field_name not in intersection_areas: + intersection_areas[field_name] = self.calculate_intersection_area(intersecting_it_features, new_feature, middle_key, suffix[1:]) + new_feature.SetField(globals()[field_name], intersection_areas[field_name]) + else: + for suffix in field_suffix: + if middle_key != "totaal": + field_name = ("STATISTICS_TABLE_FIELD_" + prefix + middle + suffix).upper() + field_name_opp = field_name.replace("PERC", "OPP") + field_name_tot = field_name_opp.replace(middle_key.upper(), "TOTAAL") + if new_feature[globals()[field_name_tot]] > 0: + perc_value = round((100 * new_feature[globals()[field_name_opp]] / new_feature[globals()[field_name_tot]]), 2) + new_feature.SetField(globals()[field_name], perc_value) + + for prefix in field_prefix: + for suffix_verharding in field_suffix_verharding: + field_name = ("STATISTICS_TABLE_FIELD_" + prefix + suffix_verharding).upper() + if prefix == "opp": + if field_name not in intersection_areas: + intersection_areas[field_name] = self.calculate_intersection_area(intersecting_it_features, new_feature, "verharding", suffix_verharding[1:]) + new_feature.SetField(globals()[field_name], intersection_areas[field_name]) + else: + field_name_opp = field_name.replace("PERC", "OPP") + field_name_tot = field_name_opp.replace(suffix_verharding[1:].upper(), "TOTAAL") + if new_feature[globals()[field_name_tot]] > 0: + perc_value = round((100 * new_feature[globals()[field_name_opp]] / new_feature[globals()[field_name_tot]]), 2) + new_feature.SetField(globals()[field_name], perc_value) + + dest_layer.CreateFeature(new_feature) + new_feature = None + + + stats_ds = None + it_layer = None + + def find_indices_intersecting_features(self, layer, stats_feature): + """ + Returns a list of feature IDs (FIDs) of all features in 'layer' that intersect with 'stats_feature'. + + Parameters: + layer (ogr.Layer): The layer to check for intersecting features. + stats_feature (ogr.Feature): The feature to check intersections against. + + Returns: + List[int]: List of feature IDs (FIDs) in 'layer' that intersect with 'stats_feature'. + """ + intersecting_fids = [] + + # Get the geometry of the stats_feature to check intersections + stats_geom = stats_feature.GetGeometryRef() + + # Loop through all features in the layer + for feature in layer: + feature_geom = feature.GetGeometryRef() + + # Check if the geometries intersect + if feature_geom and stats_geom and feature_geom.Intersects(stats_geom): + intersecting_fids.append(feature.GetFID()) + + # Reset the reading for the layer to allow further use + layer.ResetReading() + + return intersecting_fids + + def calculate_intersection_area(self, intersecting_it_features, stats_feature, stat_type, type_verharding): + it_layer = self._database.result_table + area_totals = { + "totaal": 0, + "gemengd": 0, + "hwa": 0, + "vgs": 0, + "dwa": 0, + "infiltratievoorziening": 0, + "open_water": 0, + "maaiveld": 0, + "verharding": 0 + } + + stats_geom = stats_feature.GetGeometryRef() + verhardingstype_map = { + "gesl_verh": VERHARDINGSTYPE_GESLOTEN_VERHARD, + "open_verh": VERHARDINGSTYPE_OPEN_VERHARD, + "groen_dak": VERHARDINGSTYPE_GROEN_DAK, + "waterpas_verh": VERHARDINGSTYPE_WATERPASSEREND_VERHARD, + } + verhardingstype = verhardingstype_map.get(type_verharding, type_verharding) + + if not stats_geom.IsValid(): + stats_geom = stats_geom.MakeValid() + + for fid in intersecting_it_features: + it_feature = it_layer.GetFeature(fid) + it_geom = it_feature.GetGeometryRef() + + if not it_geom.IsValid(): + it_geom = it_geom.MakeValid() + + if it_feature[RESULT_TABLE_FIELD_TYPE_VERHARDING] == verhardingstype or verhardingstype == "": + if it_geom and stats_geom and it_geom.IsValid() and stats_geom.IsValid() and stats_geom.Intersects(it_geom): + try: + intersection_geom = stats_geom.Intersection(it_geom) + intersection_area = intersection_geom.GetArea() + area_totals["totaal"] += intersection_area + area_totals["verharding"] += intersection_area + area_totals["gemengd"] += intersection_area * it_feature[TARGET_TYPE_GEMENGD_RIOOL] / 100 + area_totals["hwa"] += intersection_area * it_feature[TARGET_TYPE_HEMELWATERRIOOL] / 100 + area_totals["vgs"] += intersection_area * it_feature[TARGET_TYPE_VGS_HEMELWATERRIOOL] / 100 + area_totals["dwa"] += intersection_area * it_feature[TARGET_TYPE_VUILWATERRIOOL] / 100 + area_totals["infiltratievoorziening"] += intersection_area * it_feature[TARGET_TYPE_INFILTRATIEVOORZIENING] / 100 + area_totals["open_water"] += intersection_area * it_feature[TARGET_TYPE_OPEN_WATER] / 100 + area_totals["maaiveld"] += intersection_area * it_feature[TARGET_TYPE_MAAIVELD] / 100 + except Exception as e: + print(f"Error calculating intersection: {e}") + continue + + return round(area_totals[stat_type] / 10000, 2) + + def generate_warnings(self): + checks_table = self._database.checks_table + it_layer = self._database.result_table + feature_defn = checks_table.GetLayerDefn() + #print(feature_defn) + fid = 0 + + #Check 1: large areas + warning_large_area = f"Dit BGT vlak is groter dan {CHECKS_LARGE_AREA} m2. De kans is groot dat dit vlak aangesloten is op meerdere stelseltypen. Controleer en corrigeer dit wanneer nodig." + + for it_feature in it_layer: + # Get the geometry of the feature and calculate area + geom = it_feature.GetGeometryRef() + area = geom.GetArea() + if area > CHECKS_LARGE_AREA: # value in m2 + fid += 1 + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID,fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE,1) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE,"4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN,"") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE,str(round(area,2))) + check_feature.SetField(CHECKS_TABLE_FIELD_DESCRIPTION,warning_large_area) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + #Check 2: buildings that are in the BGT but not in the BAG + warning_bgt_bag_mismatch = "Dit pand ontbreekt in de BAG. Er is daarom geen bouwjaar toegewezen aan het pand." + + for building in self._database.non_matching_buildings: + fid += 1 + geom = building.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID,fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Info") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE,2) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE,"4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN,"BGT Identificatie") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE,building["identificatie_lokaalid"]) #identificatiebagpnd + check_feature.SetField(CHECKS_TABLE_FIELD_DESCRIPTION,warning_bgt_bag_mismatch + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + #Check 3: surface which intersect with green roofs or infiltrating pavement + warning_infiltrating_surfaces = "Dit vlak is waterpasserende verharding of een groen dak. Alleen het type verharding is daarop aangepast. Ga na of er nog meer aangepast moet worden." + + for surface in self.inf_pavements_green_roof_surfaces: + fid += 1 + geom = surface.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID,fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Info") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE,3) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE,"4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN,"Type verharding") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE,surface["type_verharding"]) + check_feature.SetField(CHECKS_TABLE_FIELD_DESCRIPTION,warning_infiltrating_surfaces + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + #Check 4: relatieve hoogteligging + warning_relatieve_hoogteligging = "Dit vlak overlapt met een ander BGT vlak en heeft een hogere relatieve hoogteligging. Zorg dat er geen overlap is tussen de vlakken en dat alleen de vlakken met hoogste relatieve hoogteligging in de dataset zitten." + + for surface in self.relative_hoogteligging_surfaces: + fid += 1 + geom = surface.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID,fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE,4) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE,"5_BGT_oppervlakken") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN,"BGT Identificatie") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE,surface["identificatie_lokaalid"]) + check_feature.SetField(CHECKS_TABLE_FIELD_DESCRIPTION,warning_relatieve_hoogteligging + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + #Check 5: nieuwe vlakken in de BGT, met nieuwe IDs, dan kunnen deze overlappen met de handmatige wijzigingen. + warning_new_BGT_surfaces = "Dit handmatige gewijzigde vlak heeft meer dan 50% overlap met een nieuw BGT vlak. Controleer of dit vlak behouden moet blijven." + for it_feature in self.new_BGT_surfaces: + fid += 1 + geom = it_feature.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID,fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE,5) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE,"4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN,"BGT identificatie") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE,it_feature["bgt_identificatie"]) + check_feature.SetField(CHECKS_TABLE_FIELD_DESCRIPTION,warning_new_BGT_surfaces + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + #Check 6: handmatig gewijzigd BGT vlak heeft een eindregistratie gekregen + warning_outdated_changed_surfaces = "Dit handmatig gewijzigde vlak zit niet meer in de BGT data. Controleer of het nog steeds bestaat." + for it_feature in self.outdated_changed_surfaces: + fid += 1 + geom = it_feature.GetGeometryRef() + check_feature = ogr.Feature(feature_defn) + check_feature.SetGeometry(geom.Clone()) + check_feature.SetField(CHECKS_TABLE_FIELD_ID,fid) + check_feature.SetField(CHECKS_TABLE_FIELD_LEVEL, "Waarschuwing") + check_feature.SetField(CHECKS_TABLE_FIELD_CODE,6) + check_feature.SetField(CHECKS_TABLE_FIELD_TABLE,"4_BGT_inlooptabel") + check_feature.SetField(CHECKS_TABLE_FIELD_COLUMN,"BGT identificatie") + check_feature.SetField(CHECKS_TABLE_FIELD_VALUE,it_feature["bgt_identificatie"]) + check_feature.SetField(CHECKS_TABLE_FIELD_DESCRIPTION,warning_outdated_changed_surfaces + ) + checks_table.CreateFeature(check_feature) + check_feature = None # Cleanup after creating the feature + + checks_table = None + it_layer = None class Database: def __init__(self, epsg=28992): @@ -604,13 +1210,44 @@ def __init__(self, epsg=28992): self.create_table( table_name=RESULT_TABLE_NAME, table_schema=RESULT_TABLE_SCHEMA ) - + self.create_table( + table_name=SETTINGS_TABLE_NAME, table_schema=SETTINGS_TABLE_SCHEMA + ) + self.create_table( + table_name=STATISTICS_TABLE_NAME, table_schema=STATISTICS_TABLE_SCHEMA + ) + self.create_table( + table_name=CHECKS_TABLE_NAME, table_schema=CHECKS_TABLE_SCHEMA + ) + self.non_matching_buildings = [] + @property def result_table(self): """Get reference to result layer (BGT Inlooptabel) :rtype ogr.Layer """ return self.mem_database.GetLayerByName(RESULT_TABLE_NAME) + + @property + def settings_table(self): + """Get reference to the Settings layer + :rtype ogr.Layer + """ + return self.mem_database.GetLayerByName(SETTINGS_TABLE_NAME) + + @property + def statistics_table(self): + """Get reference to the Settings layer + :rtype ogr.Layer + """ + return self.mem_database.GetLayerByName(STATISTICS_TABLE_NAME) + + @property + def checks_table(self): + """Get reference to the Settings layer + :rtype ogr.Layer + """ + return self.mem_database.GetLayerByName(CHECKS_TABLE_NAME) @property def bgt_surfaces(self): @@ -654,7 +1291,84 @@ def create_table(self, table_name, table_schema): lyr.CreateField(field_defn) lyr = None + + def import_it_results(self, file_path): + prev_gpkg_abspath = os.path.abspath(file_path) + if not os.path.isfile(prev_gpkg_abspath): + raise FileNotFoundError( + "Resultaten GeoPackage vorige run niet gevonden: {}".format(prev_gpkg_abspath) + ) + it_ds = ogr.Open(file_path) + # TODO more thorough checks of validity of input geopackage + try: + self.mem_database.CopyLayer( + it_ds.GetLayerByName("4_BGT_inlooptabel"), RESULT_TABLE_NAME_PREV + ) + except Exception: + # TODO more specific exception + raise FileInputError( + "Ongeldige input: {} is geen geldige Resultaten GeoPackage".format( + prev_gpkg_abspath + ) + ) + def clean_it_results(self): + """ + Update the results layer from the previous simulation such that only the manual changes are kept. + """ + layer = self.mem_database.GetLayerByName(RESULT_TABLE_NAME_PREV) + if layer is None: + raise DatabaseOperationError + + delete_fids = [] + for it_feat in layer: + if not it_feat["wijziging"]: + delete_fids.append(it_feat.GetFID()) + + for fid in delete_fids: + layer.DeleteFeature(fid) + layer = None + + def import_settings_results(self, file_path): + prev_gpkg_abspath = os.path.abspath(file_path) + if not os.path.isfile(prev_gpkg_abspath): + raise FileNotFoundError( + "Resultaten GeoPackage vorige run niet gevonden: {}".format(prev_gpkg_abspath) + ) + it_ds = ogr.Open(file_path) + # TODO more thorough checks of validity of input geopackage + try: + self.mem_database.CopyLayer( + it_ds.GetLayerByName("7_Rekeninstellingen"), SETTINGS_TABLE_NAME_PREV + ) + except Exception: + # TODO more specific exception + raise FileInputError( + "Ongeldige input: {} is geen geldige Resultaten GeoPackage".format( + prev_gpkg_abspath + ) + ) + + def import_inf_pavement_green_roofs(self,file_path): + prev_gpkg_abspath = os.path.abspath(file_path) + if not os.path.isfile(prev_gpkg_abspath): + raise FileNotFoundError( + "Resultaten GeoPackage vorige run niet gevonden: {}".format(prev_gpkg_abspath) + ) + it_ds = ogr.Open(file_path) + # TODO more thorough checks of validity of input geopackage/shapefile + try: + self.mem_database.CopyLayer( + it_ds.GetLayerByName("1_Waterpasserende_verharding_en_groene_daken"), INF_PAVEMENT_TABLE_NAME_PREV + ) + except Exception: + # TODO more specific exception + raise FileInputError( + "Ongeldige input: {} is geen geldige Resultaten GeoPackage".format( + prev_gpkg_abspath + ) + ) + def import_pipes(self, file_path): """ Copy the required contents of the GWSW GeoPackage file to self.mem_database @@ -680,7 +1394,7 @@ def import_pipes(self, file_path): ) ) - def import_surfaces_raw(self, file_path): + def import_surfaces_raw(self, file_path,extent_wkt): """ Copy the required contents of the BGT zip file 'as is' to self.mem_database :param file_path: @@ -718,6 +1432,10 @@ def import_surfaces_raw(self, file_path): continue # TODO Warning else: nr_layers_with_features += 1 + # Set spatial filter on src_layer to only include features that intersect with the extent + if extent_wkt is not None: + extent_geometry = ogr.CreateGeometryFromWkt(extent_wkt) + src_layer.SetSpatialFilter(extent_geometry) self.mem_database.CopyLayer(src_layer=src_layer, new_name=stype) print( f"raw import of {stype} layer has {self.mem_database.GetLayerByName(stype).GetFeatureCount()} features" @@ -729,6 +1447,7 @@ def import_surfaces_raw(self, file_path): except FileInputError: raise except Exception: + #self.import_surfaces_raw_alternative(file_path) raise FileInputError(f"Probleem met laag {stype}.gml in BGT zip file") def import_kolken(self, file_path): @@ -809,6 +1528,10 @@ def clean_surfaces(self): delete_fids = [] for feature in layer: geom = feature.GetGeometryRef() + if geom is None: + # If no geometry is found, skip this feature + print(f"Warning: Feature {feature.GetFID()} in layer {surface_type} has no geometry. Skipping.") + continue geom_type = geom.GetGeometryType() if geom_type == ogr.wkbPolygon: pass @@ -825,12 +1548,12 @@ def clean_surfaces(self): # print('Deleting feature {} because it is a Linestring'.format(f.GetFID())) delete_fids.append(feature.GetFID()) else: - print( - "Warning: Fixing feature {fid} in {stype} failed! No procedure defined to clean up geometry " - "type {geom_type}. Continuing anyway.".format( - fid=feature.GetFID(), stype=surface_type, geom_type=str(geom_type) - ) - ) + #print( + # "Warning: Fixing feature {fid} in {stype} failed! No procedure defined to clean up geometry " + # "type {geom_type}. Continuing anyway.".format( + # fid=feature.GetFID(), stype=surface_type, geom_type=str(geom_type) + # ) + #) continue for fid in delete_fids: layer.DeleteFeature(fid) @@ -974,7 +1697,8 @@ def merge_surfaces(self): if stype == SURFACE_TYPE_PAND: new_feature["identificatiebagpnd"] = feature["identificatieBAGPND"] - + new_feature.SetField("relatieve_hoogteligging", feature["relatieveHoogteligging"]) + target_geometry = ogr.ForceToPolygon(feature.geometry()) target_geometry.AssignSpatialReference(self.srs) new_feature.SetGeometry(target_geometry) @@ -986,7 +1710,46 @@ def merge_surfaces(self): ) previous_fcount = dest_layer.GetFeatureCount() dest_layer = None + + def identify_overlapping_surfaces(self): + """Finds all overlapping surfaces and saves the surfaces with the highest relatieve hoogteligging""" + layer = self.mem_database.GetLayerByName(SURFACES_TABLE_NAME) + if layer is None: + raise DatabaseOperationError + + # Check if the layer has any features + if layer.GetFeatureCount() == 0: + return + + # Create a list to store the features with the highest hoogteligging + highest_surfaces = [] + + # Loop through all surfaces in the layer + for feature in layer: + geom1 = feature.GetGeometryRef() # Get the geometry of the current feature (surface) + hoogteligging1 = feature.GetField("relatieve_hoogteligging") # Get the "hoogteligging" field + + # Loop through all other surfaces in the layer to check for overlaps + layer.ResetReading() # Reset the reading to iterate over all features again + for other_feature in layer: + if other_feature.GetFID() == feature.GetFID(): + # Skip comparing the surface with itself + continue + + geom2 = other_feature.GetGeometryRef() # Get the geometry of the other feature + if geom1.Intersects(geom2): # Check if the geometries intersect (overlap) + hoogteligging2 = other_feature.GetField("relatieve_hoogteligging") # Get the hoogteligging of the other feature + # Compare the two overlapping features and keep the one with the higher hoogteligging + if hoogteligging1 > hoogteligging2: + if feature not in highest_surfaces: + highest_surfaces.append(feature) # Add the feature if it's not already in the list + elif hoogteligging1 < hoogteligging2: + if other_feature not in highest_surfaces: + highest_surfaces.append(other_feature) # Add the other feature if it's not already in the list + + return highest_surfaces + def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): print("Started add_build_year_to_surface...") @@ -1001,9 +1764,13 @@ def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): # create dict from buildings building_dict = {} for building in buildings: - building_dict[building["identificatie"][1:]] = building[field_name] + if building["identificatie"][0] == "0": + building_dict[building["identificatie"][1:]] = building[field_name] + else: + building_dict[building["identificatie"]] = building[field_name] building = None - + + # List to track bui;ding-surfaces that are in the BGT but not in the BAG for surface in surfaces: if surface["surface_type"] == SURFACE_TYPE_PAND: if surface["identificatiebagpnd"] in building_dict.keys(): @@ -1011,18 +1778,208 @@ def add_build_year_to_surface(self, file_path, field_name="bouwjaar"): surface["identificatiebagpnd"] ] surfaces.SetFeature(surface) + else: + self.non_matching_buildings.append(surface) surface = None buildings = None surfaces = None print("... done") return + + def copy_features_with_matching_fields(self,src_layer, dst_layer, primary_key_field): + # Get source layer definition + src_defn = src_layer.GetLayerDefn() + + # Get the names of the fields in the destination layer + dst_defn = dst_layer.GetLayerDefn() + dst_field_names = [dst_defn.GetFieldDefn(i).GetName() for i in range(dst_defn.GetFieldCount())] + + # Iterate through the features in the source layer + for src_feat in src_layer: + # Create a new feature in the destination layer + dst_feat = ogr.Feature(dst_defn) + + # Copy the fields from the source to the destination if the field names match + for i in range(src_defn.GetFieldCount()): + field_name = src_defn.GetFieldDefn(i).GetName() + if field_name in dst_field_names: + dst_feat.SetField(field_name, src_feat.GetField(i)) + + # Set the primary key manually if needed + if primary_key_field: + dst_feat.SetField(primary_key_field, src_feat.GetFID()) + + # Set the geometry + geom = src_feat.GetGeometryRef() + if geom: + dst_feat.SetGeometry(geom.Clone()) + + # Add the feature to the destination layer + dst_layer.CreateFeature(dst_feat) + + # Destroy the feature to free resources + dst_feat = None + + # Sync the data to disk + dst_layer.SyncToDisk() + + def _save_to_gpkg(self,file_folder,template_gpkg): + print("Preparing template gpkg") + file_name = self.output_name(file_folder) + file_path = os.path.join(file_folder, file_name) + self.copy_and_rename_file(template_gpkg, file_path) + + print("Saving layers to gpkg") + # Initialize layers with common elements + layers = [ + (CHECKS_TABLE_NAME, "2_Te_controleren"), + (PIPES_TABLE_NAME, "3_GWSW_leidingen"), + (RESULT_TABLE_NAME, "4_BGT_inlooptabel"), + (SURFACES_TABLE_NAME, "5_BGT_oppervlakken"), + (STATISTICS_TABLE_NAME, "6_Statistieken"), + (SETTINGS_TABLE_NAME, "7_Rekeninstellingen") + ] + + # Prepend the additional element if the layer exists + if self.mem_database.GetLayerByName(INF_PAVEMENT_TABLE_NAME_PREV) is not None: + layers.insert(0, (INF_PAVEMENT_TABLE_NAME_PREV, "1_Waterpasserende_verharding_en_groene_daken")) + + with self.open_gpkg(file_path) as dst_gpkg: + for db_layer, gpkg_layer in layers: + print(f"Saving {gpkg_layer} layer in gpkg") + self._write_to_disk(dst_gpkg, db_layer, gpkg_layer) + if db_layer == RESULT_TABLE_NAME: + self.track_changes(dst_gpkg) + + print("All layers saved successfully.") + return str(file_path) + + def output_name(self, file_folder): + # Determine max. run_id + max_run_id = -1 + for feature in self.settings_table: + run_id = feature.GetField("run_id") + if run_id > max_run_id: + max_run_id = run_id + + if max_run_id < 1: + max_run_id = 1 + + # Set the initial output name + current_date = datetime.now().strftime("%Y%m%d") + output_name = f"v{max_run_id}_BGT_inlooptabel_{current_date}.gpkg" + file_path = os.path.join(file_folder, output_name) + + # Check if file already exists + if os.path.exists(file_path): + # Append current date and time to the output name + current_time = datetime.now().strftime("%Y%m%d_%H%M%S") + output_name = f"v{max_run_id}_BGT_inlooptabel_{current_time}.gpkg" + + return output_name + + def copy_and_rename_file(self,original_file_path, new_file_path): + """ + Copies a file and renames the copy using only sys and os modules. - def _write_to_disk(self, file_path): + :param original_file_path: Path to the original file. + :param new_file_path: Path where the new file will be saved. + """ + try: + # Read the contents of the original file + with open(original_file_path, 'rb') as original_file: + content = original_file.read() + + # Write the contents to the new file + with open(new_file_path, 'wb') as new_file: + new_file.write(content) + + print(f"Template gpkg copied to {new_file_path}") + except FileNotFoundError: + print(f"The template {original_file_path} does not exist.") + except PermissionError: + print(f"Permission denied. Unable to copy the template {original_file_path} to {new_file_path}.") + except Exception as e: + print(f"An error occurred when copying the template: {e}") + + + def _write_to_disk(self, dst_gpkg, db_layer_name, dst_layer_name): """Copy self.mem_database to file_path""" - self.out_db = GPKG_DRIVER.CopyDataSource(self.mem_database, file_path) - self.out_db = None + # Get the source layer from the memory database + db_layer = self.mem_database.GetLayerByName(db_layer_name) + if db_layer is None: + raise ValueError(f"Layer '{db_layer_name}' not found in memory database.") + + dst_layer = dst_gpkg.GetLayerByName(dst_layer_name) + if dst_layer is None: + raise ValueError(f"Layer '{dst_layer_name}' not found in destination GeoPackage.") + + layer_defn = db_layer.GetLayerDefn() + dst_layer_defn = dst_layer.GetLayerDefn() + + if layer_defn.GetFieldCount() != dst_layer_defn.GetFieldCount(): + print(f"Warning: Source and destination layers have different field counts: {layer_defn.GetFieldCount()} vs {dst_layer_defn.GetFieldCount()}. Continuing anyway.") + + field_mapping = {dst_layer_defn.GetFieldDefn(i).GetName(): layer_defn.GetFieldIndex(dst_layer_defn.GetFieldDefn(i).GetName()) + for i in range(dst_layer_defn.GetFieldCount())} + + # Iterate over features in the source layer and copy them to the destination layer + for feature in db_layer: + dst_feature = ogr.Feature(dst_layer_defn) + for dst_field_name, src_field_index in field_mapping.items(): + if src_field_index != -1: # Ensure the field exists in the source layer + dst_feature.SetField(dst_field_name, feature.GetField(src_field_index)) + else: + print(f"Warning: Source field '{dst_field_name}' not found in the source layer. Skipping field.") + #for dst_field_name, src_field_index in field_mapping.items(): + #dst_feature.SetField(dst_field_name, feature.GetField(src_field_index)) + geom = feature.GetGeometryRef() + if geom: + dst_feature.SetGeometry(geom.Clone()) + dst_layer.CreateFeature(dst_feature) + dst_feature = None + print(f"Layer '{dst_layer_name}' saved successfully.") + + @contextlib.contextmanager + def open_gpkg(self, file_path): + dst_gpkg = GPKG_DRIVER.Open(file_path, 1) + if dst_gpkg is None: + raise ValueError(f"Could not open GeoPackage '{file_path}' for writing.") + try: + yield dst_gpkg + finally: + dst_gpkg = None + + def track_changes(self, dst_gpkg): + """ Add SQL triggers to track changes """ + + # SQL statements to create the triggers + sql_time_last_change = """ + CREATE TRIGGER update_laaste_wijziging_on_update AFTER UPDATE + OF bgt_identificatie, type_verharding, graad_verharding, hellingstype, hellingspercentage, type_private_voorziening, berging_private_voorziening, leidingcode_gemengd, leidingcode_hwa, leidingcode_dwa, leidingcode_infiltratie, gemengd_riool, hemelwaterriool, vgs_hemelwaterriool, vuilwaterriool, infiltratievoorziening, open_water, maaiveld + ON "4_BGT_inlooptabel" + FOR EACH ROW + BEGIN + UPDATE "4_BGT_inlooptabel" SET laatste_wijziging = datetime('now', '+1 hour') WHERE id = old.id; + END + """ + + sql_changed_tf = """ + CREATE TRIGGER update_wijziging_on_update AFTER UPDATE + OF bgt_identificatie, type_verharding, graad_verharding, hellingstype, hellingspercentage, type_private_voorziening, berging_private_voorziening, leidingcode_gemengd, leidingcode_hwa, leidingcode_dwa, leidingcode_infiltratie, gemengd_riool, hemelwaterriool, vgs_hemelwaterriool, vuilwaterriool, infiltratievoorziening, open_water, maaiveld + ON "4_BGT_inlooptabel" + FOR EACH ROW + BEGIN + UPDATE "4_BGT_inlooptabel" SET wijziging = 1 WHERE id = old.id; + END + """ + + # Execute the SQL statements + dst_gpkg.ExecuteSQL(sql_time_last_change) + dst_gpkg.ExecuteSQL(sql_changed_tf) + print("Triggers created successfully.") class Layer(object): def __init__(self, layer): diff --git a/core/table_schemas.py b/core/table_schemas.py index a85e49c..d4a9732 100644 --- a/core/table_schemas.py +++ b/core/table_schemas.py @@ -1,5 +1,5 @@ from osgeo import ogr -from core.constants import * +from bgtinlooptool.core.constants import * class TableSchema: @@ -19,9 +19,11 @@ def __init__(self, fields, primary_key, geometry_column, geometry_type): RESULT_TABLE_FIELD_GRAAD_VERHARDING: ogr.OFTReal, "build_year": ogr.OFTInteger, "identificatiebagpnd": ogr.OFTString, + "relatieve_hoogteligging": ogr.OFTInteger, } for dist_type in DISTANCE_TYPES: surfaces_table_fields["distance_" + dist_type] = ogr.OFTReal + surfaces_table_fields["code_" + dist_type] = ogr.OFTString del dist_type SURFACES_TABLE_SCHEMA = TableSchema( @@ -43,18 +45,168 @@ def __init__(self, fields, primary_key, geometry_column, geometry_type): # RESULT_TABLE_FIELD_BERGING_DAK: ogr.OFTReal, RESULT_TABLE_FIELD_TYPE_PRIVATE_VOORZIENING: ogr.OFTString, RESULT_TABLE_FIELD_BERGING_PRIVATE_VOORZIENING: ogr.OFTReal, - RESULT_TABLE_FIELD_CODE_VOORZIENING: ogr.OFTString, - RESULT_TABLE_FIELD_PUTCODE: ogr.OFTString, - RESULT_TABLE_FIELD_LEIDINGCODE: ogr.OFTString, - TARGET_TYPE_GEMENGD_RIOOL: ogr.OFTReal, + RESULT_TABLE_FIELD_CODE_GEMENGD: ogr.OFTString, + RESULT_TABLE_FIELD_CODE_HWA: ogr.OFTString, + RESULT_TABLE_FIELD_CODE_DWA: ogr.OFTString, + RESULT_TABLE_FIELD_CODE_INFILTRATIE: ogr.OFTString, + TARGET_TYPE_GEMENGD_RIOOL: ogr.OFTReal, TARGET_TYPE_HEMELWATERRIOOL: ogr.OFTReal, TARGET_TYPE_VGS_HEMELWATERRIOOL: ogr.OFTReal, TARGET_TYPE_VUILWATERRIOOL: ogr.OFTReal, TARGET_TYPE_INFILTRATIEVOORZIENING: ogr.OFTReal, TARGET_TYPE_OPEN_WATER: ogr.OFTReal, TARGET_TYPE_MAAIVELD: ogr.OFTReal, + "surface_type": ogr.OFTString, + "bgt_fysiek_voorkomen": ogr.OFTString, + "build_year": ogr.OFTInteger, + RESULT_TABLE_FIELD_WIJZIGING: ogr.OFTInteger, }, primary_key="id", geometry_column="geom", geometry_type=ogr.wkbCurvePolygon, ) + + +SETTINGS_TABLE_SCHEMA = TableSchema( + fields={ + #"fid": ogr.OFTInteger, + SETTINGS_TABLE_FIELD_ID: ogr.OFTInteger, + SETTINGS_TABLE_FIELD_TIJD_START: ogr.OFTDateTime, + SETTINGS_TABLE_FIELD_TIJD_EIND: ogr.OFTDateTime, + SETTINGS_TABLE_FIELD_DOWNLOAD_BGT:ogr.OFTInteger, + SETTINGS_TABLE_FIELD_DOWNLOAD_GWSW:ogr.OFTInteger, + SETTINGS_TABLE_FIELD_DOWNLOAD_BAG:ogr.OFTInteger, + SETTINGS_TABLE_FIELD_PAD_BGT: ogr.OFTString, + SETTINGS_TABLE_FIELD_PAD_GWSW: ogr.OFTString, + SETTINGS_TABLE_FIELD_PAD_BAG: ogr.OFTString, + SETTINGS_TABLE_FIELD_PAD_KOLKEN: ogr.OFTString, + SETTINGS_TABLE_FIELD_AFSTAND_AFWATERINGSVOORZIENING: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_OPP_WATER: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_PAND_OPP_WATER: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_VERHARD_KOLK: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_AFKOPPELD: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFSTAND_DRIEVOUDIG: ogr.OFTReal, + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_ERF: ogr.OFTReal, + SETTINGS_TABLE_FIELD_VERHARDINGSGRAAD_HALF_VERHARD: ogr.OFTReal, + SETTINGS_TABLE_FIELD_AFKOPPELEN_HELLEND: ogr.OFTReal, + SETTINGS_TABLE_FIELD_BOUWJAAR_GESCHEIDEN_BINNENHUIS: ogr.OFTInteger, + SETTINGS_TABLE_FIELD_LEIDINGCODES_KOPPELEN: ogr.OFTReal, + }, + primary_key="run_id", + geometry_column="", #settings table has no geometry + geometry_type=ogr.wkbNone, +) + +STATISTICS_TABLE_SCHEMA = TableSchema( + fields={ + #"fid": ogr.OFTInteger, + STATISTICS_TABLE_FIELD_ID: ogr.OFTInteger, + STATISTICS_TABLE_FIELD_OPP_TOTAAL: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER: ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD: ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_TOTAAL_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GEMENGD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_HWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_VGS_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_INFILTRATIEVOORZIENING_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_WATER_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_MAAIVELD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GEMENGD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_HWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_VGS_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DWA_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_INFILTRATIEVOORZIENING_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_WATER_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_MAAIVELD_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_GROEN_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_WATERPAS_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_OPP_WATER:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GESL_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_OPEN_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_ONVERHARD:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_GROEN_DAK:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_WATERPAS_VERH:ogr.OFTReal, + STATISTICS_TABLE_FIELD_PERC_WATER:ogr.OFTReal, + }, + primary_key="id", + geometry_column="geom", + geometry_type=ogr.wkbCurvePolygon, +) + +CHECKS_TABLE_SCHEMA = TableSchema( + fields={ + CHECKS_TABLE_FIELD_ID: ogr.OFTInteger, + CHECKS_TABLE_FIELD_LEVEL: ogr.OFTString, + CHECKS_TABLE_FIELD_CODE: ogr.OFTInteger, + CHECKS_TABLE_FIELD_TABLE: ogr.OFTString, + CHECKS_TABLE_FIELD_COLUMN: ogr.OFTString, + CHECKS_TABLE_FIELD_VALUE: ogr.OFTString, + CHECKS_TABLE_FIELD_DESCRIPTION: ogr.OFTString, + }, + primary_key="id", + geometry_column="geom", + geometry_type=ogr.wkbCurvePolygon, +) \ No newline at end of file diff --git a/docs/Handleiding BGT-inlooptool ArcGIS Pro.docx b/docs/Handleiding BGT-inlooptool ArcGIS Pro.docx index c2d17e6..a09dc4d 100644 Binary files a/docs/Handleiding BGT-inlooptool ArcGIS Pro.docx and b/docs/Handleiding BGT-inlooptool ArcGIS Pro.docx differ diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..ebee953 --- /dev/null +++ b/pylintrc @@ -0,0 +1,36 @@ +[MESSAGES CONTROL] +# DEFINITELY INCOMPATIBLE WITH VIKTOR +# POSSIBLY NOT NEEDED FOR VIKTOR +# R0903 Too few public methods +# C0103 Invalid name Variables in Viktor (lowercase) look like constants to pylint (uppercase) +# Single-letter names are banned (m for model, d for designer) +# ! Should be set only for parametrization modules +# E0611: No name 'SetParametersResult' in module 'viktor.result' (no-name-in-module) +# R1705 Unnecessary elif after return Pylint seems to prefer the ternary operator over if-else statements. +# R0914 Too many local variables +# W0702 No exception type(s) specified +# W0511 No TODOs allowed +# R0912 Too many branches +# R0913 Too many arguments +# E0012 Bad option value +disable= C0111, + C0411, + E0611, + R0801, + R0201, + C0301, + C0103, + R0903, + R1705, + E0401, + R0914, + W0511, + R0913, + R0912, + E0012, + R0902, + W0703, + W0613, + R0915, + C0302, + R1702 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3afa82f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,5 @@ +[tool.pylint.messages_control] +max-line-length = 120 + +[tool.black] +line-length = 120 diff --git a/test-data/akersloot/statistiek_gebieden_buurten.cpg b/test-data/akersloot/statistiek_gebieden_buurten.cpg new file mode 100644 index 0000000..3ad133c --- /dev/null +++ b/test-data/akersloot/statistiek_gebieden_buurten.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/test-data/akersloot/statistiek_gebieden_buurten.dbf b/test-data/akersloot/statistiek_gebieden_buurten.dbf new file mode 100644 index 0000000..bffb6fa Binary files /dev/null and b/test-data/akersloot/statistiek_gebieden_buurten.dbf differ diff --git a/test-data/akersloot/statistiek_gebieden_buurten.prj b/test-data/akersloot/statistiek_gebieden_buurten.prj new file mode 100644 index 0000000..32540b1 --- /dev/null +++ b/test-data/akersloot/statistiek_gebieden_buurten.prj @@ -0,0 +1 @@ +PROJCS["RD_New",GEOGCS["GCS_Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Double_Stereographic"],PARAMETER["False_Easting",155000.0],PARAMETER["False_Northing",463000.0],PARAMETER["Central_Meridian",5.38763888888889],PARAMETER["Scale_Factor",0.9999079],PARAMETER["Latitude_Of_Origin",52.1561605555556],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/test-data/akersloot/statistiek_gebieden_buurten.qmd b/test-data/akersloot/statistiek_gebieden_buurten.qmd new file mode 100644 index 0000000..9fbe67c --- /dev/null +++ b/test-data/akersloot/statistiek_gebieden_buurten.qmd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + diff --git a/test-data/akersloot/statistiek_gebieden_buurten.shp b/test-data/akersloot/statistiek_gebieden_buurten.shp new file mode 100644 index 0000000..cebf06c Binary files /dev/null and b/test-data/akersloot/statistiek_gebieden_buurten.shp differ diff --git a/test-data/akersloot/statistiek_gebieden_buurten.shx b/test-data/akersloot/statistiek_gebieden_buurten.shx new file mode 100644 index 0000000..dff5839 Binary files /dev/null and b/test-data/akersloot/statistiek_gebieden_buurten.shx differ