changeset 2491:7247eb03e7c0 critical-bottlenecks

merged default into critical-bottlenecks branch
author Markus Kottlaender <markus@intevation.de>
date Mon, 04 Mar 2019 08:32:05 +0100
parents ae1987c5beb3 (current diff) 204b0baac93c (diff)
children 9d9c6425db82
files client/src/components/Maplayer.vue client/src/store/map.js
diffstat 10 files changed, 207 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/Maplayer.vue	Fri Mar 01 14:55:58 2019 +0100
+++ b/client/src/components/Maplayer.vue	Mon Mar 04 08:32:05 2019 +0100
@@ -337,6 +337,21 @@
     );
     layer.data.setVisible(layer.isVisible);
 
+    layer = this.getLayerByName(LAYERS.GAUGES);
+    layer.data.getSource().setLoader(
+      this.buildVectorLoader(
+        {
+          featureNS: "gemma",
+          featurePrefix: "gemma",
+          featureTypes: ["gauges_geoserver"],
+          geometryName: "geom"
+        },
+        "/internal/wfs",
+        layer.data.getSource()
+      )
+    );
+    layer.data.setVisible(layer.isVisible);
+
     layer = this.getLayerByName(LAYERS.STRETCHES);
     layer.data.getSource().setLoader(
       this.buildVectorLoader(
--- a/client/src/components/Search.vue	Fri Mar 01 14:55:58 2019 +0100
+++ b/client/src/components/Search.vue	Mon Mar 04 08:32:05 2019 +0100
@@ -58,6 +58,12 @@
             class="mr-1"
             fixed-width
           />
+          <font-awesome-icon
+            icon="ruler"
+            v-if="entry.type === 'gauge'"
+            class="mr-1"
+            fixed-width
+          />
           {{ entry.name }}
         </a>
       </div>
@@ -269,6 +275,7 @@
         if (resultEntry.type === "bottleneck") zoom = 17;
         if (resultEntry.type === "rhm") zoom = 15;
         if (resultEntry.type === "city") zoom = 13;
+        if (resultEntry.type === "gauge") zoom = 15;
         this.$store.commit("map/moveMap", {
           coordinates: resultEntry.geom.coordinates,
           zoom,
--- a/client/src/components/Sidebar.vue	Fri Mar 01 14:55:58 2019 +0100
+++ b/client/src/components/Sidebar.vue	Mon Mar 04 08:32:05 2019 +0100
@@ -199,10 +199,8 @@
         this.contextBoxContent === item &&
         this.routeName == "mainview"
       );
-    }
-  },
-  mounted() {
-    setTimeout(() => {
+    },
+    updateIndicators() {
       this.$store.dispatch("imports/getStaging").catch(error => {
         const { status, data } = error.response;
         displayError({
@@ -210,7 +208,11 @@
           message: `${status}: ${data.message || data}`
         });
       });
-    }, 15000);
+    }
+  },
+  mounted() {
+    this.updateIndicators();
+    setTimeout(this.updateIndicators, 15000);
   }
 };
 </script>
--- a/client/src/components/identify/formatter.js	Fri Mar 01 14:55:58 2019 +0100
+++ b/client/src/components/identify/formatter.js	Mon Mar 04 08:32:05 2019 +0100
@@ -37,6 +37,9 @@
   },
   stretches_geoserver: {
     label: "Stretch"
+  },
+  gauges_geoserver: {
+    label: "Gauge"
   }
 };
 
--- a/client/src/store/map.js	Fri Mar 01 14:55:58 2019 +0100
+++ b/client/src/store/map.js	Mon Mar 04 08:32:05 2019 +0100
@@ -20,7 +20,15 @@
 import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
 import OSM from "ol/source/OSM";
 import Draw from "ol/interaction/Draw.js";
-import { Icon, Stroke, Style, Fill, Text, Circle } from "ol/style.js";
+import {
+  Icon,
+  Stroke,
+  Style,
+  Fill,
+  Text,
+  Circle,
+  RegularShape
+} from "ol/style.js";
 import VectorSource from "ol/source/Vector.js";
 import Point from "ol/geom/Point.js";
 import { bbox as bboxStrategy } from "ol/loadingstrategy";
@@ -48,6 +56,7 @@
   BOTTLENECKISOLINE: "Bottleneck isolines",
   DISTANCEMARKS: "Distance marks",
   DISTANCEMARKSAXIS: "Distance marks, Axis",
+  GAUGES: "Gauges",
   DRAWTOOL: "Draw Tool",
   CUTTOOL: "Cut Tool"
 };
