Mercurial > gemma
view pkg/controllers/cross.go @ 928:0a0013fbda4a geo-style
octree2contour: Merge multi linestrings in user land before sending them to database.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 08 Oct 2018 13:09:02 +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 }