• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-spatial / tegola / 607999c17

26 Mar 2025 11:55PM UTC coverage: 40.462%. Remained the same
607999c17

Pull #1041

github

web-flow
build(deps): bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.3

Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.7.0 to 9.7.3.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.7.0...v9.7.3)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #1041: build(deps): bump github.com/redis/go-redis/v9 from 9.7.0 to 9.7.3

6656 of 16450 relevant lines covered (40.46%)

219.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/basic/geometry_math.go
1
package basic
2

3
import (
4
        "fmt"
5
        "strings"
6

7
        "errors"
8

9
        "github.com/go-spatial/geom"
10
        "github.com/go-spatial/tegola"
11
        "github.com/go-spatial/tegola/maths/webmercator"
12
)
13

14
// ApplyToPoints applys the given function to each point in the geometry and any sub geometries, return a new transformed geometry.
15
func ApplyToPoints(geometry geom.Geometry, f func(coords ...float64) ([]float64, error)) (geom.Geometry, error) {
×
16
        switch geo := geometry.(type) {
×
17
        default:
×
18
                return nil, fmt.Errorf("unknown Geometry: %T", geometry)
×
19

20
        case geom.Point:
×
21
                c, err := f(geo.X(), geo.Y())
×
22
                if err != nil {
×
23
                        return nil, err
×
24
                }
×
25
                if len(c) < 2 {
×
26
                        return nil, fmt.Errorf("function did not return minimum number of coordinates got %v expected 2", len(c))
×
27
                }
×
28
                return geom.Point{c[0], c[1]}, nil
×
29

30
        case geom.MultiPoint:
×
31
                pts := make(geom.MultiPoint, len(geo))
×
32

×
33
                for i, pt := range geo {
×
34
                        c, err := f(pt[:]...)
×
35
                        if err != nil {
×
36
                                return nil, err
×
37
                        }
×
38
                        if len(c) < 2 {
×
39
                                return nil, fmt.Errorf("function did not return minimum number of coordinates got %v expected 2", len(c))
×
40
                        }
×
41
                        pts[i][0], pts[i][1] = c[0], c[1]
×
42
                }
43
                return pts, nil
×
44

45
        case geom.LineString:
×
46
                line := make(geom.LineString, len(geo))
×
47
                for i, pt := range geo {
×
48
                        c, err := f(pt[:]...)
×
49
                        if err != nil {
×
50
                                return nil, err
×
51
                        }
×
52
                        if len(c) < 2 {
×
53
                                return nil, fmt.Errorf("function did not return minimum number of coordinates got %v expected 2", len(c))
×
54
                        }
×
55
                        line[i][0], line[i][1] = c[0], c[1]
×
56
                }
57
                return line, nil
×
58

59
        case geom.MultiLineString:
×
60
                lines := make(geom.MultiLineString, len(geo))
×
61

×
62
                for i, line := range geo {
×
63
                        // getting a geometry interface back
×
64
                        linei, err := ApplyToPoints(geom.LineString(line), f)
×
65
                        if err != nil {
×
66
                                return nil, fmt.Errorf("got error converting line(%v) of multiline: %v", i, err)
×
67
                        }
×
68

69
                        // get the value
70
                        linev, ok := linei.(geom.LineString)
×
71
                        if !ok {
×
72
                                panic("we did not get the conversion we were expecting")
×
73
                        }
74

75
                        lines[i] = linev
×
76
                }
77
                return lines, nil
×
78

79
        case geom.Polygon:
×
80
                poly := make(geom.Polygon, len(geo))
×
81

×
82
                for i, line := range geo {
×
83
                        // getting a geometry inteface back
×
84
                        linei, err := ApplyToPoints(geom.LineString(line), f)
×
85
                        if err != nil {
×
86
                                return nil, fmt.Errorf("got error converting line(%v) of polygon: %v", i, err)
×
87
                        }
×
88

89
                        // get the value
90
                        linev, ok := linei.(geom.LineString)
×
91
                        if !ok {
×
92
                                panic("we did not get the conversion we were expecting")
×
93
                        }
94

95
                        poly[i] = linev
×
96
                }
97
                return poly, nil
×
98

99
        case geom.MultiPolygon:
×
100
                mpoly := make(geom.MultiPolygon, len(geo))
×
101

×
102
                for i, poly := range geo {
×
103
                        // getting a geometry inteface back
×
104
                        polyi, err := ApplyToPoints(geom.Polygon(poly), f)
×
105
                        if err != nil {
×
106
                                return nil, fmt.Errorf("got error converting poly(%v) of multipolygon: %v", i, err)
×
107
                        }
×
108

109
                        // get the value
110
                        polyv, ok := polyi.(geom.Polygon)
×
111
                        if !ok {
×
112
                                panic("we did not get the conversion we were expecting")
×
113
                        }
114

115
                        mpoly[i] = polyv
×
116
                }
117
                return mpoly, nil
×
118
        }
119
}
120

