solarmoonpy 1.0.7__tar.gz → 1.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of solarmoonpy might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solarmoonpy
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Precise solar and lunar calculations for astronomical applications
5
5
  Author-email: figorr <jdcuartero@yahoo.es>
6
6
  License: Apache License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "solarmoonpy"
7
- version = "1.0.7"
7
+ version = "1.0.8"
8
8
  description = "Precise solar and lunar calculations for astronomical applications"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "figorr", email = "jdcuartero@yahoo.es" }]
@@ -3,7 +3,7 @@ from datetime import date, datetime, timezone
3
3
  from zoneinfo import ZoneInfo
4
4
  from typing import Optional, Union, Literal, Dict
5
5
 
6
- from .sun import sunrise_sunset, noon, dawn, dusk, midnight # Importar funciones de sun.py
6
+ from .sun import sunrise_sunset, noon, dawn, dusk, midnight, sun_position # Importar funciones de sun.py
7
7
 
8
8
  @dataclass
9
9
  class LocationInfo:
@@ -323,6 +323,39 @@ class Location:
323
323
  timezone=self.tzinfo if local else timezone.utc
324
324
  )
325
325
 
326
+ def sun_position(
327
+ self,
328
+ dt: Optional[datetime] = None,
329
+ local: bool = True,
330
+ elevation: Optional[float] = None
331
+ ) -> dict:
332
+ """
333
+ Calcula la posición actual del Sol.
334
+
335
+ Args:
336
+ dt: Momento exacto. Si None, usa ahora.
337
+ local: True para usar zona horaria local.
338
+ elevation: Elevación del observador.
339
+
340
+ Returns:
341
+ dict: elevation, azimuth, above_horizon, rising
342
+ """
343
+ if local and self.timezone is None:
344
+ raise ValueError("Se solicitó hora local pero no se definió una zona horaria.")
345
+
346
+ tz = self.tzinfo if local else timezone.utc
347
+ dt = dt or datetime.now(tz)
348
+ elevation = elevation if elevation is not None else self.elevation
349
+
350
+ return sun_position(
351
+ latitude=self.latitude,
352
+ longitude=self.longitude,
353
+ dt=dt,
354
+ elevation=elevation,
355
+ timezone=tz,
356
+ with_refraction=True
357
+ )
358
+
326
359
  def sun_events(
327
360
  self,
328
361
  date: Optional[date] = None,
@@ -356,7 +389,8 @@ class Location:
356
389
  raise ValueError("Se solicitó hora local pero no se definió una zona horaria.")
357
390
 
358
391
  tz = self.tzinfo if local else timezone.utc
359
- date = date or datetime.now(tz).date()
392
+ now = datetime.now(tz)
393
+ date = date or now.date()
360
394
  elevation = elevation if elevation is not None else self.elevation
361
395
 
362
396
  # Calcular amanecer y atardecer
@@ -444,6 +478,9 @@ class Location:
444
478
  with_refraction=True,
445
479
  )
446
480
 
481
+ # Posición actual del Sol
482
+ pos = self.sun_position(dt=now, local=local, elevation=elevation)
483
+
447
484
  return {
448
485
  "dawn_civil": dawn_civil,
449
486
  "dawn_nautical": dawn_nautical,
@@ -456,4 +493,8 @@ class Location:
456
493
  "dusk_astronomical": dusk_astronomical,
457
494
  "midnight": midnight_time,
458
495
  "daylight_duration": daylight_duration,
496
+ "sun_elevation": pos["elevation"],
497
+ "sun_azimuth": pos["azimuth"],
498
+ "sun_horizon_position": pos["horizon_position"],
499
+ "sun_rising": pos["rising"],
459
500
  }
