
The big change is that the GeoJSON package has been completely rewritten to fix a few of geometry calculation bugs, increase performance, and to better follow the GeoJSON spec RFC 7946. GeoJSON updates - A LineString now requires at least two points. - All json members, even foreign, now persist with the object. - The bbox member persists too but is no longer used for geometry calculations. This is change in behavior. Previously Tile38 would treat the bbox as the object's physical rectangle. - Corrections to geometry intersects and within calculations. Faster spatial queries - The performance of Point-in-polygon and object intersect operations are greatly improved for complex polygons and line strings. It went from O(n) to roughly O(log n). - The same for all collection types with many children, including FeatureCollection, GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon. Codebase changes - The pkg directory has been renamed to internal - The GeoJSON internal package has been moved to a seperate repo at https://github.com/tidwall/geojson. It's now vendored. Please look out for higher memory usage for datasets using complex shapes. A complex shape is one that has 64 or more points. For these shapes it's expected that there will be increase of least 54 bytes per point.
168 lines
3.8 KiB
Go
168 lines
3.8 KiB
Go
// +build ignore
|
|
|
|
package core
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
clear = "\x1b[0m"
|
|
bright = "\x1b[1m"
|
|
gray = "\x1b[90m"
|
|
yellow = "\x1b[33m"
|
|
)
|
|
|
|
// Command represents a Tile38 command.
|
|
type Command struct {
|
|
Name string `json:"-"`
|
|
Summary string `json:"summary"`
|
|
Complexity string `json:"complexity"`
|
|
Arguments []Argument `json:"arguments"`
|
|
Since string `json:"since"`
|
|
Group string `json:"group"`
|
|
DevOnly bool `json:"dev"`
|
|
}
|
|
|
|
// String returns a string representation of the command.
|
|
func (c Command) String() string {
|
|
var s = c.Name
|
|
for _, arg := range c.Arguments {
|
|
s += " " + arg.String()
|
|
}
|
|
return s
|
|
}
|
|
|
|
// TermOutput returns a string representation of the command suitable for displaying in a terminal.
|
|
func (c Command) TermOutput(indent string) string {
|
|
line := c.String()
|
|
var line1 string
|
|
if strings.HasPrefix(line, c.Name) {
|
|
line1 = bright + c.Name + clear + gray + line[len(c.Name):] + clear
|
|
} else {
|
|
line1 = bright + strings.Replace(c.String(), " ", " "+clear+gray, 1) + clear
|
|
}
|
|
line2 := yellow + "summary: " + clear + c.Summary
|
|
//line3 := yellow + "since: " + clear + c.Since
|
|
return indent + line1 + "\n" + indent + line2 + "\n" //+ indent + line3 + "\n"
|
|
}
|
|
|
|
// EnumArg represents a enum arguments.
|
|
type EnumArg struct {
|
|
Name string `json:"name"`
|
|
Arguments []Argument `json:"arguments"`
|
|
}
|
|
|
|
// String returns a string representation of an EnumArg.
|
|
func (a EnumArg) String() string {
|
|
var s = a.Name
|
|
for _, arg := range a.Arguments {
|
|
s += " " + arg.String()
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Argument represents a command argument.
|
|
type Argument struct {
|
|
Command string `json:"command"`
|
|
NameAny interface{} `json:"name"`
|
|
TypeAny interface{} `json:"type"`
|
|
Optional bool `json:"optional"`
|
|
Multiple bool `json:"multiple"`
|
|
Variadic bool `json:"variadic"`
|
|
Enum []string `json:"enum"`
|
|
EnumArgs []EnumArg `json:"enumargs"`
|
|
}
|
|
|
|
// String returns a string representation of an Argument.
|
|
func (a Argument) String() string {
|
|
var s string
|
|
if a.Command != "" {
|
|
s += " " + a.Command
|
|
}
|
|
if len(a.EnumArgs) > 0 {
|
|
eargs := ""
|
|
for _, arg := range a.EnumArgs {
|
|
v := arg.String()
|
|
if strings.Contains(v, " ") {
|
|
v = "(" + v + ")"
|
|
}
|
|
eargs += v + "|"
|
|
}
|
|
if len(eargs) > 0 {
|
|
eargs = eargs[:len(eargs)-1]
|
|
}
|
|
s += " " + eargs
|
|
} else if len(a.Enum) > 0 {
|
|
s += " " + strings.Join(a.Enum, "|")
|
|
} else {
|
|
names, _ := a.NameTypes()
|
|
subs := ""
|
|
for _, name := range names {
|
|
subs += " " + name
|
|
}
|
|
subs = strings.TrimSpace(subs)
|
|
s += " " + subs
|
|
if a.Variadic {
|
|
if len(names) == 0 {
|
|
s += " [" + subs + " ...]"
|
|
} else {
|
|
s += " [" + names[len(names)-1] + " ...]"
|
|
}
|
|
}
|
|
if a.Multiple {
|
|
s += " ..."
|
|
}
|
|
}
|
|
s = strings.TrimSpace(s)
|
|
if a.Optional {
|
|
s = "[" + s + "]"
|
|
}
|
|
return s
|
|
}
|
|
|
|
func parseAnyStringArray(any interface{}) []string {
|
|
if str, ok := any.(string); ok {
|
|
return []string{str}
|
|
} else if any, ok := any.([]interface{}); ok {
|
|
arr := []string{}
|
|
for _, any := range any {
|
|
if str, ok := any.(string); ok {
|
|
arr = append(arr, str)
|
|
}
|
|
}
|
|
return arr
|
|
}
|
|
return []string{}
|
|
}
|
|
|
|
// NameTypes returns the types and names of an argument as separate arrays.
|
|
func (a Argument) NameTypes() (names, types []string) {
|
|
names = parseAnyStringArray(a.NameAny)
|
|
types = parseAnyStringArray(a.TypeAny)
|
|
if len(types) > len(names) {
|
|
types = types[:len(names)]
|
|
} else {
|
|
for len(types) < len(names) {
|
|
types = append(types, "")
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Commands is a map of all of the commands.
|
|
var Commands = func() map[string]Command {
|
|
var commands map[string]Command
|
|
if err := json.Unmarshal([]byte(commandsJSON), &commands); err != nil {
|
|
panic(err.Error())
|
|
}
|
|
for name, command := range commands {
|
|
command.Name = strings.ToUpper(name)
|
|
commands[name] = command
|
|
}
|
|
return commands
|
|
}()
|
|
|
|
var commandsJSON = `{{.CommandsJSON}}`
|