Class: Astroscript::Body

Inherits:
Object
  • Object
show all
Defined in:
lib/astroscript/body.rb

Direct Known Subclasses

ConstBody, HouseCusp, MethodBody, Midpoint

Constant Summary collapse

ORBS =

def /(body)

Midpoint.new(self, body)

end

{ tight: 2.0, close: 6.0, max: 12.0 }.freeze
ANGLES =
%i[AC MC DC IC VX POF POS POH].freeze
STATIONARY_VELOCITY =

RETROGRADE = { # days

ME: 24, VE: 42, MA: 80, JU: 120, SA: 140, UR: 150, NE: 160, PL: 160, CE: 60

}

{ # seconds/day from https://www.astro.com/astrowiki/en/Stationary_Phase
  ME: 300, VE: 180, MA: 90, JU: 60, SA: 60, UR: 20, NE: 10, PL: 10, CE: 7
}.freeze
MAX_VELOCITY =
{ # in minutes from https://en.wikipedia.org/wiki/Planets_in_astrology
  ME: (2 * 60) + 25, VE: (1 * 60) + 25, MA: 52, CE: 30, JU: 14 + (40 / 60.0), SA: 8 + (48 / 60.0),
  UR: 4, NE: 2 + (25 / 60.0), PL: 2 + (30 / 60.0), PA: 40 + (30 / 60.0), JN: 39, VA: 36, CH: 10
}.freeze
AVG_VELOCITY =

in minutes

{ # in minutes
  SO: 59 + (8 / 60.0), MO: (13 * 60) + 11 + (36 / 60.0), ME: (1 * 60) + 23, VE: (1 * 60) + 12, MA: 31 + (27 / 60.0), CE: 12 + (40 / 60.0),
  JU: 4 + (59 / 60.0), SA: 2 + (1 / 60.0), UR: 42 / 60.0, NE: 24 / 60.0, PL: 15 / 60.0, CH: 2,
  PA: 12 + (20 / 60.0), JN: 14 + (15 / 60.0), VA: 16 + (15 / 60.0), SD: 0.289, ER: 6.307,
  NN: 3.177
}.freeze
SPEED_ORDER =
AVG_VELOCITY.sort_by{|_k, v| v }.reverse.map(&:first)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(abbr, calc) ⇒ Body

Returns a new instance of Body.



9
10
11
12
13
14
15
# File 'lib/astroscript/body.rb', line 9

def initialize(abbr, calc)
  @abbr = abbr
  @calc = calc
  @abbr = @abbr.upcase if @abbr.size == 2
  @harmonic = 1
  calculate!
end

Instance Attribute Details

#abbrObject (readonly)

Returns the value of attribute abbr.



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

def abbr
  @abbr
end

#altitudeObject (readonly)

Returns the value of attribute altitude.



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

def altitude
  @altitude
end

#antipodeObject

Returns the value of attribute antipode.



7
8
9
# File 'lib/astroscript/body.rb', line 7

def antipode
  @antipode
end

#azimuthObject (readonly)

Returns the value of attribute azimuth.



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

def azimuth
  @azimuth
end

#calcObject (readonly)

Returns the value of attribute calc.



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

def calc
  @calc
end

#declObject (readonly)

Returns the value of attribute decl.



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

def decl
  @decl
end

#distanceObject (readonly)

Returns the value of attribute distance.



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

def distance
  @distance
end

#harmonicObject (readonly)

Returns the value of attribute harmonic.



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

def harmonic
  @harmonic
end

#hdistObject (readonly)

Returns the value of attribute hdist.



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

def hdist
  @hdist
end

#hlatObject (readonly)

Returns the value of attribute hlat.



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

def hlat
  @hlat
end

#hlonObject (readonly)

Returns the value of attribute hlon.



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

def hlon
  @hlon
end

#hvelObject (readonly)

Returns the value of attribute hvel.



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

def hvel
  @hvel
end

#latObject (readonly)

Returns the value of attribute lat.



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

def lat
  @lat
end

#raObject (readonly)

Returns the value of attribute ra.



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

def ra
  @ra
end

#velocityObject (readonly)

Returns the value of attribute velocity.



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

def velocity
  @velocity
end

Class Method Details

.phase(b1, b2, opts = {}) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/astroscript/body.rb', line 31

