github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/geomfn/de9im.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 "github.com/cockroachdb/cockroach/pkg/geo" 15 "github.com/cockroachdb/cockroach/pkg/geo/geos" 16 "github.com/cockroachdb/cockroach/pkg/util" 17 "github.com/cockroachdb/errors" 18 ) 19 20 // Relate returns the DE-9IM relation between A and B. 21 func Relate(a *geo.Geometry, b *geo.Geometry) (string, error) { 22 if a.SRID() != b.SRID() { 23 return "", geo.NewMismatchingSRIDsError(a, b) 24 } 25 return geos.Relate(a.EWKB(), b.EWKB()) 26 } 27 28 // RelatePattern returns whether the DE-9IM relation between A and B matches. 29 func RelatePattern(a *geo.Geometry, b *geo.Geometry, pattern string) (bool, error) { 30 if a.SRID() != b.SRID() { 31 return false, geo.NewMismatchingSRIDsError(a, b) 32 } 33 return geos.RelatePattern(a.EWKB(), b.EWKB(), pattern) 34 } 35 36 // MatchesDE9IM checks whether the given DE-9IM relation matches the DE-91M pattern. 37 // Assumes the relation has been computed, and such has no 'T' and '*' characters. 38 // See: https://en.wikipedia.org/wiki/DE-9IM. 39 func MatchesDE9IM(relation string, pattern string) (bool, error) { 40 if len(relation) != 9 { 41 return false, errors.Newf("relation %q should be of length 9", relation) 42 } 43 if len(pattern) != 9 { 44 return false, errors.Newf("pattern %q should be of length 9", pattern) 45 } 46 for i := 0; i < len(relation); i++ { 47 matches, err := relationByteMatchesPatternByte(relation[i], pattern[i]) 48 if err != nil { 49 return false, err 50 } 51 if !matches { 52 return false, nil 53 } 54 } 55 return true, nil 56 } 57 58 // relationByteMatchesPatternByte matches a single byte of a DE-9IM relation 59 // against the DE-9IM pattern. 60 // Pattern matches are as follows: 61 // * '*': allow anything. 62 // * 't'/'T': allow only if the relation is true. This means the relation must be 63 // '0' (point), '1' (line) or '2' (area) - which is the dimensionality of the 64 // intersection. 65 // * 'f'/'F': allow only if relation is also false, which is of the form 'f'/'F'. 66 func relationByteMatchesPatternByte(r byte, p byte) (bool, error) { 67 switch util.ToLowerSingleByte(p) { 68 case '*': 69 return true, nil 70 case 't': 71 if r < '0' || r > '2' { 72 return false, nil 73 } 74 case 'f': 75 if util.ToLowerSingleByte(r) != 'f' { 76 return false, nil 77 } 78 default: 79 return false, errors.Newf("unrecognized pattern character: %s", string(p)) 80 } 81 return true, nil 82 }