@@ -401,6 +410,39 @@
         showInLegend: true
       },
       {
+        name: LAYERS.GAUGES,
+        forLegendStyle: { point: true, resolution: 8 },
+        data: new VectorLayer({
+          source: new VectorSource({
+            strategy: bboxStrategy
+          }),
+          style: function(feature) {
+            return new Style({
+              image: new RegularShape({
+                radius: 6,
+                fill: new Fill({ color: "rgba(255, 255, 0, 0.1)" }),
+                stroke: new Stroke({ color: "red", width: 1 }),
+                points: 3,
+                rotation: 0,
+                angle: 0
+              }),
+              text: new Text({
+                font: '10px "Open Sans", "sans-serif"',
+                offsetY: 10,
+                fill: new Fill({
+                  color: "black"
+                }),
+                text: feature.get("objname")
+              })
+            });
+          },
+          maxResolution: 100,
+          minResolution: 0
+        }),
+        isVisible: true,
+        showInLegend: true
+      },
+      {
         name: LAYERS.DRAWTOOL,
         data: new VectorLayer({
           source: new VectorSource({ wrapX: false }),
--- a/schema/demo-data/published_services.sql	Fri Mar 01 14:55:58 2019 +0100
+++ b/schema/demo-data/published_services.sql	Mon Mar 04 08:32:05 2019 +0100
@@ -14,6 +14,7 @@
 INSERT INTO sys_admin.published_services (name) VALUES
     ('waterway.stretches_geoserver'),
     ('waterway.fairway_dimensions'),
+    ('waterway.gauges_geoserver'),
     ('waterway.distance_marks_ashore_geoserver'),
     ('waterway.distance_marks_geoserver'),
     ('waterway.sounding_results_contour_lines_geoserver'),
--- a/schema/gemma.sql	Fri Mar 01 14:55:58 2019 +0100
+++ b/schema/gemma.sql	Mon Mar 04 08:32:05 2019 +0100
@@ -252,6 +252,28 @@
         value int NOT NULL
     )
 
+    CREATE VIEW gauges_geoserver AS
+    SELECT
+        g.location,
+        isrs_asText(g.location) AS isrs_code,
+        g.objname,
+        g.geom,
+        g.applicability_from_km,
+        g.applicability_to_km,
+        g.validity,
+        g.zero_point,
+        g.geodref,
+        g.date_info,
+        g.source_organization,
+        json_strip_nulls(json_object_agg(coalesce(r.depth_reference,'empty'),
+                                                  r.value))
+            AS reference_water_levels
+    FROM gauges g LEFT JOIN LATERAL (
+            SELECT gauge_id, depth_reference, value
+            FROM gauges_reference_water_levels
+            ) r ON r.gauge_id = g.location
+    GROUP BY g.location
+
     CREATE TABLE gauge_measurements (
         id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
         fk_gauge_id isrs NOT NULL REFERENCES gauges,
@@ -630,6 +652,7 @@
 
 -- Configure primary keys for geoserver views
 INSERT INTO waterway.gt_pk_metadata VALUES
+  ('waterway', 'gauges_geoserver', 'location'),
   ('waterway', 'distance_marks_geoserver', 'location_code'),
   ('waterway', 'distance_marks_ashore_geoserver', 'id'),
   ('waterway', 'bottlenecks_geoserver', 'id'),
--- a/schema/isrs_functions.sql	Fri Mar 01 14:55:58 2019 +0100
+++ b/schema/isrs_functions.sql	Mon Mar 04 08:32:05 2019 +0100
@@ -12,19 +12,20 @@
 --  * Tom Gottfried <tom@intevation.de>
 --  * Sascha Wilde <wilde@intevation.de>
 
--- Clip an area to a stretch given by a pair of ISRS location codes.
+CREATE OR REPLACE FUNCTION best_utm(stretch isrsrange) RETURNS integer
+AS $$
+    SELECT best_utm(ST_Collect(geom::geometry))
+        FROM waterway.distance_marks_virtual
+        WHERE location_code IN (lower(stretch), upper(stretch))
+    $$
+    LANGUAGE sql
+    STABLE PARALLEL SAFE;
+
+-- Clip waterway axis to a stretch given by a pair of ISRS location codes.
 -- Uses the table waterway.distance_marks_virtual to map ISRS location codes
--- to their geo-location and the table waterway.waterway_axis to retrieve
--- perpendicular direction at these geo-locations.
--- Distance marks are assumed to be near the axis and the area passed as
--- argument is assumed to intersect with the axis
--- (use e.g. waterway area or fairway dimensions).
--- If a multipolygon is passed, the union of the polygons intersecting with the
--- relevant part of the axis is used for clipping.
-CREATE OR REPLACE FUNCTION ISRSrange_area(
-    stretch isrsrange,
-    area geometry
-) RETURNS geometry
+-- to their geo-location.
+-- Distance marks are assumed to be near the axis.
+CREATE OR REPLACE FUNCTION ISRSrange_axis(stretch isrsrange) RETURNS geometry
 AS $$
     WITH RECURSIVE
         -- Get coordinates of location codes
@@ -34,8 +35,7 @@
                     OR location_code = upper(stretch)),
         utm_zone AS (
             -- Find best matchting UTM zone
-            SELECT best_utm(ST_Collect(geom::geometry)) AS z
-                FROM points_geog),
+            SELECT best_utm(stretch) AS z),
         axis AS (
             SELECT id, ST_Transform(wtwaxs::geometry, z) AS wtwaxs
                 FROM waterway.waterway_axis, utm_zone),
@@ -66,11 +66,8 @@
                         SELECT refgeom
                         UNION
                         -- Fill eventual gap
-                        SELECT ST_MakeLine(
-                            ST_ClosestPoint(
-                                ST_Boundary(refgeom), ST_Boundary(geom)),
-                            ST_ClosestPoint(
-                                ST_Boundary(geom), ST_Boundary(refgeom)))
+                        SELECT ST_ShortestLine(
+                                ST_Boundary(refgeom), ST_Boundary(geom))
                         UNION
                         -- Linestring to be added
                         SELECT geom)))
