Files
astro/doc/manual/map-geojson.md
T
b612 16c62a97d5 feat: 完善时标与天象几何计算并扩展输出接口
- 新增时标、ΔT 模型、质心时间与 UT1 支持
- 改进日月食、月掩、行星事件及路径边界计算
- 完善恒星三维自行与动态距离传播
- 扩展 SVG、GeoJSON、KML 输出与底层距离换算工具
- 整理中英文手册、示例资源及回归测试
2026-09-23 18:55:12 +08:00

25 KiB
Raw Permalink Blame History

天象地图、GeoJSON 与 KML

English | 返回 README

本手册的完整示例以仓库根目录为工作目录执行,生成的图片写入 doc/img/。

目录

导出日食 GeoJSON

package main

import (
	"fmt"
	"log"
	"time"

	"b612.me/astro/eclipse"
	"b612.me/astro/geojson"
)

func main() {
	cst := time.FixedZone("CST", 8*3600)
	date := time.Date(2009, 7, 22, 0, 0, 0, 0, cst)
	partial, ok := eclipse.SolarEclipsePartialFootprints(date,
		eclipse.SolarEclipsePartialFootprintOptions{Step: 10 * time.Minute, BoundaryPoints: 180})
	if !ok {
		log.Fatal("no solar eclipse")
	}
	path, ok := eclipse.SolarEclipseCentralPath(date,
		eclipse.SolarEclipsePathOptions{Step: time.Minute, TargetSpacingKM: 20})
	var centralPath *eclipse.SolarEclipsePath
	if ok {
		centralPath = &path
	}
	data, err := geojson.MarshalSolarEclipseWithTimeMarkers(partial, centralPath,
		geojson.TimeMarkerOptions{Step: 30 * time.Minute, Location: cst})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(data))
}

偏食可以没有中心路径,因此 centralPath 允许为 nil。本例把 GeoJSON 写到标准输出,可重定向到文件;SVG 与 KML 用法见后文。

API 参考

SVG 片段使用导入别名 eclipsesvg "b612.me/astro/eclipse/svg";月掩图使用 moonsvg "b612.me/astro/moon/svg"。日期和时区沿用首例。

名称 用途 备注
eclipsesvg.EclipseMapProjectionAuto / ...Equirectangular / ...NorthPolar / ...SouthPolar / ...Orthographic 日月食地图投影 零值即自动
moonsvg.MapProjectionAuto / ...Equirectangular / ...NorthPolar / ...SouthPolar / ...Orthographic 月掩地图投影 同上
SolarEclipseMapSVG / LunarEclipseMapSVG 日食、月食全球图 返回 (string, bool)
StarOccultationPathSVG / PlanetOccultationPathSVG 月掩全球掩带图 返回 (string, error)
MarshalSolarEclipse / MarshalSolarEclipseWithTimeMarkers 日食 GeoJSON 无/带时间标记
MarshalLunarEclipse / MarshalLunarEclipseWithTimeMarkers / MarshalLunarEclipseWithOptions 月食 GeoJSON 同上
MarshalStarOccultation / MarshalPlanetOccultation(及 ...WithTimeMarkers) 月掩 GeoJSON 同上
NewSolarEclipseShadowSolver / MarshalSolarEclipseShadowInstant 单时刻足迹及其 GeoJSON 拖动时间轴用
TimeMarkerOptions 时间标记 Step、Location、TimeScale Step 零值 30 分钟,最多 1440 个
astro.TimeScaleUT1 / astro.DUT1 UT1 口径与 DUT1 差值 UT1 时 Location 必须为 UTC
kml.FromGeoJSON 把 GeoJSON 转成 KML 2.2 只依赖标准库;按 role 分层并给默认调色板

常用场景

给事件选投影

for _, spec := range []struct {
	name string
	p    eclipsesvg.EclipseMapProjection
}{
	{"equirectangular", eclipsesvg.EclipseMapProjectionEquirectangular},
	{"north-polar", eclipsesvg.EclipseMapProjectionNorthPolar},
	{"south-polar", eclipsesvg.EclipseMapProjectionSouthPolar},
	{"orthographic", eclipsesvg.EclipseMapProjectionOrthographic},
} {
	svg, ok := eclipsesvg.SolarEclipseMapSVG(date, eclipsesvg.SolarEclipseMapSVGOptions{
		Width: 1200, Height: 800, Location: cst, Projection: spec.p,
	})
	fmt.Println(spec.name, ok, len(svg))
}
equirectangular true 265827
north-polar true 181602
south-polar true 91902
orthographic true 537001

