changeset 4615:32d3e0cecf4f geoserver_sql_views

Merge default into geoserver_sql_views
author Tom Gottfried <tom@intevation.de>
date Mon, 09 Sep 2019 17:46:51 +0200
parents 970e90d3d5eb (current diff) 496bbf0f618c (diff)
children b605e91f08f0
files schema/default_sysconfig.sql schema/demo-data/published_services.sql
diffstat 7 files changed, 149 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/client/docs/developers.md	Mon Sep 09 17:24:07 2019 +0200
+++ b/client/docs/developers.md	Mon Sep 09 17:46:51 2019 +0200
@@ -36,16 +36,16 @@
 ```javascript
 data = store.state.fairwayavailability.csv  // see current data
 
-data=`#time,# < LDC (164.0) [h],# >= LDC (164.0) [h],# < 230.0 [h],# >= 230.0 [h],# >= 250.0 [h]
-01-2019,0  ,744,  0,  0,744
-02-2019,324,324,150,174,324
-03-2019, 24,696, 80, 45, 50
-04-2019,120,600, 24, 24,672.5
-05-2019,140,80 , 80, 45, 50
-06-2019,  0,  0,  0,  0,  0.000
-07-2019,  0,300,  0,  0,  0
-08-2019,  0,  0,744,  0,  0
-09-2019,  0,720,  0, 96,624
+data=`#time,# < LDC (164.0) [d],# >= LDC (164.0) [d],# < 230.0 [d],# >= 230.0 [d],# >= 250.0 [d]
+01-2019, 0,31, 0, 0,31
+02-2019,14,14, 6, 8,14
+03-2019, 1,30, 3, 2, 2
+04-2019, 5,25, 1, 1,28
+05-2019, 6,25, 3, 2, 3
+06-2019, 0, 0, 0, 0, 0
+07-2019, 0,16, 0, 0, 0
+08-2019, 0, 0,31, 0, 0
+09-2019, 0, 9, 0, 3, 9
 `
 
 store.commit("fairwayavailability/setAvailableFairwayDepthData", data)