@@ -87,23 +84,43 @@
             SELECT wtwaxs AS line
                 FROM axis_snapped
                 WHERE array_length(ids, 1) = (
-                    SELECT max(array_length(ids, 1)) FROM axis_snapped)),
+                    SELECT max(array_length(ids, 1)) FROM axis_snapped))
+        -- Use linear referencing to clip axis between distance marks.
+        -- Simplification is used to work-around the problem, that
+        -- ST_LineSubstring might generate very small line segments at an
+        -- end of the resulting linestring, that significantly differ from
+        -- the direction of the input linestring due to finite precision
+        -- of the calculation. The generated small segment of the
+        -- resulting line leads to unexpected results of the buffer with
+        -- endcap=flat in the CTE below.
+        SELECT ST_SimplifyPreserveTopology(ST_LineSubstring(
+                    axis_segment.line, min(fractions.f), max(fractions.f)),
+                0.0001) AS line
+        FROM axis_segment, LATERAL (
+            SELECT ST_LineLocatePoint(axis_segment.line, points.geom) AS f
+                FROM points) AS fractions
+        GROUP BY axis_segment.line
+    $$
+    LANGUAGE sql
+    STABLE PARALLEL SAFE;
+
+-- Clip an area to a stretch given by a pair of ISRS location codes.
+-- Uses ISRSrange_axis() to retrieve the respective clipped axis used to find
+-- perpendicular direction at geo-locations of ISRS codes.
+-- The area passed as argument is assumed to intersect with the axis
+-- (use e.g. waterway area or fairway dimensions).
+-- If a multipolygon is passed, the union of the polygons intersecting with the
+-- relevant part of the axis is used for clipping.
+CREATE OR REPLACE FUNCTION ISRSrange_area(
+    stretch isrsrange,
+    area geometry
+) RETURNS geometry
+AS $$
+    WITH
         axis_substring AS (
-            -- Use linear referencing to clip axis between distance marks.
-            -- Simplification is used to work-around the problem, that
-            -- ST_LineSubstring might generate very small line segments at an
-            -- end of the resulting linestring, that significantly differ from
-            -- the direction of the input linestring due to finite precision
-            -- of the calculation. The generated small segment of the
-            -- resulting line leads to unexpected results of the buffer with
-            -- endcap=flat in the CTE below.
-            SELECT ST_SimplifyPreserveTopology(ST_LineSubstring(
-                        axis_segment.line, min(fractions.f), max(fractions.f)),
-                    0.0001) AS line
-            FROM axis_segment, LATERAL (
-                SELECT ST_LineLocatePoint(axis_segment.line, points.geom) AS f
-                    FROM points) AS fractions
-            GROUP BY axis_segment.line),
+            SELECT ISRSrange_axis(stretch) AS line),
+        utm_zone AS (
+            SELECT best_utm(stretch) AS z),
         area_subset AS (
             -- In case area is a multipolygon, process the union of those
             -- polygons, which intersect with the axis. The union is to avoid
--- a/schema/isrs_tests.sql	Fri Mar 01 14:55:58 2019 +0100
+++ b/schema/isrs_tests.sql	Mon Mar 04 08:32:05 2019 +0100
@@ -42,26 +42,24 @@
     ) IS NULL,
     'ISRSrange_area returns NULL, if given area does not intersect with axis');
 