121
// CloneGeomtry returns a deep clone of the Geometry.
122
func CloneGeometry(geometry geom.Geometry) (geom.Geometry, error) {
×
123
        switch geo := geometry.(type) {
×
124
        default:
×
125
                return nil, fmt.Errorf("unknown Geometry: %T", geometry)
×
126

127
        case geom.Point:
×
128
                return geom.Point{geo.X(), geo.Y()}, nil
×
129

130
        case geom.MultiPoint:
×
131
                pts := make(geom.MultiPoint, len(geo))
×
132
                for i, pt := range geo {
×
133
                        pts[i] = pt
×
134
                }
×
135
                return pts, nil
×
136

137
        case geom.LineString:
×
138
                line := make(geom.LineString, len(geo))
×
139
                for i, pt := range geo {
×
140
                        line[i] = pt
×
141
                }
×
142
                return line, nil
×
143

144
        case geom.MultiLineString:
×
145
                lines := make(geom.MultiLineString, len(geo))
×
146
                for i, line := range geo {
×
147
                        // getting a geometry interface back
×
148
                        linei, err := CloneGeometry(geom.LineString(line))
×
149
                        if err != nil {
×
150
                                return nil, fmt.Errorf("got error converting line(%v) of multiline: %v", i, err)
×
151
                        }
×
152

153
                        // get the value
154
                        linev, ok := linei.(geom.LineString)
×
155
                        if !ok {
×
156
                                panic("we did not get the conversion we were expecting")
×
157
                        }
158

159
                        lines[i] = linev
×
160
                }
161
                return lines, nil
×
162

163
        case geom.Polygon:
×
164
                // getting a geometry inteface back
×
165
                poly := make(geom.Polygon, len(geo))
×
166
                for i, line := range geo {
×
167
                        linei, err := CloneGeometry(geom.LineString(line))
×
168
                        if err != nil {
×
169
                                return nil, fmt.Errorf("got error converting line(%v) of polygon: %v", i, err)
×
170
                        }
×
171

172
                        // get the value
173
                        linev, ok := linei.(geom.LineString)
×
174
                        if !ok {
×
175
                                panic("we did not get the conversion we were expecting")
×
176
                        }
177

178
                        poly[i] = linev
×
179
                }
180
                return poly, nil
×
181

182
        case geom.MultiPolygon:
×
183
                mpoly := make(geom.MultiPolygon, len(geo))
×
184
                for i, poly := range geo {
×
185
                        // getting a geometry inteface back
×
186
                        polyi, err := CloneGeometry(geom.Polygon(poly))
×
187
                        if err != nil {
×
188
                                return nil, fmt.Errorf("got error converting polygon(%v) of multipolygon: %v", i, err)
×
189
                        }
×
190

191
                        // get the value
192
                        polyv, ok := polyi.(geom.Polygon)
×
193
                        if !ok {
×
194
                                panic("we did not get the conversion we were expecting")
×
195
                        }
196

197
                        mpoly[i] = polyv
×
198
                }
199
                return mpoly, nil
×
200
        }
201
}
202

