Module: AstroChart::Patterns
- Defined in:
- lib/astro_chart/patterns.rb
Overview
Aspect pattern detection (相位圖形).
Detects the classic configurations from a set of ecliptic longitudes (相位由 Aspects.calculate 重新計算,不依賴外部相位表):
大三角 (Grand Trine): 3 bodies pairwise in 三分相.
T三角 (T-Square): 2 bodies in 對分相, both 四分相 to an apex.
大十字 (Grand Cross): 4 bodies forming 2 對分相 pairs with all 4
adjacent pairs in 四分相.
上帝之指 (Yod): 2 bodies in 六分相, both 補十二分相 (150°) to an apex.
風箏 (Kite): a 大三角 plus a 4th body opposing one leg and
六分相 to the other two.
神祕矩形 (Mystic Rectangle): 2 對分相 pairs joined by 六分相 (short sides)
and 三分相 (long sides).
星群 (Stellium): 3+ bodies sharing one zodiac sign.
Deduplication rules:
- A 大十字 subsumes the 4 T三角s formed by its own bodies — those
T三角s are not reported separately.
- 南交點 sits exactly 180° from 北交點, so an opposition squared by
the node axis would always yield two mirrored T三角s (apex 北交點
and apex 南交點). The 南交點-apex twin is collapsed: the single
physical configuration is reported once, with apex 北交點.
- Each pattern is reported once regardless of body order.
- A 風箏 does NOT subsume its 大三角 — astrologers describe the two
together ("a grand trine with a kite"), so both are reported.
Constant Summary collapse
- ELEMENTS =
Elements repeat every 4 signs starting from 牡羊座 (火).
["火", "土", "風", "水"].freeze
- NODE_AXIS =
北交點/南交點 are always exactly 180° apart by definition, so their mutual 對分相 carries no astrological information. That specific pair is therefore excluded from serving as the opposition leg of a T三角, 大十字, 神祕矩形 or 風箏. The nodes themselves remain valid participants — e.g. a node may still be the apex of a T三角, or oppose a planet.
["北交點", "南交點"].sort.freeze
Class Method Summary collapse
-
.detect(positions) ⇒ Object
positions: { "太陽" => 123.45, ... } (ecliptic longitudes, degrees).
Class Method Details
.detect(positions) ⇒ Object
positions: { "太陽" => 123.45, ... } (ecliptic longitudes, degrees)
Returns Array of:
{ "pattern_type" => "大三角", "planets" => [...], "element" => "火" | nil }
{ "pattern_type" => "T三角", "planets" => [...], "apex" => "火星" }
{ "pattern_type" => "大十字", "planets" => [...] }
{ "pattern_type" => "上帝之指", "planets" => [...], "apex" => "火星" }
{ "pattern_type" => "風箏", "planets" => [...], "apex" => "火星" }
{ "pattern_type" => "神祕矩形", "planets" => [...] }
{ "pattern_type" => "星群", "planets" => [...], "zodiac" => "牡羊座" }
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/astro_chart/patterns.rb', line 52 def self.detect(positions) names = positions.keys sextiles = {} trines = {} squares = {} oppositions = {} quincunxes = {} names.combination(2) do |a, b| # minor: true so 補十二分相 (150°) is available for Yod detection; # the major classifications are unaffected (major always wins). type, _orb = Aspects.calculate(positions[a], positions[b], minor: true) case type when "六分相" then sextiles[[a, b].sort] = true when "三分相" then trines[[a, b].sort] = true when "四分相" then squares[[a, b].sort] = true when "對分相" then oppositions[[a, b].sort] = true when "補十二分相" then quincunxes[[a, b].sort] = true end end # See NODE_AXIS: the definitional node opposition never counts as # the opposition leg of a T三角, 大十字, 神祕矩形 or 風箏. oppositions.delete(NODE_AXIS) grand_trines = detect_grand_trines(names, trines, positions) grand_crosses = detect_grand_crosses(oppositions, squares) t_squares = detect_t_squares(names, oppositions, squares) # 大十字 subsumes its own 4 T三角s. cross_sets = grand_crosses.map { |gc| gc["planets"] } t_squares = t_squares.reject do |t| cross_sets.any? { |set| (t["planets"] - set).empty? } end # See NODE_AXIS: a 南交點-apex T三角 mirroring a 北交點-apex one on # the same opposition is the same physical configuration ("opposition # squared by the node axis") — report it once, with apex 北交點. t_squares = t_squares.reject do |t| t["apex"] == "南交點" && t_squares.any? do |other| other["apex"] == "北交點" && other["planets"][0, 2] == t["planets"][0, 2] end end yods = detect_yods(names, sextiles, quincunxes) kites = detect_kites(grand_trines, names, oppositions, sextiles) rectangles = detect_mystic_rectangles(oppositions, sextiles, trines) stelliums = detect_stelliums(positions) grand_trines + t_squares + grand_crosses + yods + kites + rectangles + stelliums end |