github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/geomfn/buffer.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package geomfn 12 13 import ( 14 "strconv" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/geo" 18 "github.com/cockroachdb/cockroach/pkg/geo/geos" 19 "github.com/cockroachdb/errors" 20 ) 21 22 // BufferParams is a wrapper around the geos.BufferParams. 23 type BufferParams struct { 24 p geos.BufferParams 25 } 26 27 // MakeDefaultBufferParams returns the default BufferParams/ 28 func MakeDefaultBufferParams() BufferParams { 29 return BufferParams{ 30 p: geos.BufferParams{ 31 EndCapStyle: geos.BufferParamsEndCapStyleRound, 32 JoinStyle: geos.BufferParamsJoinStyleRound, 33 SingleSided: false, 34 QuadrantSegments: 8, 35 MitreLimit: 5.0, 36 }, 37 } 38 } 39 40 // WithQuadrantSegments returns a copy of the BufferParams with the quadrantSegments set. 41 func (b BufferParams) WithQuadrantSegments(quadrantSegments int) BufferParams { 42 ret := b 43 ret.p.QuadrantSegments = quadrantSegments 44 return ret 45 } 46 47 // ParseBufferParams parses the given buffer params from a SQL string into 48 // the BufferParams form. 49 // The string must be of the same format as specified by https://postgis.net/docs/ST_Buffer.html. 50 // Returns the BufferParams, as well as the modified distance. 51 func ParseBufferParams(s string, distance float64) (BufferParams, float64, error) { 52 p := MakeDefaultBufferParams() 53 fields := strings.Fields(s) 54 for _, field := range fields { 55 fParams := strings.Split(field, "=") 56 if len(fParams) != 2 { 57 return BufferParams{}, 0, errors.Newf("unknown buffer parameter: %s", fParams) 58 } 59 f, val := fParams[0], fParams[1] 60 switch strings.ToLower(f) { 61 case "quad_segs": 62 valInt, err := strconv.ParseInt(val, 10, 64) 63 if err != nil { 64 return BufferParams{}, 0, errors.Wrapf(err, "invalid int for %s: %s", f, val) 65 } 66 p.p.QuadrantSegments = int(valInt) 67 case "endcap": 68 switch strings.ToLower(val) { 69 case "round": 70 p.p.EndCapStyle = geos.BufferParamsEndCapStyleRound 71 case "flat", "butt": 72 p.p.EndCapStyle = geos.BufferParamsEndCapStyleFlat 73 case "square": 74 p.p.EndCapStyle = geos.BufferParamsEndCapStyleSquare 75 default: 76 return BufferParams{}, 0, errors.Newf("unknown endcap: %s (accepted: round, flat, square)", val) 77 } 78 case "join": 79 switch strings.ToLower(val) { 80 case "round": 81 p.p.JoinStyle = geos.BufferParamsJoinStyleRound 82 case "mitre", "miter": 83 p.p.JoinStyle = geos.BufferParamsJoinStyleMitre 84 case "bevel": 85 p.p.JoinStyle = geos.BufferParamsJoinStyleBevel 86 default: 87 return BufferParams{}, 0, errors.Newf("unknown join: %s (accepted: round, mitre, bevel)", val) 88 } 89 case "mitre_limit", "miter_limit": 90 valFloat, err := strconv.ParseFloat(val, 64) 91 if err != nil { 92 return BufferParams{}, 0, errors.Wrapf(err, "invalid float for %s: %s", f, val) 93 } 94 p.p.MitreLimit = valFloat 95 case "side": 96 switch strings.ToLower(val) { 97 case "both": 98 p.p.SingleSided = false 99 case "left": 100 p.p.SingleSided = true 101 case "right": 102 p.p.SingleSided = true 103 distance *= -1 104 default: 105 return BufferParams{}, 0, errors.Newf("unknown side: %s (accepted: both, left, right)", val) 106 } 107 default: 108 return BufferParams{}, 0, errors.Newf("unknown field: %s (accepted fields: quad_segs, endcap, join, mitre_limit, side)", f) 109 } 110 } 111 return p, distance, nil 112 } 113 114 // Buffer buffers a given Geometry by the supplied parameters. 115 func Buffer(g *geo.Geometry, params BufferParams, distance float64) (*geo.Geometry, error) { 116 bufferedGeom, err := geos.Buffer(g.EWKB(), params.p, distance) 117 if err != nil { 118 return nil, err 119 } 120 return geo.ParseGeometryFromEWKB(bufferedGeom) 121 }