Class: Astroscript::Aspect

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/astroscript/aspect.rb

Constant Summary collapse

FLAVORS =
{
  1r => "conjunct", 1/2r => "opposite", 1/4r => "square",
  1/8r => "octile", 3/8r => "trioctile",
  1/3r => "trine", 1/6r => "sextile", # 1/9r => 'novile',
  1/12r => "semisextile", 5/12r => "quincunx",
  1/5r => "quintile", 2/5r => "biquintile"
  # 1/7r => 'septile', 2/7r => 'biseptile', 3/7r => 'triseptile'
  # 1/10r => 'decile', 1/11r => 'undecile',
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(b1, b2, opts = {}) ⇒ Aspect

Returns a new instance of Aspect.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/astroscript/aspect.rb', line 27

def initialize(b1, b2, opts = {})
  opts[:max_harmonic] ||= 12
  opts[:harmonic_orb] ||= 16.0
  if opts[:ratio] # isolate flavor, e.g. 5/12
    opts[:harmonic] = opts[:ratio].denominator
    opts[:numerator] = opts[:ratio].numerator
  end
  @bodies = [b1, b2]
  sort!
  @phase = @bodies.map(&:lon).diff.first.abs

  ary = if (h = opts[:harmonic]) # isolate single flavor
          [h]
        else
          1..opts[:max_harmonic]
        end

  ary.each do |harmonic|
    mod = 360
    orb = (@phase * harmonic) % mod
    orb = mod - orb if orb > mod / 2 # this is the "flip" for oppositions

    # check for conjunction in nth harmonic "flavor"
    next unless orb <= (opts[:orb] || opts[:harmonic_orb])

    if harmonic == 1
      @aspect = 1r # 1/1 = conjunction
    else
      num = (@phase.abs * harmonic / mod).round
      num = harmonic - num if num > harmonic / 2 # flip e.g. 7/12 to 5/12
      @aspect = Rational(num, harmonic)
    end
    @orb = orb / harmonic
    isolated_harmonic = opts[:harmonic] && @aspect.denominator != opts[:harmonic]
    isolated_numerator = opts[:numerator] && @aspect.numerator != opts[:numerator]
    return self unless isolated_harmonic || isolated_numerator
  end
  @aspect = 0r
  @orb = nil
end

Instance Attribute Details

#aspectObject (readonly)

Returns the value of attribute aspect.



5
6
7
# File 'lib/astroscript/aspect.rb', line 5

def aspect
  @aspect
end

#bodiesObject (readonly)

Returns the value of attribute bodies.



5
6
7
# File 'lib/astroscript/aspect.rb', line 5

def bodies
  @bodies
end

#orbObject (readonly)

Returns the value of attribute orb.



5
6
7
# File 'lib/astroscript/aspect.rb', line 5

def orb
  @orb
end

#phaseObject (readonly)

Returns the value of attribute phase.



5
6
7
# File 'lib/astroscript/aspect.rb', line 5

def phase
  @phase
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



68
69
70
# File 'lib/astroscript/aspect.rb', line 68

def ==(other)
  bodies.map(&:abbr).sort == other.bodies.map(&:abbr).sort && phase == other.phase
end

#antiphaseObject



149
150
151
# File 'lib/astroscript/aspect.rb', line 149

def antiphase
  -@phase % 360
end

#applying?Boolean

Returns:

  • (Boolean)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/astroscript/aspect.rb', line 95

def applying?
  return @applying if @applying

  @orb1 = @bodies.map(&:degree).inject(:-).abs
  body = @bodies.first
  if body.is_a?(Midpoint)
    body = @bodies.last
    return nil if body.is_a?(Midpoint)
  end
  body.calc.jd += 1       # move forward
  @bodies.each(&:calculate!)
  @orb2 = @bodies.map(&:degree).inject(:-).abs
  body.calc.jd -= 1       # put back
  @bodies.each(&:calculate!)
  return nil if @orb1 == @orb2

  @applying = @orb1 > @orb2
end

#direct_midpoint?Boolean

Returns:

  • (Boolean)


157
158
159
160
161
# File 'lib/astroscript/aspect.rb', line 157

def direct_midpoint?
  return unless midpoint?

  @bodies.map(&:lon).diff.first.abs < 90
end

#invalid?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/astroscript/aspect.rb', line 129

def invalid?
  numerator.zero? || !FLAVORS.keys.include?(aspect)
end

#isotrap?Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/astroscript/aspect.rb', line 167

def isotrap?
  @bodies.all?{|b| b.is_a?(Midpoint) }
end

#midpoint?Boolean

Returns:

  • (Boolean)


163
164
165
# File 'lib/astroscript/aspect.rb', line 163

def midpoint?
  @bodies.any?{|b| b.is_a?(Midpoint) }
end

#midpoint_aspectObject



175
176
177
178
179
# File 'lib/astroscript/aspect.rb', line 175

def midpoint_aspect
  return unless midpoint?

  direct_midpoint? ? SwissEphemeris::SYMBOLS[:conjunct] : SwissEphemeris::SYMBOLS[:opposite]
end

#opposite_midpoint?Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/astroscript/aspect.rb', line 171

def opposite_midpoint?
  !direct?
end

#overlap?Boolean

Returns:

  • (Boolean)


73
74
75
76
# File 'lib/astroscript/aspect.rb', line 73

def overlap?
  abbrs = @bodies.map{|b| b.abbr.to_s.split("/").flatten }
  (abbrs.first & abbrs.last).any?
end


181
182
183
184
185
186
# File 'lib/astroscript/aspect.rb', line 181

def print_midpoint
  return unless midpoint?

  movement = applying? ? "a" : "s"
  "#{@bodies.map(&:symbol).join(" #{midpoint_aspect} ")}\t[#{AstroHelper.print_dms(orb)}#{movement}]"
end

#ratioObject



121
122
123
# File 'lib/astroscript/aspect.rb', line 121

def ratio
  "#{numerator}/#{denominator}"
end

#separating?Boolean

Returns:

  • (Boolean)


114
115
116
117
118
119
# File 'lib/astroscript/aspect.rb', line 114

def separating?
  applying? # calculate stuff
  return nil if @orb1 == @orb2

  @orb1 < @orb2
end

#sort!Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/astroscript/aspect.rb', line 78

def sort!
  @bodies.sort_by!{|x| x.is_a?(Midpoint) ? x.bodies.first.speed_order.to_i : x.speed_order.to_i }
  b1 = @bodies.first
  b2 = @bodies.last
  if b1.is_a?(Midpoint)
    if b2.is_a?(Midpoint)
      if b1.bodies.first == b2.bodies.first && b1.bodies.last.speed_order.to_i < (b2.bodies.last.speed_order.to_i)
        @bodies.reverse!
      end
    else
      @bodies.reverse!
    end
  end
  @bodies.reverse! if @bodies.last.prefix
  self
end

#sumObject



153
154
155
# File 'lib/astroscript/aspect.rb', line 153

def sum
  [b1, b2].map{|b| b.send(@method) }.sum % 360
end

#to_aObject



133
134
135
# File 'lib/astroscript/aspect.rb', line 133

def to_a
  @bodies.map(&:to_sym) << { harmonic => orb.round(3) }
end

#to_s(opts = {}) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/astroscript/aspect.rb', line 137

def to_s(opts = {})
  opts[:symbol] = true unless opts.key?(:symbol)
  opts[:orb] = true unless opts.key?(:orb)
  return "invalid: #{inspect}" unless valid?

  flavor = FLAVORS[aspect]
  flavor = SwissEphemeris::SYMBOLS[flavor.to_sym] if opts[:symbol]
  output = "#{@bodies.first.handle} #{flavor} #{@bodies.last.handle}"
  output += " [#{@orb.to_dms(separator: applying? ? 'a' : 's')}]" if opts[:orb]
  output
end

#valid?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/astroscript/aspect.rb', line 125

def valid?
  !invalid?
end