cryogenic22 commited on
Commit
db54019
·
verified ·
1 Parent(s): 5b2d817

Update astro_core.py

Browse files
Files changed (1) hide show
  1. astro_core.py +98 -72
astro_core.py CHANGED
@@ -1,10 +1,16 @@
 
 
 
 
 
 
1
  from datetime import datetime
2
- from typing import Dict, Any
3
  import pytz
4
- import flatlib
5
  from flatlib.datetime import Datetime
6
  from flatlib.geopos import GeoPos
7
  from flatlib.chart import Chart
 
8
 
9
  class ChartCalculator:
10
  """Handles astrological calculations"""
@@ -13,22 +19,30 @@ class ChartCalculator:
13
  self.planets = ['Sun', 'Moon', 'Mercury', 'Venus', 'Mars',
14
  'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto']
15
 
16
- def _get_utc_offset(self, dt: datetime, timezone: str) -> str:
17
  """
18
- Get UTC offset for a given datetime and timezone
19
- Returns offset in format '+HH:MM' or '-HH:MM'
20
  """
21
- tz = pytz.timezone(timezone)
22
- offset = tz.utcoffset(dt)
23
-
24
- # Convert timedelta to hours and minutes
25
- total_seconds = int(offset.total_seconds())
26
- hours = total_seconds // 3600
27
- minutes = (abs(total_seconds) % 3600) // 60
28
 
29
- # Format as string
30
- sign = '+' if hours >= 0 else '-'
31
- return f"{sign}{abs(hours):02d}:{minutes:02d}"
 
 
 
 
 
 
 
 
 
32
 