投影只影响 SVG 表达、不改变底层 WGS84 地理结果;Auto(零值)按事件自动选极图,需要固定版式时才显式指定。正射球面视点取食甚点、只画朝向视点的半球,并切换成 NASA 摆法版式——代价与底图反解过程见地图投影。

导出 GeoJSON 与时间标记

data, err := geojson.MarshalSolarEclipseWithTimeMarkers(partial, centralPath,
	geojson.TimeMarkerOptions{Step: 30 * time.Minute, Location: cst})
fmt.Println(err, json.Valid(data), len(data))
<nil> true 426253
  • WithTimeMarkers 会追加 role=time-marker 的 Point 要素:label 按 Location 本地化显示,time 始终是 UTC RFC 3339。
  • Step 零值为 30 分钟,正值至少 1 分钟,单次导出最多 1440 个标记;不需要标记就用不带后缀的 MarshalSolarEclipse。
  • 月食与月掩有对称入口(MarshalLunarEclipse*、MarshalStarOccultation*、MarshalPlanetOccultation*);GeoJSON 不携带底图、边界、样式或投影,Web Mercator 与瓦片选择由应用决定。

时标声明与 UT1

fmt.Println(astro.DUT1(date)) // UT1−UTC,单位秒
0.23

出图默认按 UTC 口径并在图上或图注声明;TimeScale: astro.TimeScaleUT1 改成 UT1 读数并在图里写出 DUT1 = UT1−UTC = +0.23 s,此时 Location 必须是 UTC。GeoJSON 的对应成员是 time_scale(UTC 口径省略,UT1 口径写 "UT1"),完整约定见时标声明。

单时刻足迹与图层词表

solver := eclipse.NewSolarEclipseShadowSolver(eclipse.SolarEclipseShadowSolverOptions{})
instant, ok := solver.ShadowAt(date)
shadow, err := geojson.MarshalSolarEclipseShadowInstant(instant)
fmt.Println(ok, err, json.Valid(shadow), len(shadow))
true <nil> true 4217
  • 单时刻接口只算"这一瞬间的本影/半影足迹"与站心日月几何,不产生可见带、食分线、升落边界或南北界;本影不在地球上时返回空值而不是错误。
  • 插值前先比 interp_signature:只有相同的相邻时刻才适合按顶点插值,closed 翻转、段数/顶点数变化、空↔非空(U1/U4 附近)都必须改取精确几何。
  • 可降级图层用 data-source 标注实际几何来源,取值词表见地图投影。

地图投影

日食、月食与月掩的 SVG 共用同一套投影:等经纬、北极方位等距、南极方位等距与正射球面。投影只影响 SVG 表达,不改变底层 WGS84 地理结果;日食与月掩的自动投影(零值 ...Auto)会在适合时选择极图,月食默认使用等经纬投影。

投影 常量(日食/月食 · 月掩) 适用场景 画布建议
自动 EclipseMapProjectionAuto · MapProjectionAuto 默认;按事件自动选极图 1200×800
等经纬 ...Equirectangular 跨反经线的长食带或掩带 1200×800、1414×1000
北极/南极方位等距 ...NorthPolar / ...SouthPolar 事件整体落在高纬 1200×800、1000×1414
正射球面 ...Orthographic NASA 版式的半球图,视点取事件中心 1000×1414

EclipseMapProjectionOrthographic / MapProjectionOrthographic 以食甚点(月掩取事件中心)为视点,只显示朝向视点的半球。该投影使用 NASA 风格的居中球面版式,建议画布为 1000×1414。

同一事件批量出四种投影:

date := time.Date(2009, 7, 22, 12, 0, 0, 0, cst)
for _, spec := range []struct {
	name string
	p    eclipsesvg.EclipseMapProjection
}{
	{"equirectangular", eclipsesvg.EclipseMapProjectionEquirectangular},
	{"north-polar", eclipsesvg.EclipseMapProjectionNorthPolar},
	{"south-polar", eclipsesvg.EclipseMapProjectionSouthPolar},
	{"orthographic", eclipsesvg.EclipseMapProjectionOrthographic},
} {
	options := eclipsesvg.SolarEclipseMapSVGOptions{
		Width: 1200, Height: 800, Location: cst, Projection: spec.p,
	}
	svg, ok := eclipsesvg.SolarEclipseMapSVG(date, options)
	if !ok {
		continue
	}
	_ = os.WriteFile("solar-eclipse-"+spec.name+".svg", []byte(svg), 0o644)
}

