DJI Terra already emits standard XYZ z/x/y trees, so a good capture does not need slicing again. scripts/import-tiles.ps1 validates the source, refuses a tile-extension mismatch, copies it into the scan root, writes the manifest and triggers a scan. The extension check is the point: detectTileFormat picks whichever tile it happens to see first and the published URL template uses that single extension, so a layer mixing .png and .webp silently 404s half its tiles. GUIDE.md gains the mixed workflow: import for the captures that are good as-is, slice the GeoTIFF when the layer needs to be rebuildable as a mosaic.
138 lines
5.3 KiB
PowerShell
138 lines
5.3 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
把一份已切好的 z/x/y 瓦片目录(例如大疆智图 terra_dom\tile)并入一个图层。
|
|
|
|
.DESCRIPTION
|
|
做四件事:校验源目录、检查扩展名是否与现有图层冲突、拷贝进扫描根、
|
|
写好 manifest.json,最后触发一次扫描。
|
|
|
|
同一个图层只能有一种瓦片扩展名。服务发布时只会采用其中一个扩展名,
|
|
若目录里混了 .png 和 .webp,另一种会全部 404 且不报错,所以这里直接拦住。
|
|
|
|
.EXAMPLE
|
|
.\scripts\import-tiles.ps1 -Source "D:\Nie_WorkSpace\煤矿拍摄区域\lidars\terra_dom\tile" `
|
|
-Code "coal-mine-dom" -Name "煤矿拍摄区域 DOM"
|
|
|
|
.EXAMPLE
|
|
# 把第二批影像并进同一个图层(累加)
|
|
.\scripts\import-tiles.ps1 -Source "D:\Nie_WorkSpace\另一个项目\terra_dom\tile" `
|
|
-Code "uav-2026" -Name "2026无人机影像"
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$Source,
|
|
[Parameter(Mandatory = $true)][string]$Code,
|
|
[string]$Name = '',
|
|
[string]$ApiBase = 'http://127.0.0.1:8910',
|
|
[switch]$SkipScan
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Get-TileFormat {
|
|
param([string]$Root)
|
|
$zoom = Get-ChildItem -LiteralPath $Root -Directory -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.Name -match '^\d+$' } | Sort-Object { [int]$_.Name } | Select-Object -First 1
|
|
if (-not $zoom) { return $null }
|
|
foreach ($x in (Get-ChildItem -LiteralPath $zoom.FullName -Directory -ErrorAction SilentlyContinue)) {
|
|
$file = Get-ChildItem -LiteralPath $x.FullName -File -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($file) { return $file.Extension.TrimStart('.').ToLower() }
|
|
}
|
|
return $null
|
|
}
|
|
|
|
function Get-ZoomRange {
|
|
param([string]$Root)
|
|
$zooms = Get-ChildItem -LiteralPath $Root -Directory -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.Name -match '^\d+$' } | ForEach-Object { [int]$_.Name } | Sort-Object
|
|
if (-not $zooms) { return $null }
|
|
return @($zooms[0], $zooms[-1])
|
|
}
|
|
|
|
$Root = Split-Path -Parent $PSScriptRoot
|
|
$TileRoot = Join-Path $Root 'data\tiles'
|
|
$Dest = Join-Path $TileRoot $Code
|
|
|
|
if (-not (Test-Path -LiteralPath $Source)) { throw "源目录不存在:$Source" }
|
|
$Source = (Resolve-Path -LiteralPath $Source).Path
|
|
if (-not (Test-Path -LiteralPath $TileRoot)) { throw "扫描根目录不存在:$TileRoot" }
|
|
|
|
Write-Host "源目录 : $Source"
|
|
Write-Host "目标 : $Dest"
|
|
|
|
# 1) 源必须是 z/x/y 目录树
|
|
$srcZooms = Get-ZoomRange $Source
|
|
if (-not $srcZooms) {
|
|
throw "源目录下没有数字命名的级别目录(形如 12/ 13/),不像是 z/x/y 切片树。"
|
|
}
|
|
Write-Host ("源级别 : z{0}-{1}" -f $srcZooms[0], $srcZooms[1])
|
|
|
|
# 2) 探测扩展名,并和现有图层比对
|
|
$srcFormat = Get-TileFormat $Source
|
|
if (-not $srcFormat) { throw "在源目录里找不到瓦片文件:$Source" }
|
|
|
|
$existingFormat = $null
|
|
if (Test-Path -LiteralPath $Dest) { $existingFormat = Get-TileFormat $Dest }
|
|
|
|
if ($existingFormat -and $existingFormat -ne $srcFormat) {
|
|
throw @"
|
|
格式冲突,已中止。
|
|
|
|
图层 $Code 现有瓦片 : .$existingFormat
|
|
本次要导入的瓦片 : .$srcFormat
|
|
|
|
同一个图层只能有一种扩展名:服务发布 URL 时只会采用其中一个,
|
|
另一种会全部 404 且不会报错。请改用同格式的源,或换一个 -Code。
|
|
"@
|
|
}
|
|
Write-Host ("瓦片格式: .{0}{1}" -f $srcFormat, $(if ($existingFormat) { "(与现有图层一致)" } else { "" }))
|
|
|
|
# 3) 拷贝(robocopy 0-7 都算成功)
|
|
Write-Host "`n开始拷贝……"
|
|
robocopy $Source $Dest /E /NFL /NDL /NP /R:1 /W:1 /MT:8 | Out-Null
|
|
$rc = $LASTEXITCODE
|
|
if ($rc -ge 8) { throw "robocopy 失败,退出码 $rc" }
|
|
|
|
# 4) 写 manifest(保留已有显示名,除非显式传了 -Name)
|
|
$manifestPath = Join-Path $Dest 'manifest.json'
|
|
$oldName = ''
|
|
$isDefault = $true
|
|
if (Test-Path -LiteralPath $manifestPath) {
|
|
try {
|
|
$old = Get-Content -Raw -LiteralPath $manifestPath | ConvertFrom-Json
|
|
$oldName = $old.name
|
|
if ($null -ne $old.is_default) { $isDefault = [bool]$old.is_default }
|
|
} catch { }
|
|
}
|
|
if (-not $Name) { $Name = if ($oldName) { $oldName } else { $Code } }
|
|
|
|
$combined = Get-ZoomRange $Dest
|
|
$manifest = [ordered]@{
|
|
code = $Code
|
|
name = $Name
|
|
type = 'xyz'
|
|
description = '由 import-tiles.ps1 导入的已切好瓦片'
|
|
version = 'current'
|
|
status = 'ready'
|
|
tile_format = $srcFormat
|
|
tile_scheme = 'xyz'
|
|
root_path = '.'
|
|
is_default = $isDefault
|
|
}
|
|
($manifest | ConvertTo-Json -Depth 5) | Set-Content -LiteralPath $manifestPath -Encoding UTF8
|
|
Write-Host ("manifest: code={0} name={1} z{2}-{3} .{4}" -f $Code, $Name, $combined[0], $combined[1], $srcFormat)
|
|
|
|
# 5) 触发扫描(管理接口只接受本机请求,这里走 127.0.0.1)
|
|
if ($SkipScan) {
|
|
Write-Host "`n已跳过扫描(-SkipScan)。记得在运维台点一次「立即扫描」。"
|
|
exit 0
|
|
}
|
|
|
|
Write-Host "`n触发扫描……"
|
|
try {
|
|
$result = curl.exe -s -X POST "$ApiBase/api/v1/admin/scan-sources/local-basemaps/run"
|
|
Write-Host $result
|
|
} catch {
|
|
Write-Warning "自动扫描失败($($_.Exception.Message))。服务未启动时属正常,请稍后在运维台点「立即扫描」。"
|
|
}
|
|
|
|
Write-Host "`n完成。图层 $Code 现在包含 z$($combined[0])-$($combined[1]) 的 .$srcFormat 瓦片。" |