Files
digital-psychology/apps/api/internal/star/natal/aspects.go
T
jackyu66gitandCursor bd22d9dddd feat: P1 合盘/星座/问答与测测完整设计包及模拟器取证工具
落地 synastry/star/ask API 与 H5 页面,补齐 cece-frontend-re complete-design 证据文档,并加入 Android 模拟器截图抓取脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 11:37:53 +08:00

91 lines
2.2 KiB
Go

package natal
import (
"fmt"
"math"
"sort"
)
// Aspect is a major aspect between two chart points.
type Aspect struct {
A string `json:"a"`
B string `json:"b"`
ATitle string `json:"a_title"`
BTitle string `json:"b_title"`
Type string `json:"type"` // conjunction|sextile|square|trine|opposition
Angle float64 `json:"angle"`
Orb float64 `json:"orb"`
Label string `json:"label"`
}
var aspectDefs = []struct {
Type string
Angle float64
Orb float64
Label string
}{
{"conjunction", 0, 8, "合相"},
{"sextile", 60, 6, "六合"},
{"square", 90, 7, "刑相"},
{"trine", 120, 7, "拱相"},
{"opposition", 180, 8, "对冲"},
}
// majorKeys used for aspect table (外行星可选由前端过滤).
var majorKeys = []string{"sun", "moon", "rise", "mercury", "venus", "mars", "jupiter", "saturn"}
// Aspects computes major aspects among primary bodies.
func Aspects(chart Chart) []Aspect {
byKey := map[string]Body{}
for _, p := range chart.Planets {
byKey[p.Key] = p
}
var bodies []Body
for _, k := range majorKeys {
if b, ok := byKey[k]; ok {
bodies = append(bodies, b)
}
}
out := make([]Aspect, 0)
for i := 0; i < len(bodies); i++ {
for j := i + 1; j < len(bodies); j++ {
a, b := bodies[i], bodies[j]
diff := AngleDiff(a.Lon, b.Lon)
for _, def := range aspectDefs {
orb := math.Abs(diff - def.Angle)
if orb <= def.Orb {
out = append(out, Aspect{
A: a.Key, B: b.Key, ATitle: a.Title, BTitle: b.Title,
Type: def.Type, Angle: def.Angle, Orb: round1(orb),
Label: fmt.Sprintf("%s%s%s(容许%.1f°)", a.Title, def.Label, b.Title, orb),
})
break
}
}
}
}
sort.Slice(out, func(i, j int) bool {
if out[i].Orb != out[j].Orb {
return out[i].Orb < out[j].Orb
}
return out[i].Label < out[j].Label
})
return out
}
// AspectsAsMaps for JSON embedding.
func AspectsAsMaps(list []Aspect) []map[string]any {
out := make([]map[string]any, 0, len(list))
for _, a := range list {
out = append(out, map[string]any{
"a": a.A, "b": a.B, "a_title": a.ATitle, "b_title": a.BTitle,
"type": a.Type, "angle": a.Angle, "orb": a.Orb, "label": a.Label,
})
}
return out
}
func round1(x float64) float64 {
return math.Round(x*10) / 10
}