各族的选项、图层开关与带图示例见日食与月食手册与月掩手册;GeoJSON 侧只携带地理结果,投影由应用自行选择。

可降级的图层用 data-source 标注实际几何来源,取值词表见 eclipse/svg 包注释:partial-band-union、sampled-footprint-sweep、partial-band-contours、rise-set-phase-lines、magnitude-contours、greatest-time-isochrones、besselian-critical-envelope、paired-limit-chords、sampled-open-sweep、central-path-limits、penumbral-outlines、central-shadow-outlines、p1-p4-visibility-regions、p1-p4-horizon-boundaries。

时标声明

图内时刻的口径由 TimeScale 选项决定,日食全球图、月食全球图、月食详细版式与月掩三族图都会在图上或图注里写明:

  • 默认(astro.TimeScaleUTC,零值):写 图中时刻为 UTC;展示时区不是 UTC 时写 图中时刻为 UTC(显示时区 CST,UTC+08:00),把时标与展示时区分开声明。
  • astro.TimeScaleUT1:写 图中时刻为 UT1(世界时),DUT1 = UT1−UTC = +0.05 s。,差值随事件日期变化;此时 Location 必须是 UTC,否则渲染返回 false(月掩侧直接返回错误)。

GeoJSON 侧的对应成员是 time_scale:UTC 口径省略该成员,UT1 口径写 "UT1",表示所有 time 字符串与 HH:MM 标注都是 UT1 读数(RFC 3339 的 Z 后缀严格说不等于 UT1)。切时标不改掩带、足迹、地平线与等值线几何,只有写出的时刻文字换成 UT1 读数;时间标记按输出时标的整点取点(整点读数本身就是另一个物理时刻),位置随所标时刻移动。

GeoJSON

geojson 接收已经计算好的日食、月食或月掩结果,返回 []byte。这段字节是完整的 UTF-8 RFC 7946 FeatureCollection JSON,不是图片,也不是压缩数据,可以直接写入 .geojson、交给 encoding/json,或发送给前端地图组件。

package main

import (
	"encoding/json"
	"fmt"
	"time"

	"b612.me/astro/eclipse"
	"b612.me/astro/geojson"
)

func main() {
	date := time.Date(2024, 4, 8, 0, 0, 0, 0, time.UTC)
	partial, ok := eclipse.SolarEclipsePartialFootprints(
		date,
		eclipse.SolarEclipsePartialFootprintOptions{
			Step: 10 * time.Minute, BoundaryPoints: 180,
		},
	)
	if !ok {
		return
	}
	central, hasCentral := eclipse.SolarEclipseCentralPath(
		date,
		eclipse.SolarEclipsePathOptions{Step: time.Minute, TargetSpacingKM: 20},
	)
	var centralPath *eclipse.SolarEclipsePath
	if hasCentral {
		centralPath = &central
	}

	data, err := geojson.MarshalSolarEclipseWithTimeMarkers(
		partial, centralPath,
		geojson.TimeMarkerOptions{
			Step:     30 * time.Minute,
			Location: time.FixedZone("CST", 8*3600),
		},
	)
	fmt.Println(err, json.Valid(data))
}

对应的无时间标记和带时间标记入口包括:

  • MarshalSolarEclipse / MarshalSolarEclipseWithTimeMarkers
  • MarshalLunarEclipse / MarshalLunarEclipseWithTimeMarkers
  • MarshalLunarEclipseWithOptions:用 LunarEclipseOptions 一次给出时间标记、SkipRoles 与时间包络的采样档位。SkipRoles 可跳过时间包络和仅见半影带;跳过两个时间包络时不会执行包络采样。EnvelopeSweepSamples 默认 48,限制在 [2, 192];EnvelopeLongitudePoints 默认 max(360, boundaryPoints),限制在 [12, 720]。
  • MarshalStarOccultation / MarshalStarOccultationWithTimeMarkers
  • MarshalPlanetOccultation / MarshalPlanetOccultationWithTimeMarkers
  • MarshalSolarEclipseWithOptions:用 SolarEclipseOptions 一次给出时间标记与 SkipRoles,等价于上面的日食入口再加图层裁剪。SkipRoles 里最常用的是 partial-footprint(瞬时半影轮廓);partial-band 是日食带边缘(食分 0 界限),通常要留着。

