diff pkg/imports/wkb.go @ 1785:614c6c766691

Waterway area import: Implemented.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sat, 12 Jan 2019 19:53:31 +0100
parents
children 09349ca27dd7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/imports/wkb.go	Sat Jan 12 19:53:31 2019 +0100
@@ -0,0 +1,162 @@
+// 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) 2018 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+package imports
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"math"
+
+	shp "github.com/jonas-p/go-shp"
+)
+
+type (
+	lineSlice    [][]float64
+	polygonSlice [][][]float64
+
+	point struct {
+		X float64
+		Y float64
+	}
+	lineString []point
+	polygon    []lineString
+)
+
+const (
+	wkbNDR byte = 1
+
+	wkbLineString uint32 = 2
+	wkbPolygon    uint32 = 3
+)
+
+func (l lineSlice) asWKB() []byte {
+
+	size := 1 + 4 + 4 + len(l)*(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(l)))
+
+	for _, c := range l {
+		var lat, lon float64
+		if len(c) > 0 {
+			lat = c[0]
+		}
+		if len(c) > 1 {
+			lon = c[1]
+		}
+		binary.Write(buf, binary.LittleEndian, math.Float64bits(lat))
+		binary.Write(buf, binary.LittleEndian, math.Float64bits(lon))
+	}
+
+	return buf.Bytes()
+}
+
+func (p polygonSlice) asWKB() []byte {
+	if p == nil {
+		return nil
+	}
+	// pre-calculate size to avoid reallocations.
+	size := 1 + 4 + 4
+	for _, ring := range p {
+		size += 4 + len(ring)*2*8
+	}
+
+	buf := bytes.NewBuffer(make([]byte, 0, size))
+
+	binary.Write(buf, binary.LittleEndian, wkbNDR)
+	binary.Write(buf, binary.LittleEndian, wkbPolygon)
+	binary.Write(buf, binary.LittleEndian, uint32(len(p)))
+
+	for _, ring := range p {
+		binary.Write(buf, binary.LittleEndian, uint32(len(ring)))
+		for _, v := range ring {
+			var lat, lon float64
+			if len(v) > 0 {
+				lat = v[0]
+			}
+			if len(v) > 1 {
+				lon = v[1]
+			}
+			binary.Write(buf, binary.LittleEndian, math.Float64bits(lat))
+			binary.Write(buf, binary.LittleEndian, math.Float64bits(lon))
+		}
+	}
+
+	return buf.Bytes()
+}
+
+func shapeToPolygon(s shp.Shape) (polygon, error) {
+	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 toPolygon(numParts int32, parts []int32, points []shp.Point) polygon {
+	out := make(polygon, numParts)
+	var pos int32
+
+	for i := range out {
+		var howMany int32
+		if i+1 >= len(parts) {
+			howMany = int32(len(points)) - pos
+		} else {
+			howMany = parts[i+1] - parts[i]
+		}
+
+		line := make(lineString, howMany)
+		for j := int32(0); j < howMany; j, pos = j+1, pos+1 {
+			p := &points[pos]
+			line[j] = point{p.X, p.Y}
+		}
+		out[i] = line
+	}
+	return out
+}
+
+func (p polygon) asWKB() []byte {
+	if p == nil {
+		return nil
+	}
+	// pre-calculate size to avoid reallocations.
+	size := 1 + 4 + 4
+	for _, ring := range p {
+		size += 4 + len(ring)*2*8
+	}
+
+	buf := bytes.NewBuffer(make([]byte, 0, size))
+
+	binary.Write(buf, binary.LittleEndian, wkbNDR)
+	binary.Write(buf, binary.LittleEndian, wkbPolygon)
+	binary.Write(buf, binary.LittleEndian, uint32(len(p)))
+
+	for _, ring := range p {
+		binary.Write(buf, binary.LittleEndian, uint32(len(ring)))
+		for _, v := range ring {
+			binary.Write(buf, binary.LittleEndian, math.Float64bits(v.X))
+			binary.Write(buf, binary.LittleEndian, math.Float64bits(v.Y))
+		}
+	}
+
+	return buf.Bytes()
+}