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