图层筛选

SolarEclipseOptions.SkipRoles 按 role 排除输出要素,零值保留全部图层。可通过 MarshalSolarEclipseWithOptions 同时指定时间标记与筛选条件。

筛选发生在编码阶段,几何仍按完整采样计算。因此,跳过 partial-footprint 会去掉逐时刻的半影足迹,但不会降低总偏食区边缘 partial-band 的精度,也不影响中心带、食分线和升落边界。全部要素被排除时返回错误。

坐标、时间与反经线

坐标为 WGS84 [经度, 纬度],单位度。跨反经线的线和面会拆分,并在接缝两侧补出同一个交点。触及极点的环用 [±180, ±90] 两个坐标表示同一极点。

闭合环含有用于闭合的 ±180° 接缝段。填充时需要这些边;描绘真实边界时应跳过接缝。band-outline、total-band-outline 等闭合轮廓线也需按此规则处理。

带时间路径的 times 与各段坐标逐点对应。WithTimeMarkers 额外加入 role=time-marker 的 Point 要素:label 用于显示,默认 time 为 UTC RFC 3339;显式选择 UT1 时由 time_scale 区分。详见时标。

TimeMarkerOptions 字段 行为
Step 零值为 30 分钟,正值至少 1 分钟;一次导出最多 1440 个标记
Location 标签的显示时区,nil 使用 UTC
TimeScale 默认 UTC;UT1 要求 Location 为 nil 或 time.UTC

GeoJSON 不携带底图、样式或投影,应用可自行选择瓦片、Web Mercator 或极区投影。

按时刻计算日食阴影

交互地图按时间查询阴影时,可复用 eclipse.NewSolarEclipseShadowSolver 返回的求解器:

方法 输入与结果
ShadowAt(date) 民用 time.Time,返回瞬时全球阴影足迹
ShadowAtJDE(jdeTT) TT 儒略日,返回相同类型的足迹
StationStateAt / StationStateAtJDE 指定时刻与站点的食分、遮蔽率、站心角距、视半径、太阳高度/方位与全食/环食状态
ShadowBetween(start, end, step) 按步长返回足迹序列,无阴影的时刻保留空条目
StationStatesBetween 按时间采样站点状态

默认计算本影或反本影;Kind: SolarEclipseShadowPenumbra 改为半影。单时刻接口不计算整场事件的可见带、食分线、南北限或中心线;阴影不在地球上时返回空结果。

geojson.MarshalSolarEclipseShadowInstant(instant) 将结果编码为 GeoJSON。输出属性包括 time、source_boundary_closed、geometry_role、closure、delta_t_seconds、model 与 interp_signature。没有阴影时返回空 FeatureCollection。

阴影 区域 role 物理边界 role
本影/反本影 central-shadow-footprint central-shadow-boundary
半影 partial-footprint partial-footprint-boundary

单时刻半影与整场偏食采样使用相同的默认边界参数(96 点、200 km 加密),可以对照同一时刻的结果。已有单机测量中,96 点瞬时足迹约 64 µs,站点瞬时状态约 20 µs;这些数据只用于估算成本,首次查询和批量查询会受缓存状态影响。

地平线闭合与插值

central-shadow-footprint 只输出 Polygon 或 MultiPolygon。被地平线切断时,物理边界延伸到两个地平擦地点,再沿地平弧闭合为覆盖区域;此时 source_boundary_closed=false,closure 用 kind、time、subsolar 描述闭合弧。

只画真实阴影边缘时使用 central-shadow-boundary;需要填色时使用 footprint。阴影在 U1/U4 收缩为空时不输出该要素,不会退化成折线。source_boundary_closed=true 表示物理边界本身已经闭合。

采样的半影足迹也带这些属性。足迹是瞬时覆盖区域,静态掩带是整场事件的包络,两者不能互相替代。

相邻帧可先比较 interp_signature,例如 umbra-closed-seg1-pt97。只有签名一致、分段数与顶点数对应时才适合按顶点插值;这不代表插值具有严格误差上界。闭合状态改变、反经线分段改变或空/非空切换时,应查询精确几何。

