package cmd import ( "context" "encoding/json" "flag" "fmt" "log" "os" "path" "slices" "strings" ) func Run(ctx context.Context) error { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) searchRadius := fs.Float64("r", 5.0, "search radius in miles") area := fs.Float64("a", 0.5, "result radius in miles") doArea := fs.Bool("d", false, "do result radius in miles") var towns FlagStringArray fs.Var(&towns, "t", "list of towns to search around") if err := fs.Parse(os.Args[1:]); err != nil { panic(err) } radius := *area / convertToMiles radiusX := 2 * radius / 2 radiusY := 2 * radius / 3 type geoJson struct { Type string `json:"type"` Properties struct { Name string `json:"name"` } `json:"properties"` Geometry struct { Type string `json:"type"` Coordinates []any `json:"coordinates"` } `json:"geometry"` } geoJsons := []geoJson{} for _, town := range towns { m, err := NewMapsOf(ctx, town) if err != nil { return err } results, err := m.Search(ctx, fs.Args()[0], *searchRadius) if err != nil { return err } for i := range results { var a geoJson a.Type = "Feature" a.Properties.Name = path.Join(fs.Args()[0], results[i].Name) a.Geometry.Type = "Point" a.Geometry.Coordinates = []any{results[i].Lng, results[i].Lat} if *doArea { a.Geometry.Type = "Polygon" x, y := results[i].Lng, results[i].Lat a.Geometry.Coordinates = []any{[]any{ [2]float64{x, y + radiusY}, // top [2]float64{x + radiusX, y}, // right [2]float64{x, y - radiusY}, // bot [2]float64{x - radiusX, y}, // left [2]float64{x, y + radiusY}, // top }} } geoJsons = append(geoJsons, a) } } log.Println(len(geoJsons)) slices.SortFunc(geoJsons, func(a, b geoJson) int { return strings.Compare(fmt.Sprint(a.Geometry.Coordinates), fmt.Sprint(b.Geometry.Coordinates)) }) geoJsons = slices.CompactFunc(geoJsons, func(a, b geoJson) bool { return fmt.Sprint(a.Geometry.Coordinates) == fmt.Sprint(b.Geometry.Coordinates) }) log.Println("COMPACTED", len(geoJsons)) b, _ := json.Marshal(map[string]any{ "features": geoJsons, "type": "FeatureCollection", }) fmt.Printf("%s\n", b) return ctx.Err() } type FlagStringArray []string func (array *FlagStringArray) String() string { return strings.Join(*array, ", ") } func (array *FlagStringArray) Set(s string) error { *array = append(*array, s) return nil }