# HG changeset patch # User Markus Kottlaender # Date 1561563771 -7200 # Node ID 36129677ff24014e29fbac9f8c0c2745ff19bf41 # Parent a1bb7c8940589eaf811a402538172e08edd605fd fetch data for sld template from data base and interpolate colors (WIP) diff -r a1bb7c894058 -r 36129677ff24 pkg/geoserver/boot.go --- a/pkg/geoserver/boot.go Wed Jun 26 14:17:18 2019 +0200 +++ b/pkg/geoserver/boot.go Wed Jun 26 17:42:51 2019 +0200 @@ -14,18 +14,24 @@ package geoserver import ( + "context" "bytes" "encoding/json" "encoding/xml" "fmt" + "strconv" + "math" "io" "log" "net/http" "net/url" "strings" + "text/template" + "database/sql" "golang.org/x/net/html/charset" + "gemma.intevation.de/gemma/pkg/auth" "gemma.intevation.de/gemma/pkg/config" "gemma.intevation.de/gemma/pkg/models" ) @@ -36,11 +42,12 @@ databaseScheme = "waterway" databaseType = "postgis" primaryKeyMetadataTbl = "waterway.gt_pk_metadata" -) -const ( + bootRole = "sys_admin" + startupSQL = `SELECT public.setrole('${user,'||encode('waterway_user', 'hex')||'}')` closeupSQL = `RESET ROLE` + selectClassBreaksSQL = `SELECT config_val FROM sys_admin.system_config WHERE config_key = 'morphology_classbreaks'` ) func basicAuth(user, password string) func(req *http.Request) { @@ -391,6 +398,114 @@ return nil } +type classBreak struct { + Low string + High string + Color string +} + +func interpolateColor(i int, classBreaks [][]string) string { + var leftColor, rightColor string + + // look for next color to the left + lookLeft := i + for lookLeft >= 0 && leftColor == "" { + lookLeft -= 1 + if len(classBreaks[lookLeft]) == 2 { + leftColor = classBreaks[lookLeft][1] + } + } + // look for next color to the right + lookRight := i + for lookRight < len(classBreaks) && rightColor == "" { + lookRight += 1 + if len(classBreaks[lookRight]) == 2 { + rightColor = classBreaks[lookRight][1] + } + } + + // calculate interpolation factor + middle, left, right := float32(i), float32(lookLeft), float32(lookRight) + interpolationFactor := (middle - left) / (right - left) + + // convert colors to rgb + leftHex := []string{leftColor[1:3], leftColor[3:5], leftColor[5:7]} + leftR, _ := strconv.ParseFloat(leftHex[0], 32) + leftG, _ := strconv.ParseFloat(leftHex[1], 32) + leftB, _ := strconv.ParseFloat(leftHex[2], 32) + rightHex := []string{rightColor[1:3], rightColor[3:5], rightColor[5:7]} + rightR, _ := strconv.ParseFloat(rightHex[0], 32) + rightG, _ := strconv.ParseFloat(rightHex[1], 32) + rightB, _ := strconv.ParseFloat(rightHex[2], 32) + + interpolatedR := leftR + float64(interpolationFactor) * (rightR - leftR) + interpolatedG := leftG + float64(interpolationFactor) * (rightG - leftG) + interpolatedB := leftB + float64(interpolationFactor) * (rightB - leftB) + + // hexR := fmt.Sprintf("%x", math.Round(interpolatedR)) + // hexG := fmt.Sprintf("%x", math.Round(interpolatedG)) + // hexB := fmt.Sprintf("%x", math.Round(interpolatedB)) + log.Printf("#%x%x%x", int(math.Round(interpolatedR)), int(math.Round(interpolatedG)), int(math.Round(interpolatedB))) + + return "asd" +} + +func getTemplateData(name string) interface{} { + if name == "sounding_results_contour_lines_geoserver" { + // get class breaks string from database + var classBreaksString string + ctx := context.Background() + err := auth.RunAs( + ctx, bootRole, + func(conn *sql.Conn) error { + return conn.QueryRowContext(ctx, selectClassBreaksSQL).Scan(&classBreaksString) + }) + if err != nil { + log.Printf("error: %v\n", err) + } + + // convert string to array of arrays [[num, color], [num], [num], [num, color] ...] + classBreaksTmp := strings.Split(classBreaksString, ",") + classBreaks := [][]string{} + for _, cb := range classBreaksTmp { + classBreaks = append(classBreaks, strings.Split(cb, ":")) + } + + // interpolate colors + for i, cb := range classBreaks { + if (len(cb) == 1) { + classBreaks[i] = append(cb, interpolateColor(i, classBreaks)) + } + } + + classBreaksForTmpl := []classBreak{} + for i := range classBreaks { + // set low/high + var low, high string + if i == 0 { + high = classBreaks[i][0] + } else { + low = classBreaks[i - 1][0] + high = classBreaks[i][0] + } + classBreaksForTmpl = append(classBreaksForTmpl, classBreak{ + Low: low, + High: high, + Color: classBreaks[i][1], + }) + } + // add last class break (> last value) + classBreaksForTmpl = append(classBreaksForTmpl, classBreak{ + Low: classBreaks[len(classBreaks) - 1][0], + High: "", + Color: classBreaks[len(classBreaks) - 1][1], + }) + log.Printf("%v", classBreaksForTmpl) + return classBreaksForTmpl + } + return nil +} + func updateStyle(entry *models.IntEntry, create bool) error { log.Printf("info: creating style %s\n", entry.Name) @@ -400,6 +515,17 @@ if err != nil { return err } + + // Parse data as template + if entry.Name == "sounding_results_contour_lines_geoserver" { + tmpl, err := template.New(entry.Name).Parse(data) + if err != nil { + return err + } + var buffer bytes.Buffer + err = tmpl.Execute(&buffer, getTemplateData(entry.Name)) + data = buffer.String() + } var ( geoURL = config.GeoServerURL()