Mercurial > gemma
comparison 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 |
comparison
equal
deleted
inserted
replaced
959:6ab012d0f0c2 | 960:e23ae2c83427 |
---|---|
9 "errors" | 9 "errors" |
10 "fmt" | 10 "fmt" |
11 "io" | 11 "io" |
12 "log" | 12 "log" |
13 "os" | 13 "os" |
14 "path/filepath" | 14 "path" |
15 "strconv" | 15 "strconv" |
16 "strings" | 16 "strings" |
17 "time" | 17 "time" |
18 | 18 |
19 shp "github.com/jonas-p/go-shp" | |
20 | |
19 "gemma.intevation.de/gemma/pkg/octree" | 21 "gemma.intevation.de/gemma/pkg/octree" |
20 ) | 22 ) |
21 | 23 |
22 type SoundingResult struct { | 24 type SoundingResult struct { |
23 who string | 25 who string |
24 dir string | 26 zip string |
25 } | 27 } |
26 | 28 |
27 const SoundingResultDateFormat = "2006-01-02" | 29 const SoundingResultDateFormat = "2006-01-02" |
28 | 30 |
29 type SoundingResultDate struct{ time.Time } | 31 type SoundingResultDate struct{ time.Time } |
50 func (sr *SoundingResult) Who() string { | 52 func (sr *SoundingResult) Who() string { |
51 return sr.who | 53 return sr.who |
52 } | 54 } |
53 | 55 |
54 func (sr *SoundingResult) CleanUp() error { | 56 func (sr *SoundingResult) CleanUp() error { |
55 return os.RemoveAll(sr.dir) | 57 return os.RemoveAll(sr.zip) |
56 } | 58 } |
57 | 59 |
58 func find(needle string, haystack []*zip.File) *zip.File { | 60 func find(needle string, haystack []*zip.File) *zip.File { |
59 needle = strings.ToLower(needle) | 61 needle = strings.ToLower(needle) |
60 for _, straw := range haystack { | 62 for _, straw := range haystack { |
155 } | 157 } |
156 defer r.Close() | 158 defer r.Close() |
157 return loadXYZReader(r) | 159 return loadXYZReader(r) |
158 } | 160 } |
159 | 161 |
162 type ( | |
163 Point struct { | |
164 X float64 | |
165 Y float64 | |
166 } | |
167 LineString []Point | |
168 Polygon []LineString | |
169 ) | |
170 | |
171 func toPolygon(numParts int32, parts []int32, points []shp.Point) Polygon { | |
172 out := make(Polygon, numParts) | |
173 pos := 0 | |
174 for i := range out { | |
175 ps := parts[i] | |
176 line := make(LineString, ps) | |
177 for j := int32(0); j < ps; j, pos = j+1, pos+1 { | |
178 p := &points[pos] | |
179 line[j] = Point{p.X, p.Y} | |
180 } | |
181 out[i] = line | |
182 } | |
183 return out | |
184 } | |
185 | |
186 func loadBoundary(z *zip.ReadCloser) (Polygon, error) { | |
187 shpF := find(".shp", z.File) | |
188 if shpF == nil { | |
189 return nil, nil | |
190 } | |
191 prefix := strings.TrimSuffix(shpF.Name, path.Ext(shpF.Name)) | |
192 dbfF := find(prefix+".dbf", z.File) | |
193 if dbfF == nil { | |
194 return nil, fmt.Errorf("No DBF file found for %s", shpF.Name) | |
195 } | |
196 | |
197 shpR, err := shpF.Open() | |
198 if err != nil { | |
199 return nil, err | |
200 } | |
201 | |
202 dbfR, err := dbfF.Open() | |
203 if err != nil { | |
204 shpR.Close() | |
205 return nil, err | |
206 } | |
207 sr := shp.SequentialReaderFromExt(shpR, dbfR) | |
208 defer sr.Close() | |
209 | |
210 if !sr.Next() { | |
211 return nil, sr.Err() | |
212 } | |
213 | |
214 _, s := sr.Shape() | |
215 if s == nil { | |
216 return nil, sr.Err() | |
217 } | |
218 | |
219 switch p := s.(type) { | |
220 case *shp.Polygon: | |
221 return toPolygon(p.NumParts, p.Parts, p.Points), nil | |
222 case *shp.PolygonZ: | |
223 return toPolygon(p.NumParts, p.Parts, p.Points), nil | |
224 case *shp.PolygonM: | |
225 return toPolygon(p.NumParts, p.Parts, p.Points), nil | |
226 } | |
227 return nil, fmt.Errorf("Unsupported shape type %T", s) | |
228 } | |
229 | |
160 func (sr *SoundingResult) Do(conn *sql.Conn) error { | 230 func (sr *SoundingResult) Do(conn *sql.Conn) error { |
161 | 231 |
162 z, err := zip.OpenReader(filepath.Join(sr.dir, "upload.zip")) | 232 z, err := zip.OpenReader(sr.zip) |
163 if err != nil { | 233 if err != nil { |
164 return err | 234 return err |
165 } | 235 } |
166 defer z.Close() | 236 defer z.Close() |
167 | 237 |
191 | 261 |
192 if len(xyz) == 0 { | 262 if len(xyz) == 0 { |
193 return errors.New("XYZ does not contain any vertices.") | 263 return errors.New("XYZ does not contain any vertices.") |
194 } | 264 } |
195 | 265 |
196 // TODO: Implement more. | 266 // Is there a boundary shapefile in the ZIP archive? |
267 polygon, err := loadBoundary(z) | |
268 if err != nil { | |
269 return err | |
270 } | |
271 | |
272 _ = polygon | |
273 | |
274 // TODO: Send to database. | |
197 | 275 |
198 return nil | 276 return nil |
199 } | 277 } |