备份与迷雾的差异分析、合并执行,附属数据改挂坐标键
备份(.rondbackup)与迷雾(.fwss)各加一层「先看差异再动手」: - 迷雾:上传先出差异页,说清叠加能补多少、整体替换会丢多少,并在真实底图上 用绿/灰/红标出会新增 / 不变 / 会丢的区域 - 备份:与当前数据集按 UUID 逐条比对(rond 每次导出都会重排 Z_PK,编号认不出人), 新增合入、冲突逐条选、仅站内有逐条勾选删除,全在一个事务里执行; 合入的行写回 entity_raw,保证再传同一份备份时差异归零 - 地点按坐标对齐:站点的「补全地址」会把地点改名,拿名称当键会让一整个地点的 到访全变成假冲突 - 附属数据(备注/结论/访客票/图片)从 dataset_id+src_pk 换成坐标键,换数据集不再失联; 访客票没有 dataset_id,回填按活跃数据集认领 - 修正 contentHash 拿 Z_PK 当指纹的隐患,以及两处「src_pk 跨快照稳定」的错误注释 导出格式(.rondbackup / .fwss)保持原样,往返测试通过。
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
package fog
|
||||
|
||||
import (
|
||||
"image"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func bmOf(cells ...[2]int) []byte {
|
||||
bm := make([]byte, bitmapSize)
|
||||
for _, c := range cells {
|
||||
bm[c[1]*8+c[0]/8] |= 0x80 >> (c[0] % 8)
|
||||
}
|
||||
return bm
|
||||
}
|
||||
|
||||
func pixAt(img *image.NRGBA, px, py int) [4]byte {
|
||||
i := (py*256 + px) * 4
|
||||
return [4]byte{img.Pix[i], img.Pix[i+1], img.Pix[i+2], img.Pix[i+3]}
|
||||
}
|
||||
|
||||
// z=18 时一格正好 16 像素,块 (100,200) 完整落在瓦片 (400,800) 里,
|
||||
// 格 (col,row) 的中心像素是 (col*16+8, row*16+8)。
|
||||
func TestRenderDiffTilePerCell(t *testing.T) {
|
||||
key := [2]int{100, 200}
|
||||
cur := map[[2]int][]byte{key: bmOf([2]int{0, 0}, [2]int{4, 0})}
|
||||
inc := map[[2]int][]byte{key: bmOf([2]int{0, 0}, [2]int{1, 0})}
|
||||
img := RenderDiffTile(cur, inc, 18, 400, 800, "wgs84")
|
||||
if img == nil {
|
||||
t.Fatal("瓦片不该为空")
|
||||
}
|
||||
if got := pixAt(img, 8, 8); got != DiffBothColor {
|
||||
t.Errorf("两边都有的格应为灰色,实际 %v", got)
|
||||
}
|
||||
if got := pixAt(img, 24, 8); got != DiffGainColor {
|
||||
t.Errorf("只有快照有的格应为绿色,实际 %v", got)
|
||||
}
|
||||
if got := pixAt(img, 72, 8); got != DiffLostColor {
|
||||
t.Errorf("只有库里有、整体替换会丢的格应为红色,实际 %v", got)
|
||||
}
|
||||
if got := pixAt(img, 200, 200); got[3] != 0 {
|
||||
t.Errorf("没被探索的格应保持透明,实际 %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderDiffTileSingleSided(t *testing.T) {
|
||||
key := [2]int{100, 200}
|
||||
onlyCur := RenderDiffTile(map[[2]int][]byte{key: bmOf([2]int{3, 3})}, nil, 18, 400, 800, "wgs84")
|
||||
if got := pixAt(onlyCur, 56, 56); got != DiffLostColor {
|
||||
t.Errorf("快照里完全没有的块应整块为红,实际 %v", got)
|
||||
}
|
||||
onlyInc := RenderDiffTile(nil, map[[2]int][]byte{key: bmOf([2]int{3, 3})}, 18, 400, 800, "wgs84")
|
||||
if got := pixAt(onlyInc, 56, 56); got != DiffGainColor {
|
||||
t.Errorf("库里完全没有的块应整块为绿,实际 %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// z=10 时一格不足一像素,块只占 4x4 像素,按块内多数类涂色。
|
||||
func TestRenderDiffTileCoarseZoomUsesDominantKind(t *testing.T) {
|
||||
key := [2]int{100, 200}
|
||||
cur := map[[2]int][]byte{key: bmOf([2]int{0, 0})}
|
||||
inc := map[[2]int][]byte{key: bmOf([2]int{1, 1}, [2]int{2, 2}, [2]int{3, 3})}
|
||||
img := RenderDiffTile(cur, inc, 10, 1, 3, "wgs84")
|
||||
|
||||
const step, scale = WorldCells >> 10, 256.0 / (WorldCells >> 10)
|
||||
bx, by := float64(key[0]*BlockCells), float64(key[1]*BlockCells)
|
||||
px := int(math.Floor((bx - 1*step) * scale))
|
||||
py := int(math.Floor((by - 3*step) * scale))
|
||||
if got := pixAt(img, px+1, py+1); got != DiffGainColor {
|
||||
t.Errorf("三格新增、一格不变的块应以绿色为主,实际 %v", got)
|
||||
}
|
||||
if w := int(math.Ceil(float64(BlockCells) * scale)); w != 4 {
|
||||
t.Fatalf("z=10 下块应占 4 像素,实际 %d", w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderDiffTileEdgeCases(t *testing.T) {
|
||||
if RenderDiffTile(nil, nil, 18, 400, 800, "wgs84") == nil {
|
||||
t.Error("两边都空也应返回一张空瓦片")
|
||||
}
|
||||
if RenderDiffTile(nil, nil, 23, 0, 0, "wgs84") != nil {
|
||||
t.Error("超出缩放范围应返回 nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDominantKind(t *testing.T) {
|
||||
cases := []struct {
|
||||
both, gain, lost int
|
||||
want uint8
|
||||
}{
|
||||
{0, 0, 0, diffNone},
|
||||
{5, 1, 0, diffBoth},
|
||||
{1, 5, 0, diffGain},
|
||||
{1, 0, 5, diffLost},
|
||||
{2, 2, 0, diffGain}, // 平局让「会新增」胜出
|
||||
{3, 1, 1, diffBoth},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := dominantKind(c.both, c.gain, c.lost); got != c.want {
|
||||
t.Errorf("dominantKind(%d,%d,%d)=%d,期望 %d", c.both, c.gain, c.lost, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockDiffCounts(t *testing.T) {
|
||||
both, gain, lost := blockDiffCounts(bmOf([2]int{0, 0}, [2]int{1, 0}), bmOf([2]int{0, 0}, [2]int{2, 0}))
|
||||
if both != 1 || gain != 1 || lost != 1 {
|
||||
t.Errorf("一块里应各有一格:both=%d gain=%d lost=%d", both, gain, lost)
|
||||
}
|
||||
both, gain, lost = blockDiffCounts(nil, bmOf([2]int{5, 5}))
|
||||
if both != 0 || gain != 1 || lost != 0 {
|
||||
t.Errorf("只有快照有该块:both=%d gain=%d lost=%d", both, gain, lost)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user