@@ -333,6 +333,86 @@ def midnight(
333
333
  noon_time = noon(longitude, date, timezone)
334
334
  return noon_time + datetime.timedelta(hours=12)
335
335
 
336
+ def sun_position(
337
+ latitude: float,
338
+ longitude: float,
339
+ dt: datetime.datetime,
340
+ elevation: float = 0.0,
341
+ timezone: datetime.timezone = datetime.timezone.utc,
342
+ with_refraction: bool = True
343
+ ) -> dict:
344
+ """
345
+ Calcula la posición del Sol con alta precisión.
346
+ """
347
+ if dt.tzinfo is None:
348
+ dt = dt.replace(tzinfo=timezone)
349
+ dt_utc = dt.astimezone(datetime.timezone.utc)
350
+
351
+ jd = julianday(dt_utc)
352
+ jc = julianday_to_juliancentury(jd)
353
+ declination = sun_declination(jc)
354
+ eqtime = eq_of_time(jc)
355
+
356
+ # Tiempo solar verdadero en minutos desde medianoche
357
+ true_solar_time = (
358
+ dt_utc.hour * 60 + dt_utc.minute + dt_utc.second / 60.0
359
+ + eqtime + 4.0 * longitude
360
+ )
361
+
362
+ # Ángulo horario
363
+ hour_angle = (true_solar_time / 4.0) - 180.0
364
+ if hour_angle < -180:
365
+ hour_angle += 360
366
+ elif hour_angle > 180:
367
+ hour_angle -= 360
368
+
369
+ # Convertir a radianes
370
+ ha_rad = radians(hour_angle)
371
+ lat_rad = radians(latitude)
372
+ dec_rad = radians(declination)
373
+
374
+ # Elevación geométrica
375
+ sin_elev = sin(lat_rad) * sin(dec_rad) + cos(lat_rad) * cos(dec_rad) * cos(ha_rad)
376
+ elevation_geom = degrees(asin(max(min(sin_elev, 1.0), -1.0)))
377
+
378
+ # Corrección por altura del observador
379
+ elevation_adj = elevation_geom + adjust_to_horizon(elevation)
380
+
381
+ # Refracción atmosférica
382
+ if with_refraction and -10 <= elevation_adj <= 90:
383
+ refraction = refraction_at_zenith(90.0 - elevation_adj)
384
+ elevation_final = elevation_adj + refraction
385
+ else:
386
+ elevation_final = elevation_adj
387
+
388
+ # Azimut (0° = Norte)
389
+ sin_elev_final = sin(radians(elevation_final))
390
+ cos_elev_final = cos(radians(elevation_final))
391
+ cos_lat = cos(lat_rad)
392
+ sin_lat = sin(lat_rad)
393
+ sin_dec = sin(dec_rad)
394
+
395
+ if abs(cos_elev_final * cos_lat) < 1e-12:
396
+ azimuth = 180.0 if ha_rad < 0 else 0.0
397
+ else:
398
+ cos_az = (sin_dec - sin_elev_final * sin_lat) / (cos_elev_final * cos_lat)
399
+ cos_az = max(min(cos_az, 1.0), -1.0)
400
+ azimuth = degrees(acos(cos_az))
401
+ if hour_angle > 0: # PM
402
+ azimuth = 360.0 - azimuth
403
+
404
+ horizon_position: Literal["above_horizon", "below_horizon"] = (
405
+ "above_horizon" if elevation_final > 0 else "below_horizon"
406
+ )
407
+ rising = elevation_final > 0 and hour_angle < 0
408
+
409
+ return {
410
+ "elevation": round(elevation_final, 2),
411
+ "azimuth": round(azimuth, 2),
412
+ "horizon_position": horizon_position,
413
+ "rising": rising
414
+ }
415
+
336
416
  # 🎁 FUNCIÓN BONUS: Todo junto (opcional)
337
417
  def all_sun_events(
338
418
  latitude: float, longitude: float, date: datetime.date,
@@ -0,0 +1,2 @@
1
+ # version.py
2
+ __version__ = "1.0.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solarmoonpy
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Precise solar and lunar calculations for astronomical applications
5
5
  Author-email: figorr <jdcuartero@yahoo.es>
6
6
  License: Apache License
@@ -1,2 +0,0 @@
1
- # version.py
2
- __version__ = "1.0.7"
File without changes
File without changes
File without changes