# HG changeset patch # User Sascha L. Teichmann # Date 1538058615 -7200 # Node ID e10a8a682297b4c2e3ef8286d42579c244996c0f # Parent 34b2cfcab24cec7740733c3906222fe2c02fbf0d Cross sections: Clip result against area of the sounding result. This also includes the re-projections back to WGS84 and encoding the final result as GeoJSON. diff -r 34b2cfcab24c -r e10a8a682297 pkg/controllers/cross.go --- a/pkg/controllers/cross.go Thu Sep 27 16:13:59 2018 +0200 +++ b/pkg/controllers/cross.go Thu Sep 27 16:30:15 2018 +0200 @@ -54,6 +54,32 @@ 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, @@ -124,15 +150,16 @@ } log.Printf("octree traversal took: %s\n", time.Since(start)) - // The result have to be WGS84. So project the result back. start = time.Now() - rp.FromEPSG, rp.ToEPSG = tree.EPSG, WGS84 + var joined models.GeoJSONMultiLineCoordinatesZ + joined, err = clipAgainstArea( + segments, tree.EPSG, + csi.Properties.Bottleneck, csi.Properties.Date.Time, + conn, req.Context(), + ) - var joined models.GeoJSONMultiLineCoordinatesZ - joined, err = projectBack(rp, segments, req.Context()) - - log.Printf("projecting back took: %s\n", time.Since(start)) + log.Printf("clipping and projecting back took: %s\n", time.Since(start)) if err != nil { return } diff -r 34b2cfcab24c -r e10a8a682297 pkg/models/cross.go --- a/pkg/models/cross.go Thu Sep 27 16:13:59 2018 +0200 +++ b/pkg/models/cross.go Thu Sep 27 16:30:15 2018 +0200 @@ -133,10 +133,11 @@ } const ( - wkbXDR byte = 0 - wkbNDR byte = 1 - wkbLineString uint32 = 2 - wkbLineStringZ uint32 = 1000 + 2 + wkbXDR byte = 0 + wkbNDR byte = 1 + wkbLineString uint32 = 2 + wkbLineStringZ uint32 = 1000 + 2 + wkbMultiLineStringZ uint32 = 1000 + 5 ) func (lc GeoJSONLineCoordinates) AsWKB() []byte { @@ -256,3 +257,98 @@ x := dLng * math.Cos(deg2rad((cz.Lat+other.Lat)/2.0)) return math.Sqrt(dLat*dLat+x*x) * EarthRadius } + +func (mls *GeoJSONMultiLineCoordinatesZ) FromWKB(data []byte) error { + r := bytes.NewReader(data) + + var order binary.ByteOrder + + endian, err := r.ReadByte() + + switch { + case err != nil: + return err + case endian == wkbNDR: + order = binary.LittleEndian + case endian == wkbXDR: + order = binary.BigEndian + default: + return fmt.Errorf("unknown byte order %x", endian) + } + + var geomType uint32 + err = binary.Read(r, order, &geomType) + + switch { + case err != nil: + return err + case geomType != wkbMultiLineStringZ: + return fmt.Errorf("unknown geometry type %d", geomType) + } + + var numLines uint32 + if err = binary.Read(r, order, &numLines); err != nil { + return err + } + + lines := make(GeoJSONMultiLineCoordinatesZ, numLines) + + for i := range lines { + endian, err = r.ReadByte() + + switch { + case err != nil: + return err + case endian == wkbNDR: + order = binary.LittleEndian + case endian == wkbXDR: + order = binary.BigEndian + default: + return fmt.Errorf("unknown byte order %x", endian) + } + + err = binary.Read(r, order, &geomType) + switch { + case err != nil: + return err + case geomType != wkbLineStringZ: + return fmt.Errorf("unknown geometry type %d", geomType) + } + + var numPoints uint32 + if err = binary.Read(r, order, &numPoints); err != nil { + return err + } + + points := make(GeoJSONLineCoordinatesZ, numPoints) + for j := range points { + var lat, lon, z uint64 + if err = binary.Read(r, order, &lat); err != nil { + return err + } + if err = binary.Read(r, order, &lon); err != nil { + return err + } + if err = binary.Read(r, order, &z); err != nil { + return err + } + c := &points[j] + c.Lat = math.Float64frombits(lat) + c.Lon = math.Float64frombits(lon) + c.Z = math.Float64frombits(z) + } + lines[i] = points + } + + *mls = lines + + return nil +} + +func (mls *GeoJSONMultiLineCoordinatesZ) Scan(src interface{}) error { + data, ok := src.([]byte) + if !ok { + return errNoByteSlice + } + return mls.FromWKB(data) +}