diff pkg/imports/sr.go @ 960:e23ae2c83427

Load boundary polygon of sounding result from ZIP file.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 17 Oct 2018 12:23:39 +0200
parents 6ab012d0f0c2
children a4c92e0ef2e1
line wrap: on
line diff
--- a/pkg/imports/sr.go	Tue Oct 16 18:20:50 2018 +0200
+++ b/pkg/imports/sr.go	Wed Oct 17 12:23:39 2018 +0200
@@ -11,17 +11,19 @@
 	"io"
 	"log"
 	"os"
-	"path/filepath"
+	"path"
 	"strconv"
 	"strings"
 	"time"
 
+	shp "github.com/jonas-p/go-shp"
+
 	"gemma.intevation.de/gemma/pkg/octree"
 )
 
 type SoundingResult struct {
 	who string
-	dir string
+	zip string
 }
 
 const SoundingResultDateFormat = "2006-01-02"
@@ -52,7 +54,7 @@
 }
 
 func (sr *SoundingResult) CleanUp() error {
-	return os.RemoveAll(sr.dir)
+	return os.RemoveAll(sr.zip)
 }
 
 func find(needle string, haystack []*zip.File) *zip.File {
@@ -157,9 +159,77 @@
 	return loadXYZReader(r)
 }
 
+type (
+	Point struct {
+		X float64
+		Y float64
+	}
+	LineString []Point
+	Polygon    []LineString
+)
+
+func toPolygon(numParts int32, parts []int32, points []shp.Point) Polygon {
+	out := make(Polygon, numParts)
+	pos := 0
+	for i := range out {
+		ps := parts[i]
+		line := make(LineString, ps)
+		for j := int32(0); j < ps; j, pos = j+1, pos+1 {
+			p := &points[pos]
+			line[j] = Point{p.X, p.Y}
+		}
+		out[i] = line
+	}
+	return out
+}
+
+func loadBoundary(z *zip.ReadCloser) (Polygon, error) {
+	shpF := find(".shp", z.File)
+	if shpF == nil {
+		return nil, nil
+	}
+	prefix := strings.TrimSuffix(shpF.Name, path.Ext(shpF.Name))
+	dbfF := find(prefix+".dbf", z.File)
+	if dbfF == nil {
+		return nil, fmt.Errorf("No DBF file found for %s", shpF.Name)
+	}
+
+	shpR, err := shpF.Open()
+	if err != nil {
+		return nil, err
+	}
+
+	dbfR, err := dbfF.Open()
+	if err != nil {
+		shpR.Close()
+		return nil, err
+	}
+	sr := shp.SequentialReaderFromExt(shpR, dbfR)
+	defer sr.Close()
+
+	if !sr.Next() {
+		return nil, sr.Err()
+	}
+
+	_, s := sr.Shape()
+	if s == nil {
+		return nil, sr.Err()
+	}
+
+	switch p := s.(type) {
+	case *shp.Polygon:
+		return toPolygon(p.NumParts, p.Parts, p.Points), nil
+	case *shp.PolygonZ:
+		return toPolygon(p.NumParts, p.Parts, p.Points), nil
+	case *shp.PolygonM:
+		return toPolygon(p.NumParts, p.Parts, p.Points), nil
+	}
+	return nil, fmt.Errorf("Unsupported shape type %T", s)
+}
+
 func (sr *SoundingResult) Do(conn *sql.Conn) error {
 
-	z, err := zip.OpenReader(filepath.Join(sr.dir, "upload.zip"))
+	z, err := zip.OpenReader(sr.zip)
 	if err != nil {
 		return err
 	}
@@ -193,7 +263,15 @@
 		return errors.New("XYZ does not contain any vertices.")
 	}
 
-	// TODO: Implement more.
+	// Is there a boundary shapefile in the ZIP archive?
+	polygon, err := loadBoundary(z)
+	if err != nil {
+		return err
+	}
+
+	_ = polygon
+
+	// TODO: Send to database.
 
 	return nil
 }