Mercurial > gemma
view pkg/controllers/cross.go @ 935:430d52c2f6ef
client: move layer isolines to be drawn at the top
* Move layer isolones to be drawn last (and thus being "on top")
so that the bottleneck (position) layer will not interfere that much
with the colours. It also allows to set a white background with high
opacity on the bottleneck polygon in order to get highly visible
isolines.
author | Bernhard Reiter <bernhard@intevation.de> |
---|---|
date | Mon, 08 Oct 2018 17:20:42 +0200 |
parents | 03e966b71a88 |
children | a244b18cb916 |
line wrap: on
line source
package controllers import ( "context" "database/sql" "fmt" "log" "net/http" "time" "gemma.intevation.de/gemma/pkg/models" "gemma.intevation.de/gemma/pkg/octree" ) const WGS84 = 4326 func reproject( rp *models.Reprojector, src models.GeoJSONLineCoordinates, ctx context.Context, ) (models.GeoJSONLineCoordinates, error) { dst := make(models.GeoJSONLineCoordinates, len(src)) for i, s := range src { var err error if dst[i].Lat, dst[i].Lon, err = rp.Reproject( s.Lat, s.Lon, ctx, ); err != nil { return nil, err } } return dst, nil } func projectBack( rp *models.Reprojector, lines octree.MultiLineStringZ, ctx context.Context, ) (models.GeoJSONMultiLineCoordinatesZ, error) { out := make(models.GeoJSONMultiLineCoordinatesZ, len(lines)) for i, segment := range lines { coords := make(models.GeoJSONLineCoordinatesZ, len(segment)) out[i] = coords for j, v := range segment { lat, lon, err := rp.Reproject(v.X, v.Y, ctx) if err != nil { return nil, err } coords[j] = models.GeoJSONCoordinateZ{Lat: lat, Lon: lon, Z: v.Z} } } return out, nil } const clipSQL = ` SELECT ST_AsBinary(ST_Transform(ST_Multi(ST_Intersection( ST_Transform(area::geometry, $1::integer), ST_GeomFromWKB($2, $1::integer))), 4326)) FROM waterway.sounding_results WHERE bottleneck_id = $3 AND date_info = $4::date` func clipAgainstArea( line octree.MultiLineStringZ, epsg uint32, bottleneck string, dateInfo time.Time, conn *sql.Conn, ctx context.Context, ) (models.GeoJSONMultiLineCoordinatesZ, error) { var mls models.GeoJSONMultiLineCoordinatesZ err := conn.QueryRowContext( ctx, clipSQL, epsg, line.AsWKB(), bottleneck, dateInfo, ).Scan(&mls) return mls, err } func crossSection( input interface{}, req *http.Request, conn *sql.Conn, ) (jr JSONResult, err error) { csi := input.(*models.CrossSectionInput) start := time.Now() tree, err := octree.Cache.Get( csi.Properties.Bottleneck, csi.Properties.Date.Time, conn, req.Context()) log.Printf("loading octree took: %s\n", time.Since(start)) if err != nil { return } if tree == nil { err = JSONError{ Code: http.StatusNotFound, Message: fmt.Sprintf("Cannot find survey for %s/%s.", csi.Properties.Bottleneck, csi.Properties.Date.Time), } return } // The coordinate system of the octree is an UTM projection. // The input coordinates are in WGS84. // So we need to reproject them. start = time.Now() var rp *models.Reprojector if rp, err = models.NewReprojector( conn, req.Context(), WGS84, tree.EPSG, ); err != nil { return } defer rp.Close() coords, err := reproject(rp, csi.Geometry.Coordinates, req.Context()) log.Printf("transforming input coords took: %s\n", time.Since(start)) if err != nil { return } start = time.Now() var segments octree.MultiLineStringZ for i := 0; i < len(coords)-1; i++ { c1 := &coords[i] c2 := &coords[i+1] verticalLine := octree.NewVerticalLine(c1.Lat, c1.Lon, c2.Lat, c2.Lon) var line octree.MultiLineStringZ tree.Vertical(c1.Lat, c1.Lon, c2.Lat, c2.Lon, func(t *octree.Triangle) { if ls := verticalLine.Intersection(t); len(ls) > 0 { line = append(line, ls) } }) if len(line) > 0 { log.Printf("line length: %d\n", len(line)) // They are all on the segment (c1.Lat, c1.Lon) - (c2.Lat, c2.Lon). // Sort them by project them on this line. joined := line.JoinOnLine(c1.Lat, c1.Lon, c2.Lat, c2.Lon) log.Printf("joined length: %d\n", len(joined)) segments = append(segments, joined...) } } log.Printf("octree traversal took: %s\n", time.Since(start)) start = time.Now() var joined models.GeoJSONMultiLineCoordinatesZ joined, err = clipAgainstArea( segments, tree.EPSG, csi.Properties.Bottleneck, csi.Properties.Date.Time, conn, req.Context(), ) log.Printf("clipping and projecting back took: %s\n", time.Since(start)) if err != nil { return } jr = JSONResult{ Result: &models.CrossSectionOutput{ Type: "Feature", Geometry: models.CrossSectionOutputGeometry{ Type: "MultiLineString", Coordinates: joined, }, Properties: map[string]interface{}{}, }, } return }