def self.phase(b1, b2, opts = {})
  opts[:method] ||= :lon
  # $logger.debug("#{b1}, #{b2} #{opts[:method]}")
  bb1 = b1.send(opts[:method])
  bb2 = b2.send(opts[:method])
  (bb2 - bb1) % 360
  # if b1.speed_order > b2.speed_order
  #   (bb2-bb1)%360
  # else
  #   (bb1-bb2)%360
  # end
  # rescue => e
  #   raise e, "#{b1.abbr} - #{b2.abbr} => #{opts[:method]} == nil!"
end

Instance Method Details

#*(other) ⇒ Object



425
426
427
# File 'lib/astroscript/body.rb', line 425

def *(other)
  harmonize(other)
end

#==(other) ⇒ Object



27
28
29
# File 'lib/astroscript/body.rb', line 27

def ==(other)
  lon == other.lon
end

#calculate!Object

Raises:

  • (ArgumentError)


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/astroscript/body.rb', line 104

def calculate!
  # $logger.debug "calculating #{abbr}"
  if @abbr == :SVP
    @lon = -@calc.ayanamsha
    @lat = 0
    @distance = nil
    @velocity = 0
  end
  raise ArgumentError, "unknown Body #{@abbr}!" unless (body = SwissEphemeris::BODIES[@abbr])

  if (id = body[:id])
    results = @calc.calc(id)
    @lon, @lat, @distance, @velocity = results[0..4]
    results = @calc.calc(id, equatorial: true)
    # right ascension and declination
    @ra, @decl = results[0..2]
    @azimuth, @altitude, * = Swe4r.swe_azalt(calc.jd, Swe4r::SE_ECL2HOR, calc.longitude, calc.latitude,
                                             calc.altitude, 1013.25, 15.0, @lon + calc.ayanamsha, @lat.to_f, @distance.to_f)
    @azimuth = (@azimuth + 180) % 360 # adjusts to measure clockwise from north
    # heliocentric
    id = Swe4r::SE_EARTH if abbr == :EA
    results = @calc.calc(id, heliocentric: true)
    @hlon, @hlat, @hdist, @hvel = results[0..4]
  else # virtual body - angles and nodes
    method = if (a = body[:antipode])
               SwissEphemeris::BODIES[a][:name]
             else
               body[:name]
             end
    @calc.get_houses
    method = AstroHelper.symbolize(method)
    # $logger.debug "sending #{method} to @calc"
    if %i[NN SN].include?(@abbr)
      node = @calc.true_node? ? Swe4r::SE_TRUE_NODE : Swe4r::SE_MEAN_NODE
      @lon, @lat, @distance, @velocity = @calc.calc(node)
      # @lon = calc.flip(@lon) if @abbr == :SN # TODO flip after harmonic
    else
      @lon = @calc.send(method)
    end
    # TODO: get values from sun at this degree
  end
  @lon = calc.flip(@lon) if body[:antipode] || antipode
  update!
end

#closer_to_sun?(b2) ⇒ Boolean

this assumes the that BODIES hash is defined in proper order

Returns:

  • (Boolean)


235
236
237
238
239
# File 'lib/astroscript/body.rb', line 235

def closer_to_sun?(b2)
  i1 = distance_to_sun
  i2 = b2.distance_to_sun
  i1 && i2 && i1 < i2
end

#decanObject



395
396
397
# File 'lib/astroscript/body.rb', line 395

def decan
  ((to_f % 30) / 10).floor + 1
end

#distance_to_sunObject



230
231
232
# File 'lib/astroscript/body.rb', line 230

def distance_to_sun
  SwissEphemeris::BODIES.keys.index(abbr) || -1
end

#duadObject



437
438
439
# File 'lib/astroscript/body.rb', line 437

def duad
  SwissEphemeris::SIGNS[(varga_sign(12) - sign) % 12]
end

#dwadObject



449
450
451
# File 'lib/astroscript/body.rb', line 449

def dwad
  harmonic_sign(12)
end

#elementObject



366
367
368
# File 'lib/astroscript/body.rb', line 366

def element
  %i[F E A W][sign % 4]
end

#element_symObject



370
371
372
# File 'lib/astroscript/body.rb', line 370

def element_sym
  %w[🜂 🜃 🜁 🜄][sign % 4]
end

#feminine?Boolean

qualities for interpretations

Returns:

  • (Boolean)


375
376
377
# File 'lib/astroscript/body.rb', line 375

def feminine?
  %i[MO VE NE].include?(abbr)
end

#flipObject



54
55
56
57
# File 'lib/astroscript/body.rb', line 54

def flip
  @lon += 180
  @lon % 360
end

#flip!Object



59
60
61
62
# File 'lib/astroscript/body.rb', line 59