33
  def calculate_birth_chart(self,
34
  birth_datetime: datetime,
@@ -39,66 +53,78 @@ class ChartCalculator:
39
  Calculate birth chart positions
40
  Returns a dictionary of planetary positions and house cusps
41
  """
42
- # Convert datetime to format required by flatlib
43
- date_str = birth_datetime.strftime("%Y/%m/%d")
44
- time_str = birth_datetime.strftime("%H:%M")
45
-
46
- # Get UTC offset for the timezone
47
- utc_offset = self._get_utc_offset(birth_datetime, timezone)
48
-
49
- # Create flatlib datetime object
50
- date = Datetime(date_str, time_str, utc_offset)
51
- pos = GeoPos(latitude, longitude)
52
-
53
- # Calculate chart
54
- chart = Chart(date, pos)
55
-
56
- # Extract planetary positions
57
- positions = {}
58
- for planet in self.planets:
59
- obj = chart.get(planet)
60
- # Get house placement by comparing longitude to house cusps
61
- house_num = self._get_house_number(obj.lon, chart)
62
- positions[planet] = {
63
- 'sign': obj.sign,
64
- 'degrees': obj.lon,
65
- 'house': house_num
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
-
68
- # Extract house cusps
69
- houses = {}
70
- for i in range(1, 13):
71
- house = chart.houses.get(i)
72
- houses[f'House_{i}'] = {
73
- 'sign': house.sign,
74
- 'degrees': house.lon
75
  }
76
-
77
- return {
78
- 'planets': positions,
79
- 'houses': houses
80
- }
81
 
82
- def _get_house_number(self, longitude: float, chart: Chart) -> int:
83
- """
84
- Determine which house a planet is in based on its longitude
85
- """
86
- for i in range(1, 13):
87
- next_house = i + 1 if i < 12 else 1
88
- cusp = chart.houses.get(i).lon
89
- next_cusp = chart.houses.get(next_house).lon
90
-
91
- # Handle cases where house spans 0° Aries
92
- if next_cusp < cusp:
93
- if longitude >= cusp or longitude < next_cusp:
94
- return i
95
- else:
96
- if cusp <= longitude < next_cusp:
97
- return i
98
-
99
- # Fallback (shouldn't happen with valid data)
100
- return 1
101
-
102
  def get_planet_aspects(self, chart_data: Dict[str, Any]) -> Dict[str, list]:
103
  """Calculate major aspects between planets"""
104
  # TODO: Implement aspect calculation
 
1
+ # astro_core.py
2
+ """
3
+ Core astrology calculation module.
4
+ Handles birth chart calculations using flatlib.
5
+ """
6
+
7
  from datetime import datetime
 
8
  import pytz
9
+ from typing import Dict, Any
10
  from flatlib.datetime import Datetime
11
  from flatlib.geopos import GeoPos
12
  from flatlib.chart import Chart
13
+ from flatlib.const import LIST_SIGNS, LIST_PLANETS
14
 
15
  class ChartCalculator:
16
  """Handles astrological calculations"""
 
19
  self.planets = ['Sun', 'Moon', 'Mercury', 'Venus', 'Mars',
20
  'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto']
21
 
22
+ def _get_house_number(self, lon: float, chart: Chart) -> int:
23
  """
24
+ Determine house number for a given longitude
 
25
  """
26
+ house_lons = []
27
+ for i in range(1, 13):
28
+ try:
29
+ house = chart.houses.get(i)
30
+ house_lons.append(house.lon if house else 0)
31
+ except (KeyError, AttributeError):
32
+ house_lons.append(0)
33
 
34
+ # Convert longitude to house number
35
+ for i in range(12):
36
+ next_i = (i + 1) % 12
37
+ if (house_lons[i] <= lon < house_lons[next_i]) or \
38
+ (house_lons[i] > house_lons[next_i] and # Handle zodiac wrap
39
+ (lon >= house_lons[i] or lon < house_lons[next_i])):
40
+ return i + 1
41
+ return 1 # Default to first house if no match found
42
+
43
+ def _normalize_longitude(self, lon: float) -> float:
44
+ """Normalize longitude to 0-360 range"""
45
+ return lon % 360
46
 
47
  def calculate_birth_chart(self,
48
  birth_datetime: datetime,
 
53
  Calculate birth chart positions
54
  Returns a dictionary of planetary positions and house cusps
55
  """
56
+ try:
57
+ # Ensure timezone is valid
58
+ tz = pytz.timezone(timezone)
59
+ birth_datetime = tz.localize(birth_datetime) if birth_datetime.tzinfo is None else birth_datetime
60
+
61
+ # Convert to flatlib datetime
62
+ date = Datetime(birth_datetime, timezone)
63
+ pos = GeoPos(latitude, longitude)
64
+
65
+ # Calculate chart
66
+ chart = Chart(date, pos)
67
+
68
+ # Extract planetary positions
69
+ positions = {}
70
+ for planet in self.planets:
71
+ try:
72
+ obj = chart.get(planet)
73
+ if obj:
74
+ # Normalize longitude
75
+ lon = self._normalize_longitude(obj.lon)
76
+
77
+ # Get sign
78
+ sign_num = int(lon / 30)
79
+ sign = LIST_SIGNS[sign_num]
80
+
81
+ # Get house
82
+ house = self._get_house_number(lon, chart)
83
+
84
+ positions[planet] = {
85
+ 'sign': sign,
86
+ 'degrees': lon,
87
+ 'house': house
88
+ }
89
+ except Exception as e:
90
+ positions[planet] = {
91
+ 'sign': 'Unknown',
92
+ 'degrees': 0,
93
+ 'house': 1,
94
+ 'error': str(e)
95
+ }
96
+
97
+ # Extract house cusps
98
+ houses = {}
99
+ for i in range(1, 13):
100
+ try:
101
+ house = chart.houses.get(i)
102
+ if house:
103
+ lon = self._normalize_longitude(house.lon)
104
+ sign_num = int(lon / 30)
105
+ houses[f'House_{i}'] = {
106
+ 'sign': LIST_SIGNS[sign_num],
107
+ 'degrees': lon
108
+ }
109
+ except Exception as e:
110
+ houses[f'House_{i}'] = {
111
+ 'sign': 'Unknown',
112
+ 'degrees': 0,
113
+ 'error': str(e)
114
+ }
115
+
116
+ return {
117
+ 'planets': positions,
118
+ 'houses': houses
119
  }
120
+
121
+ except Exception as e:
122
+ return {
123
+ 'error': f"Failed to calculate birth chart: {str(e)}",
124
+ 'planets': {},
125
+ 'houses': {}
 
 
126
  }
 
 
 
 
 
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  def get_planet_aspects(self, chart_data: Dict[str, Any]) -> Dict[str, list]:
129
  """Calculate major aspects between planets"""
130
  # TODO: Implement aspect calculation