package radarfetch import ( "fmt" "image" "image/color" "image/png" "os" "path/filepath" ) // AttachClusterPNGs renders a tiny PNG for each cluster by flood-filling // from its centroid on the thresholded mask, cropping to the cluster bbox. // It writes files to outDir/clusters/cluster-.png and returns updated clusters // with PNG field filled. func AttachClusterPNGs(grid [][]*float64, thr float64, clusters []Cluster, outDir string) ([]Cluster, error) { const W, H = 256, 256 if len(grid) != H || (len(grid) > 0 && len(grid[0]) != W) { return clusters, nil } // precompute threshold mask mask := make([][]bool, H) for r := 0; r < H; r++ { mask[r] = make([]bool, W) for c := 0; c < W; c++ { if grid[r][c] == nil { continue } if *grid[r][c] >= thr { mask[r][c] = true } } } outDir = filepath.Join(outDir, "clusters") _ = os.MkdirAll(outDir, 0o755) for i := range clusters { cl := &clusters[i] // BFS from (Row,Col) within mask to reconstruct membership r0, c0 := cl.Row, cl.Col if r0 < 0 || r0 >= H || c0 < 0 || c0 >= W || !mask[r0][c0] { // skip if centroid not on mask continue } minR, minC := cl.MinRow, cl.MinCol maxR, maxC := cl.MaxRow, cl.MaxCol w := maxC - minC + 1 h := maxR - minR + 1 if w <= 0 || h <= 0 || w > W || h > H { continue } img := image.NewRGBA(image.Rect(0, 0, w, h)) // init transparent for y := 0; y < h; y++ { for x := 0; x < w; x++ { img.SetRGBA(x, y, color.RGBA{0, 0, 0, 0}) } } // flood fill within bbox vis := make([][]bool, H) for r := 0; r < H; r++ { vis[r] = make([]bool, W) } stack := [][2]int{{r0, c0}} vis[r0][c0] = true dirs := [][2]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}} for len(stack) > 0 { cur := stack[len(stack)-1] stack = stack[:len(stack)-1] rr, cc := cur[0], cur[1] if rr < minR || rr > maxR || cc < minC || cc > maxC { continue } // paint dbz := grid[rr][cc] if dbz != nil { col := colorForDBZ(*dbz) img.SetRGBA(cc-minC, rr-minR, col) } for _, d := range dirs { nr, nc := rr+d[0], cc+d[1] if nr < 0 || nr >= H || nc < 0 || nc >= W { continue } if vis[nr][nc] || !mask[nr][nc] { continue } vis[nr][nc] = true stack = append(stack, [2]int{nr, nc}) } } // write file name := fmt.Sprintf("cluster-%d.png", cl.ID) p := filepath.Join(outDir, name) f, err := os.Create(p) if err != nil { continue } _ = png.Encode(f, img) _ = f.Close() cl.PNG = filepath.Join(filepath.Base(outDir), name) } return clusters, nil }