Mercurial > gemma
view pkg/mesh/classbreaks.go @ 5157:673f2a00c767
add missing Author in Timeslider
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Thu, 02 Apr 2020 13:17:13 +0200 |
parents | 4847ac70103a |
children | 34bc6041e61e |
line wrap: on
line source
// 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) 2019 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> package mesh import ( "context" "database/sql" "errors" "math" "sort" "strconv" "strings" ) const ( selectClassBreaksSQL = ` SELECT config_val FROM sys_admin.system_config WHERE config_key = $1` ) func SampleDiffHeights(min, max, step float64) []float64 { var heights []float64 switch { case min >= 0: // All values positive. for v := 0.0; v <= max; v += step { if v >= min { heights = append(heights, v) } } case max <= 0: // All values negative. for v := 0.0; v >= min; v -= step { if v <= max { heights = append(heights, v) } } default: // Positive and negative. for v := step; v <= max; v += step { heights = append(heights, v) } for i, j := 0, len(heights)-1; i < j; i, j = i+1, j-1 { heights[i], heights[j] = heights[j], heights[i] } for v := 0.0; v >= min; v -= step { heights = append(heights, v) } } return heights } func ParseClassBreaks(config string) ([]float64, error) { parts := strings.Split(config, ",") classes := make([]float64, 0, len(parts)) for _, part := range parts { if idx := strings.IndexRune(part, ':'); idx >= 0 { part = part[:idx] } if part = strings.TrimSpace(part); part == "" { continue } v, err := strconv.ParseFloat(part, 64) if err != nil { return nil, err } classes = append(classes, v) } sort.Float64s(classes) return classes, nil } func LoadClassBreaks(ctx context.Context, tx *sql.Tx, key string) ([]float64, error) { var config sql.NullString err := tx.QueryRowContext(ctx, selectClassBreaksSQL, key).Scan(&config) switch { case err == sql.ErrNoRows: return nil, nil case err != nil: return nil, err case !config.Valid: return nil, errors.New("invalid config string") } return ParseClassBreaks(config.String) } func round(v float64) float64 { return math.Round(v*10000) / 10000 } func ExtrapolateClassBreaks(cbs []float64, min, max float64) []float64 { if min > max { min, max = max, min } n := make([]float64, len(cbs)) copy(n, cbs) sort.Float64s(n) for len(n) > 0 && n[0] < min { n = n[1:] } if len(n) == 0 { return n } for len(n) > 0 && n[len(n)-1] > max { n = n[:len(n)-1] } if len(n) == 0 { return n } for min < n[0] { diff := n[1] - n[0] if diff == 0 { break } m := make([]float64, len(n)+1) m[0] = round(n[0] - diff) copy(m[1:], n) n = m } for max > n[len(n)-1] { diff := n[len(n)-1] - n[len(n)-2] if diff == 0 { break } n = append(n, round(n[len(n)-1]+diff)) } return n }