044f2f4381
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
83 lines
3.3 KiB
Go
83 lines
3.3 KiB
Go
package geojson
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
eclipsecore "b612.me/astro/eclipse"
|
|
"b612.me/astro/internal/geodata"
|
|
)
|
|
|
|
// MarshalSolarEclipseShadowInstant 单时刻阴影足迹的最小 GeoJSON:只含该时刻的区域与物理边界 / one instant as the smallest useful GeoJSON.
|
|
func (module *Generator) MarshalSolarEclipseShadowInstant(
|
|
instant eclipsecore.SolarEclipseShadowInstant,
|
|
) ([]byte, error) {
|
|
if instant.Empty() {
|
|
return marshalEmptyFeatureCollection()
|
|
}
|
|
curve, err := solarShadowFootprintCurveFromSegments(instant.Boundaries)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("geojson: solar shadow instant at %s: %w", formatTime(instant.Time), err)
|
|
}
|
|
if len(curve) < 2 {
|
|
return marshalEmptyFeatureCollection()
|
|
}
|
|
properties := map[string]interface{}{
|
|
"model": string(instant.Model),
|
|
"delta_t_seconds": instant.DeltaTSeconds,
|
|
"interp_signature": instant.Topology.Signature(),
|
|
}
|
|
regionRole, boundaryRole := solarCentralShadowFootprintRole, solarCentralShadowBoundaryRole
|
|
if instant.Kind == eclipsecore.SolarEclipseShadowPenumbra {
|
|
regionRole, boundaryRole = solarPartialFootprintRole, solarPartialFootprintBoundaryRole
|
|
}
|
|
features := make([]feature, 0, 2)
|
|
regionProperties := cloneProperties(properties)
|
|
regionProperties["time"] = formatTime(instant.Time)
|
|
if instant.Closed {
|
|
// 与整包导出同构:自身闭合的区域不带 geometry_role,也不带 closure。
|
|
regionProperties["source_boundary_closed"] = true
|
|
ring := append([]geodata.GeoPoint(nil), curve...)
|
|
if solarShadowRegionDegenerate(curve, ring) {
|
|
// 首末接触附近区域收缩到零:整条缺省,不退化成线,也不让近零面积的环触发导出错误。
|
|
return marshalEmptyFeatureCollection()
|
|
}
|
|
value, err := multiPolygonGeometry([][]geodata.GeoPoint{ring})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("geojson: solar shadow instant at %s: %w", formatTime(instant.Time), err)
|
|
}
|
|
return marshalFeatureCollection([]feature{
|
|
newFeature(solarEclipseEvent, regionRole, value, regionProperties),
|
|
})
|
|
}
|
|
regionProperties["source_boundary_closed"] = false
|
|
regionProperties["geometry_role"] = "horizon-closed-region"
|
|
regionProperties["closure"] = solarHorizonClosureProperties(
|
|
instant.Time, instant.Time, solarHorizonClosureExact(instant.Boundaries, instant.HorizonEnds), module,
|
|
)
|
|
ring, boundary := solarShadowFootprintHorizonRing(
|
|
instant.Time, instant.Boundaries, instant.HorizonEnds, curve, module,
|
|
)
|
|
if solarShadowRegionDegenerate(curve, ring) {
|
|
return marshalEmptyFeatureCollection()
|
|
}
|
|
value, err := multiPolygonGeometry([][]geodata.GeoPoint{ring})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("geojson: solar shadow instant at %s: %w", formatTime(instant.Time), err)
|
|
}
|
|
features = append(features, newFeature(
|
|
solarEclipseEvent, regionRole, value, regionProperties,
|
|
))
|
|
boundaryValue, err := geoMultiLineGeometry(boundary, false)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("geojson: solar shadow instant at %s: %w", formatTime(instant.Time), err)
|
|
}
|
|
boundaryProperties := cloneProperties(properties)
|
|
boundaryProperties["time"] = formatTime(instant.Time)
|
|
boundaryProperties["source_boundary_closed"] = false
|
|
boundaryProperties["geometry_role"] = "open-boundary"
|
|
features = append(features, newFeature(
|
|
solarEclipseEvent, boundaryRole, boundaryValue, boundaryProperties,
|
|
))
|
|
return marshalFeatureCollection(features)
|
|
}
|