Mercurial > gemma
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 } |