Mercurial > gemma
changeset 643:756f3fc62da6
Cross sections: Using the database in the web service.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Thu, 13 Sep 2018 12:09:23 +0200 |
parents | e95df6657023 |
children | c1a31858ad54 |
files | pkg/controllers/cross.go pkg/models/common.go pkg/models/cross.go pkg/models/user.go |
diffstat | 4 files changed, 173 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/controllers/cross.go Thu Sep 13 10:31:22 2018 +0200 +++ b/pkg/controllers/cross.go Thu Sep 13 12:09:23 2018 +0200 @@ -7,16 +7,62 @@ "gemma.intevation.de/gemma/pkg/models" ) +// TODO: This is hardcoded on SLT's model of a concrete sounding result. +const crossSQL = ` +SELECT ST_AsBinary((ST_Dump(ST_Multi(ST_3DIntersection( + ST_Translate( + ST_Extrude( + ST_FromWKB($1, 4326), + 0, 0, 100), + 0, 0, -150), + geom)))).geom) +FROM b442017 +WHERE ST_Intersects(geom, ST_FromWKB($1, 4326)) +` + func crossSection( input interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { - // TODO: Implement me! csi := input.(*models.CrossSectionInput) - _ = csi + // TODO: Use these properties in query + _ = csi.Properties.Bottleneck + _ = csi.Properties.Date + + var rows *sql.Rows + + rows, err = db.QueryContext(req.Context(), csi.Coordinates.AsWKB()) + if err != nil { + return + } + defer rows.Close() + + var segments []models.GeoJSONLineCoordinatesZ + + for rows.Next() { + var segment models.GeoJSONLineCoordinatesZ + if err = rows.Scan(&segment); err != nil { + return + } + segments = append(segments, segment) + } + + if err = rows.Err(); err != nil { + return + } + + // TODO: Join the segments. + + jr = JSONResult{ + Result: &models.CrossSectionOutput{ + Type: "Feature", + Geometry: "MultLineString", + Coordinates: segments, + }, + } return }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/models/common.go Thu Sep 13 12:09:23 2018 +0200 @@ -0,0 +1,5 @@ +package models + +import "errors" + +var errNoString = errors.New("Not a string")
--- a/pkg/models/cross.go Thu Sep 13 10:31:22 2018 +0200 +++ b/pkg/models/cross.go Thu Sep 13 12:09:23 2018 +0200 @@ -1,8 +1,13 @@ package models import ( + "bytes" + "encoding/binary" "encoding/json" "errors" + "fmt" + "math" + "strings" "time" ) @@ -21,12 +26,19 @@ Lat float64 } + GeoJSONCoordinateZ struct { + Lon float64 + Lat float64 + Z float64 + } + CrossSectionInputProperties struct { Bottleneck string `json:"bottleneck"` Date GeoJSONDate `json:"date"` } - GeoJSONLineCoordinates []GeoJSONCoordinate + GeoJSONLineCoordinates []GeoJSONCoordinate + GeoJSONLineCoordinatesZ []GeoJSONCoordinateZ CrossSectionInput struct { Type GeoJSONFeature `json:"type"` @@ -34,6 +46,12 @@ Coordinates GeoJSONLineCoordinates `json:"coordinates"` Properties CrossSectionInputProperties `json:"properties"` } + + CrossSectionOutput struct { + Type string `json:"type"` + Geometry string `json:"geometry"` + Coordinates []GeoJSONLineCoordinatesZ `json:"coordinates"` + } ) var ( @@ -103,3 +121,104 @@ *t = GeoJSONLineStringType(s) return nil } + +const ( + wkbXDR byte = 0 + wkbNDR byte = 1 + wkbPoint uint32 = 1 + wkbPointZ uint32 = 1000 + 1 + wkbLineString uint32 = 2 + wkbLineStringZ uint32 = 1000 + 2 +) + +func (lc GeoJSONLineCoordinates) AsWKB() string { + + size := 1 + 4 + 4 + len(lc)*(1+4+2*8) + + buf := bytes.NewBuffer(make([]byte, 0, size)) + + binary.Write(buf, binary.LittleEndian, wkbNDR) + binary.Write(buf, binary.LittleEndian, wkbLineString) + binary.Write(buf, binary.LittleEndian, uint32(len(lc))) + + for i := range lc { + c := &lc[i] + binary.Write(buf, binary.LittleEndian, wkbNDR) + binary.Write(buf, binary.LittleEndian, wkbPoint) + binary.Write(buf, binary.LittleEndian, math.Float64bits(c.Lon)) + binary.Write(buf, binary.LittleEndian, math.Float64bits(c.Lat)) + } + + return buf.String() +} + +func (cz GeoJSONCoordinateZ) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + fmt.Fprintf(&buf, "[%.8f %.8f %.8f]", cz.Lon, cz.Lat, cz.Z) + return buf.Bytes(), nil +} + +func (lcz *GeoJSONLineCoordinatesZ) Scan(src interface{}) error { + data, ok := src.(string) + if !ok { + return errNoString + } + return lcz.FromWKB(data) +} + +func (lcz *GeoJSONLineCoordinatesZ) FromWKB(data string) error { + + r := strings.NewReader(data) + + endian, err := r.ReadByte() + + var order binary.ByteOrder + + switch { + case err != nil: + return err + case endian == wkbNDR: + order = binary.BigEndian + case endian == wkbXDR: + order = binary.LittleEndian + 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 != wkbLineStringZ: + return fmt.Errorf("unknown geometry type %d", geomType) + } + + var num uint32 + if err = binary.Read(r, order, &num); err != nil { + return err + } + + coords := make(GeoJSONLineCoordinatesZ, num) + + for i := range coords { + err = binary.Read(r, order, &geomType) + switch { + case err != nil: + return err + case geomType != wkbPointZ: + return fmt.Errorf("unknown geometry type %d", geomType) + } + c := &coords[i] + for _, addr := range []*float64{&c.Lat, &c.Lon, &c.Z} { + if err = binary.Read(r, order, addr); err != nil { + return err + } + } + } + + *lcz = coords + + return nil +}
--- a/pkg/models/user.go Thu Sep 13 10:31:22 2018 +0200 +++ b/pkg/models/user.go Thu Sep 13 12:09:23 2018 +0200 @@ -49,7 +49,6 @@ `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])`) errNoEmailAddress = errors.New("Not a valid email address") - errNoString = errors.New("Not a string") ) func (e *Email) UnmarshalJSON(data []byte) error {