203
// ToWebMercator takes a SRID and a geometry encode using that srid, and returns a geometry encoded as a WebMercator.
204
func ToWebMercator(SRID uint64, geometry geom.Geometry) (geom.Geometry, error) {
×
205
        switch SRID {
×
206
        default:
×
207
                return nil, fmt.Errorf("don't know how to convert from %v to %v.", tegola.WebMercator, SRID)
×
208
        case tegola.WebMercator:
×
209
                // Instead of just returning the geometry, we are cloning it so that the user of the API can rely
×
210
                // on the result to alway be a copy. Instead of being a reference in the on instance that it's already
×
211
                // in the same SRID.
×
212

×
213
                return CloneGeometry(geometry)
×
214
        case tegola.WGS84:
×
215

×
216
                return ApplyToPoints(geometry, webmercator.PToXY)
×
217
        }
218
}
219

220
// FromWebMercator takes a geometry encoded with WebMercator, and returns a Geometry encodes to the given srid.
221
func FromWebMercator(SRID uint64, geometry geom.Geometry) (geom.Geometry, error) {
×
222
        switch SRID {
×
223
        default:
×
224
                return nil, fmt.Errorf("don't know how to convert from %v to %v.", SRID, tegola.WebMercator)
×
225
        case tegola.WebMercator:
×
226
                // Instead of just returning the geometry, we are cloning it so that the user of the API can rely
×
227
                // on the result to alway be a copy. Instead of being a reference in the on instance that it's already
×
228
                // in the same SRID.
×
229
                return CloneGeometry(geometry)
×
230
        case tegola.WGS84:
×
231
                return ApplyToPoints(geometry, webmercator.PToLonLat)
×
232
        }
233
}
234

235
func interfaceAsFloatslice(v interface{}) (vals []float64, err error) {
×
236
        vs, ok := v.([]interface{})
×
237
        if !ok {
×
238
                return nil, fmt.Errorf("Incorrect value type looking for float64 slice, not %t.", v)
×
239
        }
×
240
        for _, iv := range vs {
×
241
                vv, ok := iv.(float64)
×
242
                if !ok {
×
243
                        return nil, fmt.Errorf("Incorrect value type looking for float64 slice, not %t.", v)
×
244
                }
×
245
                vals = append(vals, vv)
×
246
        }
247
        return vals, nil
×
248
}
249

250
func mapIsOfType(v map[string]interface{}, wants ...string) (string, error) {
×
251
        typ, ok := v["type"].(string)
×
252
        if !ok {
×
253
                return "", fmt.Errorf("Was not able to convert type to string.")
×
254
        }
×
255
        for _, want := range wants {
×
256
                if typ == want {
×
257
                        return typ, nil
×
258
                }
×
259
        }
260
        return "", fmt.Errorf("Expected all subtypes to be one of type (%v), not %v", strings.Join(wants, ","), v["type"])
×
261
}
262

263
func interfaceAsLine(v interface{}) (Line, error) {
×
264
        vals, err := interfaceAsFloatslice(v)
×
265
        if err != nil {
×
266
                return nil, fmt.Errorf("Incorrect values for line type: %v", err)
×
267
        }
×
268
        return NewLine(vals...), nil
×
269
}
270

271
func interfaceAsPoint(v interface{}) (Point, error) {
×
272
        vals, err := interfaceAsFloatslice(v)
×
273
        if err != nil {
×
274
                return Point{}, fmt.Errorf("Incorrect values for point type: %v", err)
×
275
        }
×
276
        return Point{vals[0], vals[1]}, nil
×
277
}
278

