github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/summary.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 geo 12 13 import ( 14 "fmt" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/geo/geopb" 18 "github.com/cockroachdb/errors" 19 "github.com/twpayne/go-geom" 20 ) 21 22 // Summary returns a text summary of the contents of the geometry type. 23 // 24 // Flags shown square brackets after the geometry type have the following meaning: 25 // M: has M coordinate 26 // Z: has Z coordinate 27 // B: has a cached bounding box 28 // G: is geography 29 // S: has spatial reference system 30 func Summary(t geom.T, shape geopb.Shape, isGeography bool) (string, error) { 31 return summary(t, shape, isGeography, 0) 32 } 33 34 func summary( 35 t geom.T, shape geopb.Shape, isGeography bool, offset int, 36 ) (summaryLine string, err error) { 37 f, err := summaryFlag(t, isGeography) 38 if err != nil { 39 return "", err 40 } 41 42 summaryLine += strings.Repeat(" ", offset) 43 switch t := t.(type) { 44 case *geom.Point: 45 return summaryLine + fmt.Sprintf("%s[%s]", shape.String(), f), nil 46 case *geom.LineString: 47 return summaryLine + fmt.Sprintf("%s[%s] with %d points", shape.String(), f, t.NumCoords()), nil 48 case *geom.Polygon: 49 numLinearRings := t.NumLinearRings() 50 51 summaryLine += fmt.Sprintf("%s[%s] with %d ring", shape.String(), f, t.NumLinearRings()) 52 if numLinearRings > 1 { 53 summaryLine += "s" 54 } 55 56 for i := 0; i < numLinearRings; i++ { 57 ring := t.LinearRing(i) 58 summaryLine += fmt.Sprintf("\n ring %d has %d points", i, ring.NumCoords()) 59 } 60 61 return summaryLine, nil 62 case *geom.MultiPoint: 63 numPoints := t.NumPoints() 64 65 summaryLine += fmt.Sprintf("%s[%s] with %d element", shape.String(), f, numPoints) 66 if 1 < numPoints { 67 summaryLine += "s" 68 } 69 70 for i := 0; i < numPoints; i++ { 71 point := t.Point(i) 72 line, err := summary(point, geopb.Shape_Point, isGeography, offset+2) 73 if err != nil { 74 return "", err 75 } 76 77 summaryLine += "\n" + line 78 } 79 80 return summaryLine, nil 81 case *geom.MultiLineString: 82 numLineStrings := t.NumLineStrings() 83 84 summaryLine += fmt.Sprintf("%s[%s] with %d element", shape.String(), f, numLineStrings) 85 if 1 < numLineStrings { 86 summaryLine += "s" 87 } 88 89 for i := 0; i < numLineStrings; i++ { 90 lineString := t.LineString(i) 91 line, err := summary(lineString, geopb.Shape_LineString, isGeography, offset+2) 92 if err != nil { 93 return "", err 94 } 95 96 summaryLine += "\n" + line 97 } 98 99 return summaryLine, nil 100 case *geom.MultiPolygon: 101 numPolygons := t.NumPolygons() 102 103 summaryLine += fmt.Sprintf("%s[%s] with %d element", shape.String(), f, numPolygons) 104 if 1 < numPolygons { 105 summaryLine += "s" 106 } 107 108 for i := 0; i < numPolygons; i++ { 109 polygon := t.Polygon(i) 110 line, err := summary(polygon, geopb.Shape_Polygon, isGeography, offset+2) 111 if err != nil { 112 return "", err 113 } 114 115 summaryLine += "\n" + line 116 } 117 118 return summaryLine, nil 119 case *geom.GeometryCollection: 120 numGeoms := t.NumGeoms() 121 122 summaryLine += fmt.Sprintf("%s[%s] with %d element", shape.String(), f, numGeoms) 123 if 1 < numGeoms { 124 summaryLine += "s" 125 } 126 127 for i := 0; i < numGeoms; i++ { 128 g := t.Geom(i) 129 gShape, err := geopbShape(g) 130 if err != nil { 131 return "", err 132 } 133 134 line, err := summary(g, gShape, isGeography, offset+2) 135 if err != nil { 136 return "", err 137 } 138 139 summaryLine += "\n" + line 140 } 141 142 return summaryLine, nil 143 default: 144 return "", errors.Newf("unsupported geom type: %T", t) 145 } 146 } 147 148 func summaryFlag(t geom.T, isGeography bool) (f string, err error) { 149 layout := t.Layout() 150 if layout.MIndex() != -1 { 151 f += "M" 152 } 153 154 if layout.ZIndex() != -1 { 155 f += "Z" 156 } 157 158 bbox, err := BoundingBoxFromGeom(t) 159 if err != nil { 160 return "", err 161 } 162 163 if bbox != nil { 164 f += "B" 165 } 166 167 if geopb.SRID(t.SRID()) != geopb.UnknownSRID { 168 f += "S" 169 } 170 171 if isGeography { 172 f += "G" 173 } 174 175 return f, nil 176 }