移动距离也会随事件阶段变化:已有两分钟采样的对照中,足迹质心在中段移动约 78–232 km,接触附近可达约 520 km。因此不能仅凭固定时间步长判断动画误差。

ΔT 与地面位置

求解器的 DeltaTSeconds > 0 可为该句柄指定 ΔT;小于等于 0 时采用进程级模型。结果回传实际使用的值。

同一 TT 下,改变 ΔT 会改变地球自转相位,而不改变日月在空间中的相对几何。地面经向位移的近似量级为 0.4651 × |ΔΔT| × cos(纬度) 千米,函数 basic.DeltaTGroundShiftKM 可用于换算。库不提供 ΔT 不确定度模型,误差输入需由调用方给出。

月掩瞬时足迹

moon.StarOccultationFootprintAt / moon.PlanetOccultationFootprintsAt 的结果可传给 geojson.MarshalStarOccultationFootprint / MarshalPlanetOccultationFootprints。

它们同样输出 delta_t_seconds、source_boundary_closed、geometry_role 和 interp_signature。月球地平线闭合采用 closure.kind=target-horizon、body=moon 与 sublunar 月下点。月掩计算沿用进程级 ΔT,并在结果中报告实际值。

先查事件再计算几何

只需要事件列表时,可先用 eclipse.SolarEclipseCandidates(start, end, options) 获取食甚时刻、食型、中心食类型、食分、伽马和可选沙罗信息;这个结果不包含地理几何。

固定地点的中心食搜索使用 SearchLocalCentralSolarEclipse,选项包括 Kind、MaxYears、Backward、Geometric、Model,返回 (info, status)。status.Exhausted 表示已用尽搜索范围。

MaxYears<=0 使用默认搜索预算(6000 次候选步进,约 992 年)。找到事件后再计算路径、足迹或 SVG,可以避免为不需要的事件生成地图数据。

KML

kml.FromGeoJSON(data []byte, options kml.Options) ([]byte, error) 把 GeoJSON FeatureCollection 转成 KML 2.2。输入可来自本库,也可以是第三方文件;转换器读取已有几何和时间属性,不计算新的星历或动画帧。

转换文件

下面的程序把 eclipse.geojson 转成 eclipse.kml,可在 Google Earth 中打开:

package main

import (
	"log"
	"os"

	"b612.me/astro/kml"
)

func main() {
	data, err := os.ReadFile("eclipse.geojson")
	if err != nil {
		log.Fatal(err)
	}
	result, err := kml.FromGeoJSON(data, kml.Options{
		Name: "2009-07-22 日食",
	})
	if err != nil {
		log.Fatal(err)
	}
	if err := os.WriteFile("eclipse.kml", result, 0644); err != nil {
		log.Fatal(err)
	}
}

Options

字段 零值或默认行为 设置后的作用
Name 按事件类型与最早时刻推导文档名 指定 Document/name
Language "zh" "en" 使用英文图层名;未收录的角色保留原始 role
Styles 内置配色 以 role 或 event/role 为键覆盖样式,后者优先
NoLookAt 自动设置取景 true 不写 Document/LookAt
SkipRoles 保留所有角色 按 role 删除整层,包括几何、样式和取景贡献
FillContext 只填充高亮中心带和掩星带 true 为其他面图层添加浅灰半透明填充
NoTimes 写入输入中存在的时间 true 不输出时间元素,生成静态叠加

图层与样式

要素按 event 和 role 分组到 Folder。同一集合含多个事件类型时,图层名带事件前缀;第三方 event 与 role 也可使用相同的样式覆盖规则。

图层 role 默认样式
日食中心带与本影 central-band、central-shadow、central-shadow-footprint、central-shadow-sweep、total-footprint 红色;面填充约 35% 不透明度
中心线 center-line 黑色,3 px
日食食甚等时线 greatest-time-line 绿色
食分线 magnitude-line、magnitude-one-envelope 黄色
掩星全掩与偏掩带 total-band、partial-band、total-band-outline、occultation-band 黄色,带半透明填充
升落可见边界、月食时间包络、日食偏食带边缘 visibility-boundary、p1-horizon、p4-horizon、visible-at-p1、visible-at-p4、visible-during-eclipse、visible-throughout-eclipse、日食的 partial-band 橙色
仅见半影的月出/月落带 penumbra-moonrise、penumbra-moonset 月出蓝紫、月落紫红,带半透明填充
其他限界、轮廓、足迹与时间标记 其他 role 灰色,面默认只画轮廓