def flip!
  self.antipode = !antipode
  calculate!
end

#gateObject



222
223
224
# File 'lib/astroscript/body.rb', line 222

def gate
  AstroHelper.deg_to_gate(lon)
end

#handleObject



88
89
90
# File 'lib/astroscript/body.rb', line 88

def handle
  "#{prefix}#{abbr}"
end

#harmonic_sign(h) ⇒ Object

Harmonic Divisions



403
404
405
# File 'lib/astroscript/body.rb', line 403

def harmonic_sign(h) # always use 1st harmonic longitude
  SwissEphemeris::SIGNS[varga_sign(h)]
end

#harmonic_signs(*args) ⇒ Object



411
412
413
# File 'lib/astroscript/body.rb', line 411

def harmonic_signs *args
  args.map{|h| harmonic_sign(h) }
end

#harmonize(h) ⇒ Object



421
422
423
# File 'lib/astroscript/body.rb', line 421

def harmonize(h)
  dup.harmonize!(h)
end

#harmonize!(h) ⇒ Object



415
416
417
418
419
# File 'lib/astroscript/body.rb', line 415

def harmonize!(h)
  @harmonic = h
  calculate!
  self
end

#houseObject



350
351
352
# File 'lib/astroscript/body.rb', line 350

def house
  @calc.which_house(lon)
end

#in_detriment?Boolean

Returns:

  • (Boolean)


291
292
293
294
295
# File 'lib/astroscript/body.rb', line 291

def in_detriment?
  EXALTATION[abbr].first == rotate_sign(6)
rescue NoMethodError
  false
end

#in_domicile?Boolean

Returns:

  • (Boolean)


273
274
275
276
277
# File 'lib/astroscript/body.rb', line 273

def in_domicile?
  RULERSHIPS[abbr].include?(sign_sym)
rescue NoMethodError
  false
end

#in_exaltation?Boolean

Returns:

  • (Boolean)


285
286
287
288
289
# File 'lib/astroscript/body.rb', line 285

def in_exaltation?
  EXALTATION[abbr].first == sign_sym
rescue NoMethodError
  false
end

#in_fall?Boolean

opposite to rulership

Returns:

  • (Boolean)


279
280
281
282
283
# File 'lib/astroscript/body.rb', line 279

def in_fall? # opposite to rulership
  RULERSHIPS[abbr].include?(rotate_sign(6))
rescue NoMethodError
  false
end

#inner?Boolean

Returns:

  • (Boolean)


387
388
389
# File 'lib/astroscript/body.rb', line 387

def inner?
  luminary? || %i[ME VE MA].include?(abbr)
end

#inspectObject



17
18
19
20
21
# File 'lib/astroscript/body.rb', line 17

def inspect
  return super unless defined?(IRB)

  "#{abbr}\t#{AstroHelper.deg_to_s(lon)}"
end

#is_angle?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/astroscript/body.rb', line 242

def is_angle?
  ANGLES.include?(abbr)
end

#lonObject Also known as: degree, to_f



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/astroscript/body.rb', line 64

def lon
  output = @lon # @calc.in_mundo? ? prime_degree : @lon
  output *= @harmonic
  output %= 360
  output += @calc.arc if @calc
  # TODO: make harmonic charts a calc transformer?
  if (t = calc&.transformer)
    t.call(self, output)
  else
    output
  end
end

#luminary?Boolean

Returns:

  • (Boolean)


391
392
393
# File 'lib/astroscript/body.rb', line 391

def luminary?
  %i[SO MO].include?(abbr)
end

#masculine?Boolean

Returns:

  • (Boolean)


379
380
381
# File 'lib/astroscript/body.rb', line 379

def masculine?
  %i[SO MA JU UR PL].include?(abbr)
end

#meridian_degreeObject

longitude



172
173
174
175
176
177
178
179
# File 'lib/astroscript/body.rb', line 172

def meridian_degree # longitude
  azimuth, altitude, * = Swe4r.swe_azalt(calc.jd, Swe4r::SE_ECL2HOR, calc.longitude, calc.latitude, calc.altitude,
                                         0, 0, @lon, @lat.to_f, @distance.to_f)
  azimuth = (azimuth + 90) % 360
  lon, decl, * = Swe4r.swe_cotrans(90, azimuth, altitude)
  output = [((lon + 180) % 360).round(4), decl.round(4)]
  output[0]
end

#midpoint?Boolean

Returns:

  • (Boolean)


461
462
463
# File 'lib/astroscript/body.rb', line 461

def midpoint?
  is_a?(Astroscript::Midpoint)