-SELECT ok(
-    ST_DWithin(
-        (SELECT geom FROM waterway.distance_marks_virtual
-            WHERE location_code = ('AT', 'XXX', '00001', '00000', 0)::isrs),
-        ST_Boundary(ISRSrange_area(isrsrange(
-                ('AT', 'XXX', '00001', '00000', 0)::isrs,
-                ('AT', 'XXX', '00001', '00000', 1)::isrs),
-            (SELECT ST_Collect(CAST(area AS geometry))
-                FROM waterway.waterway_area))),
-        1)
-    AND
-    ST_DWithin(
-        (SELECT geom FROM waterway.distance_marks_virtual
-            WHERE location_code = ('AT', 'XXX', '00001', '00000', 1)::isrs),
-        ST_Boundary(ISRSrange_area(isrsrange(
-                ('AT', 'XXX', '00001', '00000', 0)::isrs,
-                ('AT', 'XXX', '00001', '00000', 1)::isrs),
-            (SELECT ST_Collect(CAST(area AS geometry))
-                FROM waterway.waterway_area))),
-        1),
+SELECT results_eq($$
+    SELECT every(ST_DWithin(
+            ST_Boundary(ISRSrange_area(
+                isrsrange(
+                    ('AT', 'XXX', '00001', '00000', 0)::isrs,
+                    ('AT', 'XXX', '00001', '00000', 1)::isrs),
+                (SELECT ST_Collect(CAST(area AS geometry))
+                    FROM waterway.waterway_area))),
+            geom,
+            1))
+        FROM waterway.distance_marks_virtual
+        WHERE location_code IN(
+            ('AT', 'XXX', '00001', '00000', 0)::isrs,
+            ('AT', 'XXX', '00001', '00000', 1)::isrs)
+    $$,
+    $$
+    SELECT true
+    $$,
     'Resulting polygon almost ST_Touches points corresponding to stretch');
 
 \set test_area 'POLYGON((-1 1, 2 1, 2 -1, -1 -1, -1 1))'
@@ -101,11 +99,22 @@
                 4326))),
     'Self-intersecting multipolygon leads to one polygon in result');
 
-SELECT ok(
-    ISRSrange_area(
-        isrsrange(
+SELECT results_eq($$
+    SELECT every(ST_DWithin(
+            ST_Boundary(ISRSrange_area(
+                isrsrange(
+                    ('AT', 'XXX', '00001', '00000', 0)::isrs,
+                    ('AT', 'XXX', '00001', '00000', 2)::isrs),
+                (SELECT ST_Collect(CAST(area AS geometry))
+                    FROM waterway.waterway_area))),
+            geom,
+            1))
+        FROM waterway.distance_marks_virtual
+        WHERE location_code IN(
             ('AT', 'XXX', '00001', '00000', 0)::isrs,
-            ('AT', 'XXX', '00001', '00000', 2)::isrs),
-        (SELECT ST_Collect(CAST(area AS geometry))
-            FROM waterway.waterway_area)) IS NOT NULL,
+            ('AT', 'XXX', '00001', '00000', 2)::isrs)
+    $$,
+    $$
+    SELECT true
+    $$,
     'Area generated from non-matching distance mark and non-contiguous axis');
--- a/schema/search_functions.sql	Fri Mar 01 14:55:58 2019 +0100
+++ b/schema/search_functions.sql	Mon Mar 04 08:32:05 2019 +0100
@@ -51,10 +51,30 @@
 END;
 $$;
 
+CREATE OR REPLACE FUNCTION search_gauges(search_string text) RETURNS jsonb
+  LANGUAGE plpgsql
+  AS $$
+DECLARE
+  _result jsonb;
+BEGIN
+  SELECT COALESCE(json_agg(r),'[]')
+    INTO _result
+    FROM (SELECT objname AS name,
+                 ST_AsGeoJSON(geom)::json AS geom,
+                 'gauge' AS type
+            FROM waterway.gauges
+            WHERE objname ILIKE '%' || search_string || '%'
+          ORDER BY name) r;
+  RETURN _result;
+END;
+$$;
+
 CREATE OR REPLACE FUNCTION search_most(search_string text) RETURNS jsonb
   LANGUAGE plpgsql
   AS $$
 BEGIN
-  RETURN search_bottlenecks(search_string) || search_cities(search_string);
+  RETURN search_bottlenecks(search_string)
+         || search_gauges(search_string)
+         || search_cities(search_string);
 END;
 $$;