comparison 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
comparison
equal deleted inserted replaced
1784:724758455a4e 1785:614c6c766691
1 // This is Free Software under GNU Affero General Public License v >= 3.0
2 // without warranty, see README.md and license for details.
3 //
4 // SPDX-License-Identifier: AGPL-3.0-or-later
5 // License-Filename: LICENSES/AGPL-3.0.txt
6 //
7 // Copyright (C) 2018 by via donau
8 // – Österreichische Wasserstraßen-Gesellschaft mbH
9 // Software engineering by Intevation GmbH
10 //
11 // Author(s):
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de>
13
14 package imports
15
16 import (
17 "bytes"
18 "encoding/binary"
19 "fmt"
20 "math"
21
22 shp "github.com/jonas-p/go-shp"
23 )
24
25 type (
26 lineSlice [][]float64
27 polygonSlice [][][]float64
28
29 point struct {
30 X float64
31 Y float64
32 }
33 lineString []point
34 polygon []lineString
35 )
36
37 const (
38 wkbNDR byte = 1
39
40 wkbLineString uint32 = 2
41 wkbPolygon uint32 = 3
42 )
43
44 func (l lineSlice) asWKB() []byte {
45
46 size := 1 + 4 + 4 + len(l)*(2*8)
47
48 buf := bytes.NewBuffer(make([]byte, 0, size))
49
50 binary.Write(buf, binary.LittleEndian, wkbNDR)
51 binary.Write(buf, binary.LittleEndian, wkbLineString)
52 binary.Write(buf, binary.LittleEndian, uint32(len(l)))
53
54 for _, c := range l {
55 var lat, lon float64
56 if len(c) > 0 {
57 lat = c[0]
58 }
59 if len(c) > 1 {
60 lon = c[1]
61 }
62 binary.Write(buf, binary.LittleEndian, math.Float64bits(lat))
63 binary.Write(buf, binary.LittleEndian, math.Float64bits(lon))
64 }
65
66 return buf.Bytes()
67 }
68
69 func (p polygonSlice) asWKB() []byte {
70 if p == nil {
71 return nil
72 }
73 // pre-calculate size to avoid reallocations.
74 size := 1 + 4 + 4
75 for _, ring := range p {
76 size += 4 + len(ring)*2*8
77 }
78
79 buf := bytes.NewBuffer(make([]byte, 0, size))
80
81 binary.Write(buf, binary.LittleEndian, wkbNDR)
82 binary.Write(buf, binary.LittleEndian, wkbPolygon)
83 binary.Write(buf, binary.LittleEndian, uint32(len(p)))
84
85 for _, ring := range p {
86 binary.Write(buf, binary.LittleEndian, uint32(len(ring)))
87 for _, v := range ring {
88 var lat, lon float64
89 if len(v) > 0 {
90 lat = v[0]
91 }
92 if len(v) > 1 {
93 lon = v[1]
94 }
95 binary.Write(buf, binary.LittleEndian, math.Float64bits(lat))
96 binary.Write(buf, binary.LittleEndian, math.Float64bits(lon))
97 }
98 }
99
100 return buf.Bytes()
101 }
102
103 func shapeToPolygon(s shp.Shape) (polygon, error) {
104 switch p := s.(type) {
105 case *shp.Polygon:
106 return toPolygon(p.NumParts, p.Parts, p.Points), nil
107 case *shp.PolygonZ:
108 return toPolygon(p.NumParts, p.Parts, p.Points), nil
109 case *shp.PolygonM:
110 return toPolygon(p.NumParts, p.Parts, p.Points), nil
111 }
112 return nil, fmt.Errorf("Unsupported shape type %T", s)
113 }
114
115 func toPolygon(numParts int32, parts []int32, points []shp.Point) polygon {
116 out := make(polygon, numParts)
117 var pos int32
118
119 for i := range out {
120 var howMany int32
121 if i+1 >= len(parts) {
122 howMany = int32(len(points)) - pos
123 } else {
124 howMany = parts[i+1] - parts[i]
125 }
126
127 line := make(lineString, howMany)
128 for j := int32(0); j < howMany; j, pos = j+1, pos+1 {
129 p := &points[pos]
130 line[j] = point{p.X, p.Y}
131 }
132 out[i] = line
133 }
134 return out
135 }
136
137 func (p polygon) asWKB() []byte {
138 if p == nil {
139 return nil
140 }
141 // pre-calculate size to avoid reallocations.
142 size := 1 + 4 + 4
143 for _, ring := range p {
144 size += 4 + len(ring)*2*8
145 }
146
147 buf := bytes.NewBuffer(make([]byte, 0, size))
148
149 binary.Write(buf, binary.LittleEndian, wkbNDR)
150 binary.Write(buf, binary.LittleEndian, wkbPolygon)
151 binary.Write(buf, binary.LittleEndian, uint32(len(p)))
152
153 for _, ring := range p {
154 binary.Write(buf, binary.LittleEndian, uint32(len(ring)))
155 for _, v := range ring {
156 binary.Write(buf, binary.LittleEndian, math.Float64bits(v.X))
157 binary.Write(buf, binary.LittleEndian, math.Float64bits(v.Y))
158 }
159 }
160
161 return buf.Bytes()
162 }