end

#modalityObject



362
363
364
# File 'lib/astroscript/body.rb', line 362

def modality
  %i[c f m][sign % 3]
end

#nameObject



92
93
94
95
96
# File 'lib/astroscript/body.rb', line 92

def name
  return unless (body = SwissEphemeris::BODIES[abbr])

  body[:name].capitalize
end


445
446
447
# File 'lib/astroscript/body.rb', line 445

def navamsha
  harmonic_sign(9)
end

#outer?Boolean

Returns:

  • (Boolean)


383
384
385
# File 'lib/astroscript/body.rb', line 383

def outer?
  %i[SA UR NE PL].include?(abbr)
end

#pentanObject



429
430
431
# File 'lib/astroscript/body.rb', line 429

def pentan
  harmonic_sign(6)
end

#personal_angle?Boolean

Returns:

  • (Boolean)


246
247
248
# File 'lib/astroscript/body.rb', line 246

def personal_angle?
  (ANGLES + %i[VX POF POS POH]).include?(abbr)
end

#prefixObject



84
85
86
# File 'lib/astroscript/body.rb', line 84

def prefix
  @calc&.prefix
end

#prime_degreeObject Also known as: pvl

According to BPHS the victor is the Graha who is further north. Surya Siddhanta adds that the brighter will win even if in the south. By brighter is meant an unusually brighter planet. To determine this we need to know the natural order of brightness from least bright to most bright which is: Saturn, Mars, Mercury, Jupiter, Venus. On very rare occasions when a planet in its oval shaped revolution is much closer to Earth and the other much further away, one planet can gain a lot of brightness while the other loses brightness. On these occasions a planet that is normally darker than another may appear brighter – in which case it wins the war. To determine the victor in a war, therefore, requires first that elaborate calculations are done based on the diameter of the planet and its proximity to Earth in order to determine the brightness. If the brightness of the two planets follows the regular order, then the Graha with the most northern declination wins the war. If, on the other hand, the planet that is regularly less bright is brighter, than it wins the war and no check for most northern position need be made. Venus, regardless, always wins the war, due to her much greater brilliance she is considered to never be defeated. astrology-videos.com/CourseMaterials/PlanetaryWar.pdf



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

def prime_degree
  # lon, decl = Swe4r::swe_cotrans( 90, @azimuth+calc.ayanamsha, @altitude)
  (Swe4r.swe_house_pos(calc.ramc, calc.latitude, calc.oe, "C".ord, @lon + calc.ayanamsha, @lat.to_f) * 30) - 30
end


226
227
228
# File 'lib/astroscript/body.rb', line 226

def print(opts = {})
  puts to_s({ prefix: true, gate: true, spectrum: true, house: true, theme: true, symbol: true }.merge(opts))
end

#radixObject



23
24
25
# File 'lib/astroscript/body.rb', line 23

def radix
  harmonize(1)
end

#relative_velocityObject



340
341
342
343
344
345
346
347
348
# File 'lib/astroscript/body.rb', line 340

def relative_velocity
  return nil unless (minutes = AVG_VELOCITY[abbr])

  begin
    velocity / (minutes / 60.0)
  rescue StandardError
    1.0
  end
end

#retrograde?Boolean

Returns:

  • (Boolean)


297
298
299
# File 'lib/astroscript/body.rb', line 297

def retrograde?
  @velocity&.negative?
end

#ruler(chart = nil) ⇒ Object Also known as: dispositor

RULERSHIP ###



263
264
265
266
267
268
269
270
# File 'lib/astroscript/body.rb', line 263

def ruler(chart = nil)
  ruler = RULERSHIPS.find{|_k, v| v.include? sign_sym }.first
  if chart
    chart.get_body(ruler)
  else
    ruler
  end
end

#signObject



192
193
194
# File 'lib/astroscript/body.rb', line 192

def sign
  (lon / 30).floor
end

#sign_and_houseObject



457
458
459
# File 'lib/astroscript/body.rb', line 457

def sign_and_house
  "#{sign_sym.capitalize} in #{house.ordinalize}"
end

#sign_iObject

ORBS = 2.0, close: 4.0, max: 16.0 # Cochrane



188
189
190
# File 'lib/astroscript/body.rb', line 188

def sign_i
  sign
end

#sign_symObject



196
197
198
# File 'lib/astroscript/body.rb', line 196

def sign_sym
  SwissEphemeris::SIGNS[sign]
end

#speed_orderObject



250
251
252
253
254
255
256
257
# File 'lib/astroscript/body.rb', line 250

