diff --git a/README.md b/README.md index 4a23021..c10ee1d 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,6 @@ 百度地图api接口 https://api.map.baidu.com/customimage/tile?&x=瓦片x&y=瓦片y&z=缩放层级&customid=地图风格 -`getid.exe` 采用golang编写,用于百度BD09坐标系转墨卡托平面坐标系转百度瓦片ID - -`getpic.bat` 负责单个进程下载百度瓦片图并校验是否下载成功 - -`多线程百度地图瓦片下载.bat` 负责调用`getid.exe`计算瓦片ID,提交下载任务给`getpic.bat`,并且负责管理curl进程(保护大量调用curl运行而不卡死系统) +交互式菜单,傻瓜化操作! 仅供学习与参考,请勿用于商业用途! diff --git a/getid.exe b/getid.exe deleted file mode 100644 index 7288a1e..0000000 Binary files a/getid.exe and /dev/null differ diff --git a/getpic.bat b/getpic.bat deleted file mode 100644 index e3bdca7..0000000 --- a/getpic.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -setlocal enabledelayedexpansion -cd "%~dp0" -:loop -curl "https://api.map.baidu.com/customimage/tile?&x=%1&y=%2&z=%3&customid=%4" -s -o map/%3/%1/%2.png -if not exist "map/%3/%1/%2.png" goto loop -exit \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..4e35c2e --- /dev/null +++ b/main.go @@ -0,0 +1,260 @@ +package main + +import ( + "fmt" + "io" + "math" + "net/http" + "os" + "path/filepath" + "strconv" + "sync" + "time" +) + +var ( + style string + a float64 + b float64 + c float64 + d float64 + min int + max int + concurrentLimit int + array1 = []float64{75, 60, 45, 30, 15, 0} + array2 = [][]float64{ + {-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5}, + {0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5}, + {0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5}, + {0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5}, + {-0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5}, + {-0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45}, + } +) + +type LatLngPoint struct { + Lat, Lng float64 +} + +type PointF struct { + X, Y float64 +} + +func init() { + // 默认值 + style = "normal" + a = 116.199599 + b = 40.033261 + c = 116.537074 + d = 39.830986 + min = 3 + max = 19 + concurrentLimit = 50 + + // 用户交互式输入 + fmt.Println("地图风格") + fmt.Println("常规 normal") + fmt.Println("清新蓝 light") + fmt.Println("黑夜 dark") + fmt.Println("红色警戒 redalert") + fmt.Println("精简 googlelite") + fmt.Println("自然绿 grassgreen") + fmt.Println("午夜蓝 midnight") + fmt.Println("浪漫粉 pink") + fmt.Println("青春绿 darkgreen") + fmt.Println("清新蓝绿 bluish") + fmt.Println("高端灰 grayscale") + fmt.Println("强边界 hardedge") + + fmt.Printf("地图风格 (默认 %s): ", style) + styleInput := "" + fmt.Scanln(&styleInput) + if styleInput != "" { + style = styleInput + } + + fmt.Printf("百度地图左上角经度 (默认 %.10f): ", a) + aInput := "" + fmt.Scanln(&aInput) + if aInput != "" { + a, _ = strconv.ParseFloat(aInput, 64) + } + + fmt.Printf("百度地图左上角纬度 (默认 %.10f): ", b) + bInput := "" + fmt.Scanln(&bInput) + if bInput != "" { + b, _ = strconv.ParseFloat(bInput, 64) + } + + fmt.Printf("百度地图右下角经度 (默认 %.10f): ", c) + cInput := "" + fmt.Scanln(&cInput) + if cInput != "" { + c, _ = strconv.ParseFloat(cInput, 64) + } + + fmt.Printf("百度地图右下角纬度 (默认 %.10f): ", d) + dInput := "" + fmt.Scanln(&dInput) + if dInput != "" { + d, _ = strconv.ParseFloat(dInput, 64) + } + + fmt.Printf("最小层级 (默认 %d): ", min) + minInput := "" + fmt.Scanln(&minInput) + if minInput != "" { + min, _ = strconv.Atoi(minInput) + } + + fmt.Printf("最大层级 (默认 %d): ", max) + maxInput := "" + fmt.Scanln(&maxInput) + if maxInput != "" { + max, _ = strconv.Atoi(maxInput) + } + + fmt.Printf("最大并发请求数量 (默认 %d): ", concurrentLimit) + concurrentInput := "" + fmt.Scanln(&concurrentInput) + if concurrentInput != "" { + concurrentLimit, _ = strconv.Atoi(concurrentInput) + } +} + +func main() { + var wg sync.WaitGroup + sem := make(chan struct{}, concurrentLimit) + + for z := min; z <= max; z++ { + x1, y1 := getID(a, b, z) + x2, y2 := getID(c, d, z) + + // 确保 x2 > x1 和 y2 > y1 + if x1 > x2 { + x1, x2 = x2, x1 + } + if y1 > y2 { + y1, y2 = y2, y1 + } + + fmt.Printf("\n缩放级别 %d: 瓦片范围: x 从 %d 到 %d, y 从 %d 到 %d\n", z, x1, x2, y1, y2) + totalTiles := (x2 - x1 + 1) * (y2 - y1 + 1) + fmt.Printf("缩放级别 %d: 瓦片总数: %d\n", z, totalTiles) + + for x := x1; x <= x2; x++ { + for y := y1; y <= y2; y++ { + wg.Add(1) + sem <- struct{}{} + go func(x, y, z int) { + defer wg.Done() + defer func() { <-sem }() + downloadTile(x, y, z) + }(x, y, z) + } + } + } + + wg.Wait() + fmt.Println("下载完成") +} + +func LatLng2Mercator(p LatLngPoint) PointF { + var arr []float64 + if p.Lat > 74 { + p.Lat = 74 + } else if p.Lat < -74 { + p.Lat = -74 + } + + for i, latLimit := range array1 { + if p.Lat >= latLimit { + arr = array2[i] + break + } + } + if arr == nil { + for i := len(array1) - 1; i >= 0; i-- { + if p.Lat <= -array1[i] { + arr = array2[i] + break + } + } + } + + res := Convertor(p.Lng, p.Lat, arr) + return PointF{res[0], res[1]} +} + +func Convertor(x, y float64, param []float64) []float64 { + T := param[0] + param[1]*math.Abs(x) + cC := math.Abs(y) / param[9] + cF := param[2] + param[3]*cC + param[4]*cC*cC + param[5]*cC*cC*cC + param[6]*cC*cC*cC*cC + param[7]*cC*cC*cC*cC*cC + param[8]*cC*cC*cC*cC*cC*cC + T *= sign(x) + cF *= sign(y) + return []float64{T, cF} +} + +func sign(value float64) float64 { + if value < 0 { + return -1 + } + return 1 +} + +func getTileIndices(x, y float64, zoom int) (int, int) { + scale := math.Pow(2, float64(18-zoom)) + pixelX := x / scale + pixelY := y / scale + return int(pixelX) / 256, int(pixelY) / 256 +} + +func getID(lng, lat float64, z int) (int, int) { + mercator := LatLng2Mercator(LatLngPoint{Lat: lat, Lng: lng}) + return getTileIndices(mercator.X, mercator.Y, z) +} + +func downloadTile(x, y, z int) { + url := fmt.Sprintf("https://api.map.baidu.com/customimage/tile?&x=%d&y=%d&z=%d&customid=%s", x, y, z, style) + filePath := fmt.Sprintf("map/%d/%d/%d.png", z, x, y) + + err := os.MkdirAll(filepath.Dir(filePath), 0755) + if err != nil { + fmt.Printf("创建目录失败: %v\n", err) + return + } + + for { + resp, err := http.Get(url) + if err != nil { + fmt.Printf("下载失败: %v\n", err) + time.Sleep(1 * time.Second) + continue + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + fmt.Printf("下载失败, 状态码: %d\n", resp.StatusCode) + time.Sleep(1 * time.Second) + continue + } + + file, err := os.Create(filePath) + if err != nil { + fmt.Printf("创建文件失败: %v\n", err) + return + } + defer file.Close() + + _, err = io.Copy(file, resp.Body) + if err != nil { + fmt.Printf("保存文件失败: %v\n", err) + time.Sleep(1 * time.Second) + continue + } + + fmt.Printf("下载成功: %s\n", filePath) + break + } +} diff --git "a/\345\244\232\347\272\277\347\250\213\347\231\276\345\272\246\345\234\260\345\233\276\347\223\246\347\211\207\344\270\213\350\275\275.bat" "b/\345\244\232\347\272\277\347\250\213\347\231\276\345\272\246\345\234\260\345\233\276\347\223\246\347\211\207\344\270\213\350\275\275.bat" deleted file mode 100644 index cf317c5..0000000 --- "a/\345\244\232\347\272\277\347\250\213\347\231\276\345\272\246\345\234\260\345\233\276\347\223\246\347\211\207\344\270\213\350\275\275.bat" +++ /dev/null @@ -1,90 +0,0 @@ -@echo off -setlocal enabledelayedexpansion -cd "%~dp0" -title ٶȵͼƬ -echo ͼ -echo normal -echo light -echo ҹ dark -echo ɫ redalert -echo googlelite -echo Ȼ grassgreen -echo ҹ midnight -echo pink -echo ഺ darkgreen -echo bluish -echo ߶˻ grayscale -echo ǿ߽ hardedge -set style=midnight -set a=120.86441707191187 -set b=31.87829317767047 -set c=122.28637881960425 -set d=30.68334074991772 -set /a min=3 -set /a max=19 -set /p style=ͼ(Ĭ %style%): -set /p a=ٶȵͼϽǾ(Ĭ %a%): -set /p b=ٶȵͼϽγ(Ĭ %b%): -set /p c=ٶȵͼ½Ǿ(Ĭ %c%): -set /p d=ٶȵͼ½γ(Ĭ %d%): -set /p min=С㼶(Ĭ %min%): -set /p max=㼶(Ĭ %max%): -set /a startH=%time:~0,2% -if %time:~3,1% EQU 0 (set /a startM=%time:~4,1%) else (set /a startM=%time:~3,2%) -if %time:~6,1% EQU 0 (set /a startS=%time:~7,1%) else (set /a startS=%time:~6,2%) -RD /S /Q map -mkdir map -cls -set /a n=0 -set /a m=0 -:start -if !min! LEQ !max! (set /a z=!min!) else (goto end) -mkdir map\!min! -set /a min+=1 -:setx1 -for /f "tokens=1 delims= " %%i in ('getid -x %a% -y %b% -z !z!') do ( -set x1=%%i -mkdir map\!z!\!x1! -) -:sety1 -for /f "tokens=2 delims= " %%i in ('getid -x %a% -y %b% -z !z!') do ( -set y1=%%i -) -:setx2 -for /f "tokens=1 delims= " %%i in ('getid -x %c% -y %d% -z !z!') do ( -set x2=%%i -) -:sety2 -for /f "tokens=2 delims= " %%i in ('getid -x %c% -y %d% -z !z!') do ( -set y2=%%i -) -:loopy -if !y1! GEQ !y2! (start /b getpic !x1! !y2! !z! !style! && set /a n+=1 && set /a y2+=1) else (goto loopx) -set /a m+=1 -if !m! EQU 100 ( -set /a m=0 -:loop -for /f "delims=" %%i in ('tasklist ^| find /c /i "curl.exe"') do ( -set tasklist=%%i -if !tasklist! LEQ 30 (echo %time% ǰcurl!tasklist!) else (echo %time% ǰcurl!tasklist! && goto loop) -) -) else ( -title !n! Ƭ 㼶 !z! Ƭ X=!x1! Ƭ Y=!y2! ͼ !style! -) -goto loopy -:loopx -if !x1! LSS !x2! (set /a x1+=1 && mkdir map\!z!\!x1! && goto sety1) else (goto start) -:end -for /f "delims=" %%i in ('tasklist ^| find /c /i "curl.exe"') do ( -set tasklist=%%i -if !tasklist! EQU 0 (echo curlȫ) else (echo %time% ȴcurlȫ,ǰʣ!tasklist! && goto end) -) -set /a stopH=%time:~0,2% -if %time:~3,1% EQU 0 (set /a stopM=%time:~4,1%) else (set /a stopM=%time:~3,2%) -if %time:~6,1% EQU 0 (set /a stopS=%time:~7,1%) else (set /a stopS=%time:~6,2%) -set /a starttime=%startH%*3600+%startM%*60+%startS% -set /a stoptime=%stopH%*3600+%stopM%*60+%stopS% -if %starttime% GTR %stoptime% (set /a alltime=86400-%starttime%+%stoptime%) else (set /a alltime=%stoptime%-%starttime%) -set /a avg=n/alltime -echo ܼ%n%Ƭͼ,ʱ%alltime%,ƽٶ%avg%/s -pause>nul \ No newline at end of file