@@ -55,8 +55,7 @@
 ```javascript
 data = store.state.fairwayavailability.csv  // see current data
 
-data=`
-#time,# < LDC (162.0) [h],# >= LDC (162.0) [h],#d < 230.0 [%],#d >= 230.0 [%],#d >= 250.0 [%]
+data=`#time,# < LDC (162.0) [h],# >= LDC (162.0) [h],#d < 230.0 [%],#d >= 230.0 [%],#d >= 250.0 [%]
 09-2018,100,  0,100  ,    0,  0
 10-2018,100,  0, 80  ,   20,  0
 11-2018,100,  0,  0  ,  100,  0
--- a/client/src/components/fairway/AvailableFairwayDepth.vue	Mon Sep 09 17:24:07 2019 +0200
+++ b/client/src/components/fairway/AvailableFairwayDepth.vue	Mon Sep 09 17:46:51 2019 +0200
@@ -93,15 +93,6 @@
 import { FREQUENCIES } from "@/store/fairwayavailability";
 import { defaultDiagramTemplate } from "@/lib/DefaultDiagramTemplate";
 
-// FIXME This is a rounding methods that shows that we have fractions,
-// because we are coming from hours.  Users will understand the underlying
-// math better and we can see if this is wanted.
-// With the backend just giving us the summarized hours, we cannot do
-// a classification of each day into a category.
-// (The name of the function is kept to keep the diff more readable and
-// should changed if this is more clarified.)
-const hoursInDays = x => Math.round((x * 10) / 24) / 10;
-
 export default {
   mixins: [diagram, pdfgen, templateLoader],
   components: {
@@ -475,19 +466,15 @@
             .querySelector(".diagram-container")
             .getBoundingClientRect().left;
           d3.select("#tooltip")
-            .text(hoursInDays(d.height))
+            .text(d.height)
             .attr("y", y - 10)
             .attr("x", d3.event.pageX - dy);
           //d3.event.pageX gives coordinates relative to SVG
           //dy gives offset of svg on page
         })
-        .attr("y", d => {
-          return (
-            2 * yScale(0) - yScale(hoursInDays(d.translateY)) + this.paddingTop
-          );
-        })
+        .attr("y", d => 2 * yScale(0) - yScale(d.translateY) + this.paddingTop)
         .attr("height", d => {
-          return yScale(0) - yScale(hoursInDays(d.height));
+          return yScale(0) - yScale(d.height);
         })
         .attr("x", ldcOffset + spaceBetween / 2)
         .attr("width", widthPerItem - ldcOffset - spaceBetween)
@@ -500,19 +487,19 @@
           .selectAll("g.bars")
           .data(d => d.lowerLevels)
           .enter()
-          .filter(d => hoursInDays(d.height) > 0)
+          .filter(d => d.height > 0)
           .insert("text")
           .attr("y", d => {
             return (
               2 * yScale(0) -
-              yScale(hoursInDays(d.translateY)) +
+              yScale(d.translateY) +
               this.paddingTop +
-              (yScale(0) - yScale(hoursInDays(d.height))) +
+              (yScale(0) - yScale(d.height)) +
               (yScale(0) - yScale(1.9)) //instead o alignment-baseline hanging
             );
           })
           .attr("x", widthPerItem / 2)
-          .text(d => hoursInDays(d.height))
+          .text(d => d.height)
           // does not work with svg2pdf .attr("alignment-baseline", "hanging")
           .attr("text-anchor", "middle")
           .attr("font-size", "8")
@@ -520,7 +507,7 @@
       }
     },
     fnheight({ name, yScale }) {
-      return d => yScale(0) - yScale(hoursInDays(d[name]));
+      return d => yScale(0) - yScale(d[name]);
     },
     drawLDC({ everyBar, yScale, widthPerItem, spaceBetween, ldcOffset }) {
       const height = this.fnheight({ name: "ldc", yScale });
@@ -540,7 +527,7 @@
             .querySelector(".diagram-container")
             .getBoundingClientRect().left;
           d3.select("#tooltip")
-            .text(hoursInDays(d.ldc))
+            .text(d.ldc)
             .attr("y", y - 50)
             .attr("x", d3.event.pageX - dy);
           //d3.event.pageX gives coordinates relative to SVG
@@ -558,11 +545,11 @@
         .attr("id", "ldc");
       if (this.showNumbers) {
         everyBar
-          .filter(d => hoursInDays(d.ldc) > 0)
+          .filter(d => d.ldc > 0)
           .append("text")
           .attr("y", yScale(0.5)) // some distance from the bar
           .attr("x", spaceBetween / 2)
-          .text(d => hoursInDays(d.ldc))
+          .text(d => d.ldc)
           .attr("text-anchor", "left")
           .attr("font-size", "8")
           .attr(
@@ -596,7 +583,7 @@
             .querySelector(".diagram-container")
             .getBoundingClientRect().left;
           d3.select("#tooltip")
-            .text(hoursInDays(d.highestLevel))
+            .text(d.highestLevel)
             .attr("y", y - 50)
             .attr("x", d3.event.pageX - dy);
           //d3.event.pageX gives coordinates relative to SVG
@@ -613,11 +600,11 @@
         .attr("fill", this.$options.COLORS.HIGHEST);
       if (this.showNumbers) {
         everyBar
-          .filter(d => hoursInDays(d.highestLevel) > 0)
+          .filter(d => d.highestLevel > 0)
           .append("text")
           .attr("y", yScale(0.5)) // some distance from the bar
           .attr("x", widthPerItem / 2)
-          .text(d => hoursInDays(d.highestLevel))
+          .text(d => d.highestLevel)
           .attr("text-anchor", "middle")
           .attr("font-size", "8")
           .attr(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/common/round.go	Mon Sep 09 17:46:51 2019 +0200
@@ -0,0 +1,71 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha Wilde <wilde@sha-bang.de>
+
+package common
+
+import (
+	"math"
+	"sort"
+	"time"
+)
+
+type Rest struct {
+	Key  int
+	Rest float64
+}
+
+// Simple sum preserving rounding method:
+func SumPreservingRound(arr []float64) []int {
+	var (
+		sum   float64
+		rests []Rest
+	)
+	result := make([]int, len(arr))
+
+	// floor all values
+	for i, v := range arr {
+		sum += v
+		result[i] = int(v)
+		rests = append(rests, Rest{Key: i, Rest: v - float64(result[i])})
+	}
+
+	// find the difference in summs
+	var newSum int
+	for _, v := range result {
+		newSum += v
+	}
+	delta := int(math.Round(sum)) - newSum
+
+	// spread delta over values with highest rest
+	sort.Slice(rests, func(i, j int) bool {
+		return rests[i].Rest > rests[j].Rest
+	})
+	for _, v := range rests {
+		if delta <= 0 {
+			break
+		}
+		result[v.Key]++
+		delta--
+	}
+
+	return result
+}
+
+// Round anarray of Duratons to full days
+func RoundToFullDays(durations []time.Duration) []int {
+	days := make([]float64, len(durations))
+	for i, v := range durations {
+		days[i] = v.Hours() / 24
+	}
+	return SumPreservingRound(days)
+}
--- a/pkg/controllers/bottlenecks.go	Mon Sep 09 17:24:07 2019 +0200
+++ b/pkg/controllers/bottlenecks.go	Mon Sep 09 17:46:51 2019 +0200
@@ -503,8 +503,8 @@
 
 	record := make([]string, 1+2+len(breaks)+1)
 	record[0] = "#time"
-	record[1] = fmt.Sprintf("# < LDC (%.1f) [h]", ldcRefs[0])
-	record[2] = fmt.Sprintf("# >= LDC (%.1f) [h]", ldcRefs[0])
+	record[1] = fmt.Sprintf("# < LDC (%.1f) [%%]", ldcRefs[0])
+	record[2] = fmt.Sprintf("# >= LDC (%.1f) [%%]", ldcRefs[0])
 	for i, v := range breaks {
 		if i == 0 {
 			record[3] = fmt.Sprintf("#d < %.1f [%%]", v)
@@ -653,13 +653,13 @@
 	// label, ldc, classes
 	record := make([]string, 1+2+len(breaks)+1)
 	record[0] = "#time"
-	record[1] = fmt.Sprintf("# < LDC (%.1f) [h]", ldcRefs[0])
-	record[2] = fmt.Sprintf("# >= LDC (%.1f) [h]", ldcRefs[0])
+	record[1] = fmt.Sprintf("# < LDC (%.1f) [d]", ldcRefs[0])
+	record[2] = fmt.Sprintf("# >= LDC (%.1f) [d]", ldcRefs[0])
 	for i, v := range breaks {
 		if i == 0 {
-			record[3] = fmt.Sprintf("# < %.1f [h]", v)
+			record[3] = fmt.Sprintf("# < %.1f [d]", v)
 		}
-		record[i+4] = fmt.Sprintf("# >= %.1f [h]", v)
+		record[i+4] = fmt.Sprintf("# >= %.1f [d]", v)
 	}
 
 	if err := out.Write(record); err != nil {
@@ -701,13 +701,17 @@
 			access,
 		)
 
+		// Round to full days
+		ldcRounded := common.RoundToFullDays(ldc)
+		rangesRounded := common.RoundToFullDays(ranges)
+
 		record[0] = label
-		for i, v := range ldc {
-			record[i+1] = fmt.Sprintf("%.3f", v.Hours())
+		for i, v := range ldcRounded {
+			record[i+1] = fmt.Sprintf("%d", v)
 		}
 
-		for i, d := range ranges {
-			record[3+i] = fmt.Sprintf("%.3f", d.Hours())
+		for i, d := range rangesRounded {
+			record[3+i] = fmt.Sprintf("%d", d)
 		}
 
 		if err := out.Write(record); err != nil {
--- a/pkg/controllers/stretches.go	Mon Sep 09 17:24:07 2019 +0200
+++ b/pkg/controllers/stretches.go	Mon Sep 09 17:46:51 2019 +0200
@@ -27,6 +27,7 @@
 
 	"github.com/gorilla/mux"
 
+	"gemma.intevation.de/gemma/pkg/common"
 	"gemma.intevation.de/gemma/pkg/middleware"
 )
 
@@ -348,19 +349,19 @@
 	// label, lnwl, classes
 	record := make([]string, 1+2+len(breaks)+1)
 	record[0] = "# time"
-	record[1] = "# < LDC [h]"
-	record[2] = "# >= LDC [h]"
+	record[1] = "# < LDC [d]"
+	record[2] = "# >= LDC [d]"
 	for i, v := range breaks {
 		if useDepth && useWidth {
 			if i == 0 {
-				record[3] = "# < break_1 [h]"
+				record[3] = "# < break_1 [d]"
 			}
 			record[i+4] = fmt.Sprintf("# >= break_%d", i+1)
 		} else {
 			if i == 0 {
-				record[3] = fmt.Sprintf("# < %.1f [h]", v)
+				record[3] = fmt.Sprintf("# < %.1f [d]", v)
 			}
-			record[i+4] = fmt.Sprintf("# >= %.1f [h]", v)
+			record[i+4] = fmt.Sprintf("# >= %.1f [d]", v)
 		}
 	}
 
@@ -379,13 +380,23 @@
 	}
 
 	for _, r := range results {
-		record[0] = r.label
+		// Round to full days
 		for i, v := range r.ldc {
-			record[1+i] = fmt.Sprintf("%.3f", v.Hours()*scale)
+			r.ldc[i] = time.Duration(float64(v) * scale)
+		}
+		for i, v := range r.breaks {
+			r.breaks[i] = time.Duration(float64(v) * scale)
+		}
+		ldcRounded := common.RoundToFullDays(r.ldc)
+		rangesRounded := common.RoundToFullDays(r.breaks)
+
+		record[0] = r.label
+		for i, v := range ldcRounded {
+			record[1+i] = fmt.Sprintf("%d", v)
 		}
 
-		for i, d := range r.breaks {
-			record[3+i] = fmt.Sprintf("%.3f", d.Hours()*scale)
+		for i, d := range rangesRounded {
+			record[3+i] = fmt.Sprintf("%d", d)
 		}
 
 		if err := out.Write(record); err != nil {
--- a/schema/default_sysconfig.sql	Mon Sep 09 17:24:07 2019 +0200
+++ b/schema/default_sysconfig.sql	Mon Sep 09 17:46:51 2019 +0200
@@ -12,6 +12,7 @@
 --  * Sascha Wilde <wilde@intevation.de>
 --  * Bernhard Reiter <bernhard.reiter@intevation.de>
 --  * Fadi Abbund <fadi.abbud@intevation.de>
+--  * Tom Gottfried <tom@intevation.de>
 
 BEGIN;
 
@@ -20,6 +21,24 @@
 --
 
 --
+-- Tables and views published via GeoServer
+--
+INSERT INTO sys_admin.published_services (schema, name) VALUES
+    ('waterway', 'sections_geoserver'),
+    ('waterway', 'stretches_geoserver'),
+    ('waterway', 'fairway_dimensions'),
+    ('waterway', 'gauges_geoserver'),
+    ('waterway', 'distance_marks_ashore_geoserver'),
+    ('waterway', 'distance_marks_geoserver'),
+    ('waterway', 'sounding_results_contour_lines_geoserver'),
+    ('waterway', 'bottlenecks_geoserver'),
+    ('waterway', 'bottleneck_overview'),
+    ('waterway', 'waterway_axis'),
+    ('waterway', 'waterway_area'),
+    ('waterway', 'waterway_profiles'),
+    ('waterway', 'sounding_differences');
+
+--
 -- Settings
 --
 INSERT INTO sys_admin.system_config VALUES ('ecdis_wms_url', 'https://service.d4d-portal.info/wms/');
--- a/schema/demo-data/published_services.sql	Mon Sep 09 17:24:07 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
--- This is Free Software under GNU Affero General Public License v >= 3.0
--- without warranty, see README.md and license for details.
-
--- SPDX-License-Identifier: AGPL-3.0-or-later
--- License-Filename: LICENSES/AGPL-3.0.txt
-
--- Copyright (C) 2018 by via donau
---   – Österreichische Wasserstraßen-Gesellschaft mbH
--- Software engineering by Intevation GmbH
-
--- Author(s):
---  * Tom Gottfried <tom@intevation.de>
-
-INSERT INTO sys_admin.published_services (schema, name, view_def) VALUES
-    ('waterway', 'sections_geoserver', NULL),
-    ('waterway', 'stretches_geoserver', NULL),
-    ('waterway', 'fairway_dimensions', NULL),
-    ('waterway', 'gauges_geoserver', NULL),
-    ('waterway', 'distance_marks_ashore_geoserver', NULL),
-    ('waterway', 'distance_marks_geoserver', NULL),
-    ('waterway', 'sounding_results_contour_lines_geoserver', NULL),
-    ('waterway', 'bottlenecks_geoserver', NULL),
-    ('waterway', 'bottleneck_overview', NULL),
-    ('waterway', 'waterway_axis', NULL),
-    ('waterway', 'waterway_area', NULL),
-    ('waterway', 'waterway_profiles', NULL),
-    ('waterway', 'sounding_differences', NULL)
-ON CONFLICT DO NOTHING