def speed_order
  a = abbr
  a = :NN if %i[MN SN].include?(a)
  return -1 * ANGLES.reverse.index(a) if is_angle?

  # https://groups.io/g/SpiritusMundi/topic/speed_of_ascendant_and/83787680
  SPEED_ORDER.index(a)
end

#stationary?Boolean

Here is a snippet of the Python code I use for the speeds: # Adjust the speeds to be compatible with the old standalone version # of Haydn’s Jyotish. { # Haydn Huntley [email protected] } daysPerEarthYear = 365.242199 x = 360.0 / daysPerEarthYear ** 2 self.speed *= 0.09706 # Magic constant. self.speed *= 686.971 * x # Orbital period in days, self.speed *= 4332.59 * x # according to Wikipedia. self.speed *= 10759.22 * x self.speed *= 30799.095 * x self.speed *= 60190.03 * x self.speed *= 89865.65 * x self.speed *= 6585.3213 * x # Saros cycle in days. self.speed *= 6585.3213 * x

Returns:

  • (Boolean)


334
335
336
337
338
# File 'lib/astroscript/body.rb', line 334

def stationary?
  return nil unless (minutes = MAX_VELOCITY[abbr])

  velocity.abs <= (0.05 * minutes / 60.0) # 5% of velocity in degrees/day
end

#subduadObject

is this correct



441
442
443
# File 'lib/astroscript/body.rb', line 441

def subduad # is this correct
  SwissEphemeris::SIGNS[(varga_sign(144) - sign) % 12]
end

#subdwadObject



453
454
455
# File 'lib/astroscript/body.rb', line 453

def subdwad
  harmonic_sign(144)
end

#subpentanObject



433
434
435
# File 'lib/astroscript/body.rb', line 433

def subpentan
  harmonic_sign(36)
end

#symbolObject



98
99
100
101
102
# File 'lib/astroscript/body.rb', line 98

def symbol
  return unless (body = SwissEphemeris::BODIES[abbr])

  body[:symbol]
end

#to_dms(opts = {}) ⇒ Object



80
81
82
# File 'lib/astroscript/body.rb', line 80

def to_dms(opts = {})
  lon.to_dms(opts)
end

#to_json(*_args) ⇒ Object



465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/astroscript/body.rb', line 465

def to_json(*_args)
  d, m, * = AstroHelper.dms(lon)
  key = "#{name.downcase} in #{SwissEphemeris::SIGNS[sign]}"
  {
    house: house,
    name: name,
    sign_degrees: d,
    sign_minutes: m.round,
    sign_name: SwissEphemeris::SIGNS[sign],
    total_angle: @lon.round(2),
    description: key.titleize,
    key: key
  }
end

#to_s(_opts = {}) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/astroscript/body.rb', line 200

def to_s(_opts = {})
  opts = { angle: true, symbol: true }.merge!(_opts)
  postfix = " "
  if opts[:angle]
    postfix = "r" if retrograde?
    postfix = "s" if stationary?
    dignity = nil
    # dignity = SYMBOLS[:exalted] if in_exaltation? # TODO
    # dignity = SYMBOLS[:detriment] if in_detriment?
  end
  if opts[:symbol]
    opts[:prefix] = format("%4s", symbol) if opts[:symbol]
    opts[:padding] = 2
  end
  opts[:prefix] = "#{opts[:symbol] ? symbol : name}#{dignity}" if opts[:prefix]
  if opts[:house]
    opts[:postfix] = "#{postfix} #{format('%-5s', HOUSES[house])}"
    opts[:postfix] += " (#{AstroHelper::HOUSE_THEMES[house]})" if opts[:theme]
  end
  AstroHelper.deg_to_s(lon, { postfix: postfix }.merge!(opts)) # .strip
end

#transit!Object



50
51
52
# File 'lib/astroscript/body.rb', line 50

def transit!
  @transit = true
end

#transit?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/astroscript/body.rb', line 46

def transit?
  @transit
end

#triple_harmonic_signs(h) ⇒ Object



407
408
409
# File 'lib/astroscript/body.rb', line 407

def triple_harmonic_signs(h)
  harmonic_signs(1, h, h * h)
end

#yang?Boolean

Returns:

  • (Boolean)


358
359
360
# File 'lib/astroscript/body.rb', line 358

def yang?
  sign.even?
end

#yin?Boolean

Returns:

  • (Boolean)


354
355
356
# File 'lib/astroscript/body.rb', line 354

def yin?
  sign.odd?
end