Mercurial > gemma
changeset 4296:95786a675d70
WIP: Started with downloading stretches as ESRI shapes.
GET /api/data/stretch/shape/{stretch}
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 30 Aug 2019 18:34:27 +0200 |
parents | 0bb735a412af |
children | a524e7d7e75f |
files | pkg/controllers/routes.go pkg/controllers/stretches.go pkg/wkb/data.go pkg/wkb/wkb.go |
diffstat | 4 files changed, 190 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/controllers/routes.go Fri Aug 30 16:54:12 2019 +0200 +++ b/pkg/controllers/routes.go Fri Aug 30 18:34:27 2019 +0200 @@ -309,6 +309,9 @@ // Handler to serve data to the client. + api.Handle("/data/{kind:stretch|section}/shape/{name}", any( + mw.DBConn(http.HandlerFunc(stretchShapeDownload)))).Methods(http.MethodGet) + api.Handle("/data/{kind:stretch|section}/availability/{name}", any( mw.DBConn(http.HandlerFunc(stretchAvailabilty)))).Methods(http.MethodGet)
--- a/pkg/controllers/stretches.go Fri Aug 30 16:54:12 2019 +0200 +++ b/pkg/controllers/stretches.go Fri Aug 30 18:34:27 2019 +0200 @@ -26,6 +26,7 @@ "time" "gemma.intevation.de/gemma/pkg/middleware" + "gemma.intevation.de/gemma/pkg/wkb" "github.com/gorilla/mux" ) @@ -656,3 +657,115 @@ log.Printf("error: %v\n", err) } } + +const ( + selectStretchSQL = ` +SELECT + id, + isrs_asText(lower(stretch)), + isrs_asText(upper(stretch)), + ST_AsBinary(area::geometry), + objnam, + nobjnam, + date_info, + source_organization +FROM waterway.stretches WHERE + staging_done AND + name = $1` + + selectStretchCountriesSQL = ` +SELECT country_code FROM waterway.stretch_countries +WHERE stretches_id = $1 +ORDER BY country_code` +) + +func stretchShapeDownload(rw http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + stretch := vars["kind"] == "stretch" + name := vars["name"] + + // TODO: Implement me! + if !stretch { + http.Error( + rw, "Not implemented, yet!", + http.StatusBadRequest) + return + } + + conn := middleware.GetDBConn(req) + ctx := req.Context() + + tx, err := conn.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) + if err != nil { + http.Error( + rw, fmt.Sprintf("DB error: %v.", err), + http.StatusInternalServerError) + return + } + defer tx.Rollback() + + var ( + id int64 + lower, upper string + data []byte + objnam string + nobjnam sql.NullString + dateInfo time.Time + source string + ) + + switch err := tx.QueryRowContext(ctx, selectStretchSQL, name).Scan( + &id, + &lower, &upper, + &data, + &objnam, &nobjnam, + &dateInfo, + &source, + ); { + case err == sql.ErrNoRows: + http.NotFound(rw, req) + return + case err != nil: + http.Error( + rw, fmt.Sprintf("DB error: %v.", err), + http.StatusInternalServerError) + return + } + + var countries []string + + if err := func() error { + rows, err := tx.Query(selectStretchCountriesSQL, id) + if err != nil { + return err + } + defer rows.Close() + + for rows.Next() { + var country string + if err := rows.Scan(&country); err != nil { + return err + } + countries = append(countries, country) + } + + return rows.Err() + }(); err != nil { + http.Error( + rw, fmt.Sprintf("DB error: %v.", err), + http.StatusInternalServerError) + return + } + + var geom wkb.MultiPolygonGeom + + if err := geom.FromWKB(data); err != nil { + http.Error( + rw, fmt.Sprintf("Decoding WKB error: %v.", err), + http.StatusInternalServerError) + return + } + + // TODO: Serialize as ESRI shapefile. + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/wkb/data.go Fri Aug 30 18:34:27 2019 +0200 @@ -0,0 +1,73 @@ +// 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 wkb + +import ( + "bytes" + "encoding/binary" + "fmt" + "log" +) + +type ( + PointGeom struct { + X float64 + Y float64 + } + LinearRingGeom []PointGeom + PolygonGeom []LinearRingGeom + MultiPolygonGeom []PolygonGeom +) + +func (mpg *MultiPolygonGeom) FromWKB(data []byte) error { + r := bytes.NewReader(data) + + endian, err := r.ReadByte() + + var order binary.ByteOrder + + switch { + case err != nil: + return err + case endian == NDR: + order = binary.LittleEndian + case endian == XDR: + 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 != MultiPolygon: + return fmt.Errorf("unknown geometry type %x", geomType) + } + + var numPolygons int32 + if err := binary.Read(r, order, &numPolygons); err != nil { + return err + } + log.Printf("info: num polygons: %d\n", numPolygons) + + polygons := make([]PolygonGeom, numPolygons) + + // TODO: Parse the polygons. + + *mpg = polygons + return nil +}
--- a/pkg/wkb/wkb.go Fri Aug 30 16:54:12 2019 +0200 +++ b/pkg/wkb/wkb.go Fri Aug 30 18:34:27 2019 +0200 @@ -25,6 +25,7 @@ LineString uint32 = 2 Polygon uint32 = 3 MultiLineString uint32 = 5 + MultiPolygon uint32 = 6 PointZ uint32 = 1000 + 1 LineStringZ uint32 = 1000 + 2 MultiPointZ uint32 = 1000 + 4