Compare commits
5 Commits
7f379e9d90
...
1b4d33b7ce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b4d33b7ce | ||
|
|
bac048a685 | ||
|
|
5101525607 | ||
|
|
cc74cc60f2 | ||
|
|
bcdfacc142 |
20
.mise/tasks/search
Executable file
20
.mise/tasks/search
Executable file
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/env bash
|
||||
#MISE description="TODO"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
cd "${MISE_PROJECT_ROOT}"
|
||||
|
||||
cities=()
|
||||
for city in "$@"; do
|
||||
cities+=("-t=$city")
|
||||
done
|
||||
searches=(
|
||||
"-s=mobile home park=0.5"
|
||||
"-s=schools=0.25"
|
||||
"-s=water treatment facility=1.0"
|
||||
"-s=landfill=1.5"
|
||||
"-s=police department=0.1"
|
||||
"-s=prison=2.5"
|
||||
)
|
||||
go run ./ "${searches[@]}" -d "${cities[@]}"
|
||||
112
cmd/run.go
112
cmd/run.go
@@ -5,31 +5,24 @@ import (
|
||||
"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")
|
||||
searches := StringToFloat64{}
|
||||
fs.Var(&searches, "s", "list of things to search for around each town")
|
||||
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
radius := *area / convertToMiles
|
||||
radiusX := radius / 2
|
||||
radiusY := radius / 3
|
||||
|
||||
m, err := NewMapsOf(ctx, fs.Args()[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
results, err := m.Search(ctx, fs.Args()[1], *searchRadius)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type geoJson struct {
|
||||
Type string `json:"type"`
|
||||
@@ -41,24 +34,51 @@ func Run(ctx context.Context) error {
|
||||
Coordinates []any `json:"coordinates"`
|
||||
} `json:"geometry"`
|
||||
}
|
||||
geoJsons := make([]geoJson, len(results))
|
||||
for i := range results {
|
||||
geoJsons[i].Type = "Feature"
|
||||
geoJsons[i].Properties.Name = path.Join(fs.Args()[1], results[i].Name)
|
||||
geoJsons[i].Geometry.Type = "Point"
|
||||
geoJsons[i].Geometry.Coordinates = []any{results[i].Lng, results[i].Lat}
|
||||
if *doArea {
|
||||
geoJsons[i].Geometry.Type = "Polygon"
|
||||
x, y := results[i].Lng, results[i].Lat
|
||||
geoJsons[i].Geometry.Coordinates = []any{[]any{
|
||||
[2]float64{x - radiusX, y + radiusY}, // top left
|
||||
[2]float64{x + radiusX, y + radiusY}, // top righ
|
||||
[2]float64{x + radiusX, y - radiusY}, // bot righ
|
||||
[2]float64{x - radiusX, y - radiusY}, // bot left
|
||||
[2]float64{x - radiusX, y + radiusY}, // top left
|
||||
}}
|
||||
geoJsons := []geoJson{}
|
||||
for _, town := range towns {
|
||||
for search, area := range searches {
|
||||
radius := area / convertToMiles
|
||||
radiusX := 2 * radius / 2
|
||||
radiusY := 2 * radius / 3
|
||||
m, err := NewMapsOf(ctx, town)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
results, err := m.Search(ctx, search, *searchRadius)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range results {
|
||||
var a geoJson
|
||||
a.Type = "Feature"
|
||||
a.Properties.Name = path.Join(search, 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",
|
||||
@@ -67,3 +87,35 @@ func Run(ctx context.Context) error {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type StringToFloat64 map[string]float64
|
||||
|
||||
func (array *StringToFloat64) String() string {
|
||||
return fmt.Sprintf("%+v", (*map[string]float64)(array))
|
||||
}
|
||||
|
||||
func (array *StringToFloat64) Set(s string) error {
|
||||
idx := strings.Index(s, "=")
|
||||
if idx < 0 {
|
||||
return fmt.Errorf("should be formatted as k=v")
|
||||
}
|
||||
k := s[:idx]
|
||||
v := s[idx+1:]
|
||||
var n float64
|
||||
if err := json.Unmarshal([]byte(v), &n); err != nil {
|
||||
return err
|
||||
}
|
||||
(*array)[k] = n
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,5 +8,8 @@ run = "mise run search -- {sammamish,duvall,'cottage lake',issaquah,snohomish}',
|
||||
[tasks.olympia]
|
||||
run = "mise run search -- {olympia,lacey,tumwater}', wa'"
|
||||
|
||||
[tasks.bend]
|
||||
run = "mise run search -- 'bend, or'"
|
||||
|
||||
[tasks.bellingham]
|
||||
run = "mise run search -- {burlington,sedro-wooley,'mt vernon',bellingham,ferndale}', wa'"
|
||||
|
||||
Reference in New Issue
Block a user