Style 的零值字段沿用默认样式:

字段 含义
LineColor 线色,KML aabbggrr 十六进制
FillColor 面填充色;点和线忽略此项
LineWidth 像素;小于等于 0 时使用默认线宽
NoFill 强制不填充,优先于 FillColor 与默认配色

KML 颜色顺序是透明通道、蓝、绿、红。例如 ff0000ff 为不透明红,590000ff 为约 35% 不透明度的红;它与 CSS rrggbb 的顺序不同。

options := kml.Options{
    Language: "zh",
    Styles: map[string]kml.Style{
        "center-line": {LineColor: kml.ColorBlack, LineWidth: 4},
        "solar-eclipse/central-band": {FillColor: "590000ff"},
        "partial-footprint": {NoFill: true},
    },
}
result, err := kml.FromGeoJSON(data, options)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(result))

无填充的面会转成轮廓线。有填充的面与描边分别表示,反经线拆分产生的接缝不作为真实边界绘制。这样既可保持面闭合,也可避免沿 ±180° 经线出现贯穿地图的描边。

时间轴与静态叠加

GeoJSON 时间数据 KML 输出
单个 time 属性 包含该要素全部子几何的 Placemark 带一个 TimeStamp
MultiLineString 的 times 按线段拆成 Placemark,各段取首个时间作为 TimeStamp
至少一个有效时间戳 Document 带覆盖最早至最晚时间戳的 TimeSpan
time_scale: "UT1" 先按当前时标模型换回 UTC,再写 <when>
NoTimes: true 不输出 TimeStamp 或 TimeSpan

时间戳保留源数据的小数秒。要素含 label 时用它作名称;自动生成的名称只显示到秒。UT1 数据的原 time_scale 保留在属性中;转换时应与生成 GeoJSON 时使用同一 ΔT 模型。

时间轴中的帧来自输入数据。times 不会让折线上的每个顶点自动变成独立动画帧;需要本影或半影逐时刻变化时,应先用 GeoJSON 侧的采样选项生成这些要素。

Google Earth 会按所选时间窗口隐藏带时间戳的要素。查看静态全路径时可设置 NoTimes: true;播放时则将时间窗口移到事件日期,并调整可见时间段的宽度。

控制文件大小和取景

半影足迹通常覆盖很大区域。密集采样、大量顶点与半透明面重叠都会增加客户端绘制开销;可增大采样步长,或按用途去掉部分图层。

只需要总偏食区边缘和中心食路径时,可跳过 partial-footprint,保留 partial-band:

result, err := kml.FromGeoJSON(data, kml.Options{
    SkipRoles: []string{"partial-footprint"},
    NoTimes: true,
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(result))

若在生成 GeoJSON 时已经确定不需要某层,可通过 geojson.MarshalSolarEclipseWithOptions 的 SkipRoles 先排除,减少中间数据。KML 的 SkipRoles 适用于已有文件。

自动取景优先使用中心线、中心带、限界和本影等路径图层,缺少这些图层时再使用全部要素。包络考虑跨反经线情况,LookAt/range 的单位为米,下限 200 km。需要客户端自行定位时设 NoLookAt: true。

属性与输入校验

通过 SkipRoles 筛选后,所有保留要素都具有且值相同的属性才提升到 Document/ExtendedData。其余属性留在各自 Placemark,嵌套对象也会保留;times 已转换成时间戳,不重复写入属性。

坐标至少含经纬度两项。经度超出 ±180° 时回绕,原本的 +180° 与 −180° 保持不变;纬度必须在 ±90° 内。额外的高度分量被忽略,输出采用 clampToGround。

多边形环会补闭合,并调整为外环逆时针、内环顺时针。支持 Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon 和 GeometryCollection。

以下情况返回错误:JSON 或几何类型无效、坐标非有限或纬度越界、时间数组与线段结构不匹配、过滤后没有剩余要素,或所有要素均没有可绘制几何。两个相同坐标组成的单点路径片段会被跳过。输入本来就是空 FeatureCollection 时,返回合法的空 Document。