279
func interfaceAsPoint3(v interface{}) (Point3, error) {
×
280
        vals, err := interfaceAsFloatslice(v)
×
281
        if err != nil {
×
282
                return Point3{}, fmt.Errorf("Incorrect values for point3 type: %v", err)
×
283
        }
×
284
        return Point3{vals[0], vals[1], vals[2]}, nil
×
285
}
286

287
func forEachMapInSlice(v interface{}, do func(typ string, v interface{}) error, wants ...string) error {
×
288
        vals, ok := v.([]interface{})
×
289
        if !ok {
×
290
                return fmt.Errorf("Expected values to be []interface{}: ")
×
291
        }
×
292
        for i, iv := range vals {
×
293

×
294
                v, ok := iv.(map[string]interface{})
×
295
                if !ok {
×
296
                        return fmt.Errorf("Expected v[%v] to be map[string]interface{}: ", i)
×
297
                }
×
298
                typ, err := mapIsOfType(v, wants...)
×
299
                if err != nil {
×
300
                        return err
×
301
                }
×
302
                if err = do(typ, v["value"]); err != nil {
×
303
                        return err
×
304
                }
×
305
        }
306
        return nil
×
307
}
308

309
func interfaceAsPolygon(v interface{}) (Polygon, error) {
×
310
        var p Polygon
×
311
        err := forEachMapInSlice(v, func(_ string, v interface{}) error {
×
312
                l, err := interfaceAsLine(v)
×
313
                if err != nil {
×
314
                        return err
×
315
                }
×
316
                p = append(p, l)
×
317
                return nil
×
318
        }, "linestring")
319
        if err != nil {
×
320
                return nil, err
×
321
        }
×
322
        return p, nil
×
323
}
324

325
func MapAsGeometry(m map[string]interface{}) (geo Geometry, err error) {
×
326
        typ, err := mapIsOfType(m, "point", "point3", "linestring", "polygon", "multipolygon", "multipoint", "multiline")
×
327
        if err != nil {
×
328
                return nil, err
×
329
        }
×
330
        switch typ {
×
331
        case "point":
×
332
                return interfaceAsPoint(m["value"])
×
333
        case "point3":
×
334
                return interfaceAsPoint3(m["value"])
×
335

336
        case "linestring":
×
337
                return interfaceAsLine(m["value"])
×
338
        case "polygon":
×
339
                fmt.Println("Working on Polygon:")
×
340
                return interfaceAsPolygon(m["value"])
×
341
        case "multipolygon":
×
342
                fmt.Println("Working on MPolygon:")
×
343
                var mp MultiPolygon
×
344
                err := forEachMapInSlice(m["value"], func(_ string, v interface{}) error {
×
345
                        p, err := interfaceAsPolygon(v)
×
346
                        if err != nil {
×
347
                                return err
×
348
                        }
×
349
                        mp = append(mp, p)
×
350
                        return nil
×
351
                }, "polygon")
352
                if err != nil {
×
353
                        return nil, err
×
354
                }
×
355
                return mp, nil
×
356
        case "multipoint":
×
357
                var mp MultiPoint
×
358
                err := forEachMapInSlice(m["value"], func(_ string, v interface{}) error {
×
359
                        p, err := interfaceAsPoint(v)
×
360
                        if err != nil {
×
361
                                return err
×
362
                        }
×
363
                        mp = append(mp, p)
×
364
                        return nil
×
365
                }, "point")
366
                if err != nil {
×
367
                        return nil, err
×
368
                }
×
369
                return mp, nil
×
370
        case "multiline":
×
371
                var ml MultiLine
×
372
                err := forEachMapInSlice(m["value"], func(_ string, v interface{}) error {
×
373
                        l, err := interfaceAsLine(v)
×
374
                        if err != nil {
×
375
                                return err
×
376
                        }
×
377
                        ml = append(ml, l)
×
378
                        return nil
×
379
                }, "linestring")
380
                if err != nil {
×
381
                        return nil, err
×
382
                }
×
383
                return ml, nil
×
384
        }
385
        return nil, errors.New("Unknown type")
×
386
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc