1package geojson 2 3import "github.com/tidwall/gjson" 4 5func resIsArray(res gjson.Result) bool { 6 if res.Type == gjson.JSON { 7 for i := 0; i < len(res.Raw); i++ { 8 if res.Raw[i] == '[' { 9 return true 10 } 11 if res.Raw[i] <= ' ' { 12 continue 13 } 14 break 15 } 16 } 17 return false 18} 19 20//////////////////////////////// 21// level 1 22//////////////////////////////// 23 24func fillLevel1Map(json string) ( 25 coordinates Position, bbox *BBox, err error, 26) { 27 coords := gjson.Get(json, "coordinates") 28 switch coords.Type { 29 default: 30 err = errInvalidCoordinates 31 return 32 case gjson.Null: 33 err = errCoordinatesRequired 34 return 35 case gjson.JSON: 36 if !resIsArray(coords) { 37 err = errInvalidCoordinates 38 return 39 } 40 coordinates, err = fillPosition(coords) 41 if err != nil { 42 return 43 } 44 } 45 bbox, err = fillBBox(json) 46 return 47} 48 49func level1CalculatedBBox(coordinates Position, bbox *BBox) BBox { 50 if bbox != nil { 51 return *bbox 52 } 53 return BBox{ 54 Min: coordinates, 55 Max: coordinates, 56 } 57} 58 59func level1PositionCount(coordinates Position, bbox *BBox) int { 60 if bbox != nil { 61 return 3 62 } 63 return 1 64} 65 66func level1Weight(coordinates Position, bbox *BBox) int { 67 return level1PositionCount(coordinates, bbox) * sizeofPosition 68} 69 70func appendLevel1JSON(json []byte, name string, coordinates Position, bbox *BBox, bboxDefined bool) []byte { 71 if bbox != nil && !bboxDefined { 72 bbox = nil 73 } 74 isCordZ := level1IsCoordZDefined(coordinates, bbox) 75 json = append(json, `{"type":"`...) 76 json = append(json, name...) 77 json = append(json, `","coordinates":[`...) 78 json = appendPositionJSON(json, coordinates, isCordZ) 79 json = append(json, ']') 80 if bboxDefined { 81 json = appendBBoxJSON(json, bbox) 82 } 83 return append(json, '}') 84} 85 86func level1IsCoordZDefined(coordinates Position, bbox *BBox) bool { 87 if bbox.isCordZDefined() { 88 return true 89 } 90 return coordinates.Z != nilz 91} 92 93//////////////////////////////// 94// level 2 95//////////////////////////////// 96 97func fillLevel2Map(json string) ( 98 coordinates []Position, bbox *BBox, err error, 99) { 100 coords := gjson.Get(json, "coordinates") 101 switch coords.Type { 102 default: 103 err = errInvalidCoordinates 104 return 105 case gjson.Null: 106 err = errCoordinatesRequired 107 return 108 case gjson.JSON: 109 if !resIsArray(coords) { 110 err = errInvalidCoordinates 111 return 112 } 113 v := coords.Array() 114 coordinates = make([]Position, len(v)) 115 for i, coords := range v { 116 if !resIsArray(coords) { 117 err = errInvalidCoordinates 118 return 119 } 120 var p Position 121 p, err = fillPosition(coords) 122 if err != nil { 123 return 124 } 125 coordinates[i] = p 126 } 127 } 128 bbox, err = fillBBox(json) 129 return 130} 131 132func level2CalculatedBBox(coordinates []Position, bbox *BBox) BBox { 133 if bbox != nil { 134 return *bbox 135 } 136 _, bbox2 := positionBBox(0, BBox{}, coordinates) 137 return bbox2 138} 139 140func level2PositionCount(coordinates []Position, bbox *BBox) int { 141 if bbox != nil { 142 return 2 + len(coordinates) 143 } 144 return len(coordinates) 145} 146 147func level2Weight(coordinates []Position, bbox *BBox) int { 148 return level2PositionCount(coordinates, bbox) * sizeofPosition 149} 150 151func appendLevel2JSON(json []byte, name string, coordinates []Position, bbox *BBox, bboxDefined bool) []byte { 152 if bbox != nil && !bboxDefined { 153 bbox = nil 154 } 155 isCordZ := level2IsCoordZDefined(coordinates, bbox) 156 json = append(json, `{"type":"`...) 157 json = append(json, name...) 158 json = append(json, `","coordinates":[`...) 159 for i, p := range coordinates { 160 if i > 0 { 161 json = append(json, ',') 162 } 163 json = append(json, '[') 164 json = appendPositionJSON(json, p, isCordZ) 165 json = append(json, ']') 166 } 167 json = append(json, ']') 168 if bboxDefined { 169 json = appendBBoxJSON(json, bbox) 170 } 171 json = append(json, '}') 172 return json 173} 174 175func level2IsCoordZDefined(coordinates []Position, bbox *BBox) bool { 176 if bbox.isCordZDefined() { 177 return true 178 } 179 for _, p := range coordinates { 180 if p.Z != nilz { 181 return true 182 } 183 } 184 return false 185} 186 187//////////////////////////////// 188// level 3 189//////////////////////////////// 190 191func fillLevel3Map(json string) ( 192 coordinates [][]Position, bbox *BBox, err error, 193) { 194 coords := gjson.Get(json, "coordinates") 195 switch coords.Type { 196 default: 197 err = errInvalidCoordinates 198 return 199 case gjson.Null: 200 err = errCoordinatesRequired 201 return 202 case gjson.JSON: 203 if !resIsArray(coords) { 204 err = errInvalidCoordinates 205 return 206 } 207 v := coords.Array() 208 coordinates = make([][]Position, len(v)) 209 for i, coords := range v { 210 if !resIsArray(coords) { 211 err = errInvalidCoordinates 212 return 213 } 214 v := coords.Array() 215 ps := make([]Position, len(v)) 216 for i, coords := range v { 217 if !resIsArray(coords) { 218 err = errInvalidCoordinates 219 return 220 } 221 var p Position 222 p, err = fillPosition(coords) 223 if err != nil { 224 return 225 } 226 ps[i] = p 227 } 228 coordinates[i] = ps 229 } 230 } 231 bbox, err = fillBBox(json) 232 return 233} 234 235func level3CalculatedBBox(coordinates [][]Position, bbox *BBox, isPolygon bool) BBox { 236 if bbox != nil { 237 return *bbox 238 } 239 var bbox2 BBox 240 var i = 0 241 for _, ps := range coordinates { 242 i, bbox2 = positionBBox(i, bbox2, ps) 243 if isPolygon { 244 break // only the exterior ring should be calculated for a polygon 245 } 246 } 247 return bbox2 248} 249 250func level3Weight(coordinates [][]Position, bbox *BBox) int { 251 return level3PositionCount(coordinates, bbox) * sizeofPosition 252} 253 254func level3PositionCount(coordinates [][]Position, bbox *BBox) int { 255 var res int 256 for _, p := range coordinates { 257 res += len(p) 258 } 259 if bbox != nil { 260 return 2 + res 261 } 262 return res 263} 264 265func appendLevel3JSON(json []byte, name string, coordinates [][]Position, bbox *BBox, bboxDefined bool) []byte { 266 if bbox != nil && !bboxDefined { 267 bbox = nil 268 } 269 isCordZ := level3IsCoordZDefined(coordinates, bbox) 270 json = append(json, `{"type":"`...) 271 json = append(json, name...) 272 json = append(json, `","coordinates":[`...) 273 for i, p := range coordinates { 274 if i > 0 { 275 json = append(json, ',') 276 } 277 json = append(json, '[') 278 for i, p := range p { 279 if i > 0 { 280 json = append(json, ',') 281 } 282 json = append(json, '[') 283 json = appendPositionJSON(json, p, isCordZ) 284 json = append(json, ']') 285 } 286 json = append(json, ']') 287 } 288 json = append(json, ']') 289 if bboxDefined { 290 json = appendBBoxJSON(json, bbox) 291 } 292 return append(json, '}') 293} 294 295func level3IsCoordZDefined(coordinates [][]Position, bbox *BBox) bool { 296 if bbox.isCordZDefined() { 297 return true 298 } 299 for _, p := range coordinates { 300 for _, p := range p { 301 if p.Z != nilz { 302 return true 303 } 304 } 305 } 306 return false 307} 308 309//////////////////////////////// 310// level 4 311//////////////////////////////// 312 313func fillLevel4Map(json string) ( 314 coordinates [][][]Position, bbox *BBox, err error, 315) { 316 coords := gjson.Get(json, "coordinates") 317 switch coords.Type { 318 default: 319 err = errInvalidCoordinates 320 return 321 case gjson.Null: 322 err = errCoordinatesRequired 323 return 324 case gjson.JSON: 325 if !resIsArray(coords) { 326 err = errInvalidCoordinates 327 return 328 } 329 v := coords.Array() 330 coordinates = make([][][]Position, len(v)) 331 for i, coords := range v { 332 if !resIsArray(coords) { 333 err = errInvalidCoordinates 334 return 335 } 336 v := coords.Array() 337 ps := make([][]Position, len(v)) 338 for i, coords := range v { 339 if !resIsArray(coords) { 340 err = errInvalidCoordinates 341 return 342 } 343 v := coords.Array() 344 pss := make([]Position, len(v)) 345 for i, coords := range v { 346 if !resIsArray(coords) { 347 err = errInvalidCoordinates 348 return 349 } 350 var p Position 351 p, err = fillPosition(coords) 352 if err != nil { 353 return 354 } 355 pss[i] = p 356 } 357 ps[i] = pss 358 } 359 coordinates[i] = ps 360 } 361 } 362 bbox, err = fillBBox(json) 363 return 364} 365 366func level4Weight(coordinates [][][]Position, bbox *BBox) int { 367 return level4PositionCount(coordinates, bbox) * sizeofPosition 368} 369 370func level4PositionCount(coordinates [][][]Position, bbox *BBox) int { 371 var res int 372 for _, p := range coordinates { 373 for _, p := range p { 374 res += len(p) 375 } 376 } 377 if bbox != nil { 378 return 2 + res 379 } 380 return res 381} 382 383func appendLevel4JSON(json []byte, name string, coordinates [][][]Position, bbox *BBox, bboxDefined bool) []byte { 384 if bbox != nil && !bboxDefined { 385 bbox = nil 386 } 387 isCordZ := level4IsCoordZDefined(coordinates, bbox) 388 json = append(json, `{"type":"`...) 389 json = append(json, name...) 390 json = append(json, `","coordinates":[`...) 391 for i, p := range coordinates { 392 if i > 0 { 393 json = append(json, ',') 394 } 395 json = append(json, '[') 396 for i, p := range p { 397 if i > 0 { 398 json = append(json, ',') 399 } 400 json = append(json, '[') 401 for i, p := range p { 402 if i > 0 { 403 json = append(json, ',') 404 } 405 json = append(json, '[') 406 json = appendPositionJSON(json, p, isCordZ) 407 json = append(json, ']') 408 } 409 json = append(json, ']') 410 } 411 json = append(json, ']') 412 } 413 json = append(json, ']') 414 if bboxDefined { 415 json = appendBBoxJSON(json, bbox) 416 } 417 return append(json, '}') 418} 419 420func level4IsCoordZDefined(coordinates [][][]Position, bbox *BBox) bool { 421 if bbox.isCordZDefined() { 422 return true 423 } 424 for _, p := range coordinates { 425 for _, p := range p { 426 for _, p := range p { 427 if p.Z != nilz { 428 return true 429 } 430 } 431 } 432 } 433 return false 434} 435