starplot 0.16.1__py2.py3-none-any.whl → 0.17.0__py2.py3-none-any.whl

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.
Files changed (40) hide show
  1. starplot/__init__.py +28 -2
  2. starplot/base.py +42 -60
  3. starplot/config.py +41 -9
  4. starplot/data/bigsky.py +1 -1
  5. starplot/data/constellations.py +9 -681
  6. starplot/data/db.py +2 -2
  7. starplot/data/dsos.py +11 -28
  8. starplot/data/library/bigsky.0.4.0.stars.mag11.parquet +0 -0
  9. starplot/data/library/sky.db +0 -0
  10. starplot/data/stars.py +15 -433
  11. starplot/data/translations.py +161 -0
  12. starplot/geometry.py +52 -6
  13. starplot/horizon.py +18 -12
  14. starplot/map.py +1 -5
  15. starplot/mixins.py +283 -0
  16. starplot/models/__init__.py +19 -7
  17. starplot/models/base.py +1 -1
  18. starplot/models/comet.py +332 -0
  19. starplot/models/constellation.py +10 -0
  20. starplot/models/dso.py +24 -0
  21. starplot/{optics.py → models/optics.py} +4 -4
  22. starplot/models/satellite.py +158 -0
  23. starplot/models/star.py +10 -0
  24. starplot/optic.py +24 -13
  25. starplot/plotters/__init__.py +1 -0
  26. starplot/plotters/arrow.py +162 -0
  27. starplot/plotters/constellations.py +34 -56
  28. starplot/plotters/dsos.py +8 -14
  29. starplot/plotters/experimental.py +560 -8
  30. starplot/plotters/legend.py +5 -0
  31. starplot/plotters/stars.py +7 -16
  32. starplot/styles/base.py +20 -1
  33. starplot/styles/extensions.py +10 -1
  34. starplot/zenith.py +4 -1
  35. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/METADATA +20 -17
  36. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/RECORD +40 -36
  37. /starplot/{observer.py → models/observer.py} +0 -0
  38. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/WHEEL +0 -0
  39. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/entry_points.txt +0 -0
  40. {starplot-0.16.1.dist-info → starplot-0.17.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,161 @@
1
+ LABELS = {
2
+ "en-us": {
3
+ "legend": "legend",
4
+ "star magnitude": "star magnitude",
5
+ "star": "star",
6
+ "deep sky object": "deep sky object",
7
+ "open cluster": "open cluster",
8
+ "globular cluster": "globular cluster",
9
+ "nebula": "nebula",
10
+ "galaxy": "galaxy",
11
+ "dark nebula": "dark nebula",
12
+ "association of stars": "association of stars",
13
+ "double star": "double star",
14
+ "emission nebula": "emission nebula",
15
+ "galaxy pair": "galaxy pair",
16
+ "galaxy triplet": "galaxy triplet",
17
+ "galaxy cluster": "galaxy cluster",
18
+ "group of galaxies": "group of galaxies",
19
+ "hii ionized region": "hii ionized region",
20
+ "nova star": "nova star",
21
+ "planetary nebula": "planetary nebula",
22
+ "reflection nebula": "reflection nebula",
23
+ "star cluster nebula": "star cluster nebula",
24
+ "supernova remnant": "supernova remnant",
25
+ "unknown": "unknown",
26
+ "planet": "planet",
27
+ "mercury": "mercury",
28
+ "venus": "venus",
29
+ "mars": "mars",
30
+ "jupiter": "jupiter",
31
+ "saturn": "saturn",
32
+ "uranus": "uranus",
33
+ "neptune": "neptune",
34
+ "pluto": "pluto",
35
+ "sun": "sun",
36
+ "moon": "moon",
37
+ "north": "north",
38
+ "east": "east",
39
+ "south": "south",
40
+ "west": "west",
41
+ "ecliptic": "ecliptic",
42
+ "celestial equator": "celestial equator",
43
+ "n": "n",
44
+ "e": "e",
45
+ "s": "s",
46
+ "w": "w",
47
+ "milky way": "milky way",
48
+ },
49
+ "fr": {
50
+ "legend": "légende",
51
+ "star magnitude": "magnitude des étoiles",
52
+ "star": "étoile",
53
+ "deep sky object": "objet du ciel profond",
54
+ "open cluster": "amas ouvert",
55
+ "globular cluster": "amas globulaire",
56
+ "nebula": "nébuleuse",
57
+ "galaxy": "galaxie",
58
+ "dark nebula": "nébuleuse obscure",
59
+ "association of stars": "amas d'étoiles",
60
+ "double star": "étoile double",
61
+ "emission nebula": "nébuleuse en émission",
62
+ "galaxy pair": "paire de galaxies",
63
+ "galaxy triplet": "triplet de galaxies",
64
+ "galaxy cluster": "amas de galaxies",
65
+ "group of galaxies": "groupes de galaxies",
66
+ "hii ionized region": "région d'hydrogène ionisé",
67
+ "nova star": "nova",
68
+ "planetary nebula": "nébuleuse planétaire",
69
+ "reflection nebula": "nébuleuse par réflexion",
70
+ "star cluster nebula": "nébuleuse d’amas d’étoiles",
71
+ "supernova remnant": "rémanent de supernova",
72
+ "unknown": "inconnu",
73
+ "planet": "planète",
74
+ "mercury": "mercure",
75
+ "venus": "venus",
76
+ "mars": "mars",
77
+ "jupiter": "jupiter",
78
+ "saturn": "saturne",
79
+ "uranus": "uranus",
80
+ "neptune": "neptune",
81
+ "pluto": "pluton",
82
+ "sun": "soleil",
83
+ "moon": "lune",
84
+ "north": "nord",
85
+ "east": "est",
86
+ "south": "sud",
87
+ "west": "ouest",
88
+ "ecliptic": "écliptique",
89
+ "celestial equator": "équateur céleste",
90
+ "n": "n",
91
+ "e": "e",
92
+ "s": "s",
93
+ "w": "o",
94
+ "milky way": "voie lactée",
95
+ },
96
+ "zh-cn": {
97
+ "legend": "图例",
98
+ "star magnitude": "星等",
99
+ "star": "恒星",
100
+ "deep sky object": "深空天体",
101
+ "open cluster": "疏散星团",
102
+ "globular cluster": "球状星团",
103
+ "nebula": "星云",
104
+ "galaxy": "星系",
105
+ "dark nebula": "暗星云",
106
+ "association of stars": "星协",
107
+ "double star": "双星",
108
+ "emission nebula": "发射星云",
109
+ "galaxy pair": "星系对",
110
+ "galaxy triplet": "三重星系",
111
+ "galaxy cluster": "星系团",
112
+ "group of galaxies": "星系群",
113
+ "hii ionized region": "hii电离氢区",
114
+ "nova star": "新星",
115
+ "planetary nebula": "行星状星云",
116
+ "reflection nebula": "反射星云",
117
+ "star cluster nebula": "星团星云",
118
+ "supernova remnant": "超新星遗迹",
119
+ "unknown": "未知天体",
120
+ "planet": "行星",
121
+ "mercury": "水星",
122
+ "venus": "金星",
123
+ "mars": "火星",
124
+ "jupiter": "木星",
125
+ "saturn": "土星",
126
+ "uranus": "天王星",
127
+ "neptune": "海王星",
128
+ "pluto": "冥王星",
129
+ "sun": "太阳",
130
+ "moon": "月球",
131
+ "north": "北",
132
+ "east": "东",
133
+ "south": "南",
134
+ "west": "西",
135
+ "ecliptic": "黄道",
136
+ "celestial equator": "天赤道",
137
+ "n": "北",
138
+ "e": "东",
139
+ "s": "南",
140
+ "w": "西",
141
+ "milky way": "银河",
142
+ },
143
+ }
144
+
145
+
146
+ def language_name_column(language: str, column_prefix: str = "name") -> str:
147
+ language_name = language.replace("-", "_").lower()
148
+
149
+ return f"{column_prefix}_{language_name}"
150
+
151
+
152
+ def translate(text: str, language: str) -> str:
153
+ if not text:
154
+ return text
155
+
156
+ translation = LABELS[language.lower()].get(text.lower())
157
+
158
+ if not translation:
159
+ return text
160
+
161
+ return translation.title()
starplot/geometry.py CHANGED
@@ -5,7 +5,7 @@ from typing import Union
5
5
  from shapely import transform
6
6
  from shapely.geometry import Point, Polygon, MultiPolygon
7
7
 
8
- from starplot import geod, utils
8
+ from starplot import geod
9
9
 
10
10
  GLOBAL_EXTENT = Polygon(
11
11
  [
@@ -18,17 +18,18 @@ GLOBAL_EXTENT = Polygon(
18
18
  )
19
19
 
20
20
 
21
- def circle(center, diameter_degrees):
21
+ def circle(center, diameter_degrees, num_pts=100):
22
22
  points = geod.ellipse(
23
23
  center,
24
24
  diameter_degrees,
25
25
  diameter_degrees,
26
26
  angle=0,
27
- num_pts=100,
27
+ num_pts=num_pts,
28
28
  )
29
- points = [
30
- (round(24 - utils.lon_to_ra(lon), 4), round(dec, 4)) for lon, dec in points
31
- ]
29
+ # points = [
30
+ # (round(24 - utils.lon_to_ra(lon), 4), round(dec, 4)) for lon, dec in points
31
+ # ]
32
+ points = [(round(lon, 4), round(dec, 4)) for lon, dec in points]
32
33
  return Polygon(points)
33
34
 
34
35
 
@@ -143,6 +144,51 @@ def split_polygon_at_zero(polygon: Polygon) -> list[Polygon]:
143
144
  return [polygon]
144
145
 
145
146
 
147
+ def split_polygon_at_360(polygon: Polygon) -> list[Polygon]:
148
+ """
149
+ Splits a polygon at 360 degrees
150
+
151
+ Args:
152
+ polygon: Polygon that possibly needs splitting
153
+
154
+ Returns:
155
+ List of polygons
156
+ """
157
+ ra, _ = [p for p in polygon.exterior.coords.xy]
158
+
159
+ if max(ra) > 360:
160
+ polygon_1 = polygon.intersection(
161
+ Polygon(
162
+ [
163
+ [0, -90],
164
+ [360, -90],
165
+ [360, 90],
166
+ [0, 90],
167
+ [0, -90],
168
+ ]
169
+ )
170
+ )
171
+
172
+ polygon_2 = polygon.intersection(
173
+ Polygon(
174
+ [
175
+ [360, -90],
176
+ [720, -90],
177
+ [720, 90],
178
+ [360, 90],
179
+ [360, -90],
180
+ ]
181
+ )
182
+ )
183
+
184
+ p2_ra, p2_dec = [p for p in polygon_2.exterior.coords.xy]
185
+ p2_new_ra = [ra - 360 for ra in p2_ra]
186
+
187
+ return [polygon_1, Polygon(list(zip(p2_new_ra, p2_dec)))]
188
+
189
+ return [polygon]
190
+
191
+
146
192
  def random_point_in_polygon(
147
193
  polygon: Polygon, max_iterations: int = 100, seed: int = None
148
194
  ) -> Point:
starplot/horizon.py CHANGED
@@ -3,9 +3,6 @@ import math
3
3
  from functools import cache
4
4
  from typing import Callable
5
5
 
6
- import pandas as pd
7
- import geopandas as gpd
8
-
9
6
  from cartopy import crs as ccrs
10
7
  from matplotlib import pyplot as plt, patches
11
8
  from matplotlib.ticker import FixedLocator, FuncFormatter
@@ -14,13 +11,14 @@ from shapely import Point, Polygon, MultiPolygon
14
11
  from starplot.coordinates import CoordinateSystem
15
12
  from starplot.base import BasePlot, DPI
16
13
  from starplot.mixins import ExtentMaskMixin
17
- from starplot.observer import Observer
14
+ from starplot.models.observer import Observer
18
15
  from starplot.plotters import (
19
16
  ConstellationPlotterMixin,
20
17
  StarPlotterMixin,
21
18
  DsoPlotterMixin,
22
19
  MilkyWayPlotterMixin,
23
20
  GradientBackgroundMixin,
21
+ LegendPlotterMixin,
24
22
  )
25
23
  from starplot.styles import (
26
24
  PlotStyle,
@@ -30,8 +28,6 @@ from starplot.styles import (
30
28
  GradientDirection,
31
29
  )
32
30
 
33
- pd.options.mode.chained_assignment = None # default='warn'
34
-
35
31
  DEFAULT_HORIZON_STYLE = PlotStyle().extend(extensions.MAP)
36
32
 
37
33
  DEFAULT_HORIZON_LABELS = {
@@ -49,11 +45,13 @@ DEFAULT_HORIZON_LABELS = {
49
45
  class HorizonPlot(
50
46
  BasePlot,
51
47
  ExtentMaskMixin,
48
+ # HorizonExtentMaskMixin,
52
49
  ConstellationPlotterMixin,
53
50
  StarPlotterMixin,
54
51
  DsoPlotterMixin,
55
52
  MilkyWayPlotterMixin,
56
53
  GradientBackgroundMixin,
54
+ LegendPlotterMixin,
57
55
  ):
58
56
  """Creates a new horizon plot.
59
57
 
@@ -122,6 +120,8 @@ class HorizonPlot(
122
120
  self.logger.debug("Creating HorizonPlot...")
123
121
  self.alt = altitude
124
122
  self.az = azimuth
123
+ self._alt = altitude
124
+ self._az = azimuth
125
125
  self.center_alt = sum(altitude) / 2
126
126
  self.center_az = sum(azimuth) / 2
127
127
 
@@ -155,16 +155,18 @@ class HorizonPlot(
155
155
  return pos_az.degrees, pos_alt.degrees
156
156
 
157
157
  def _prepare_star_coords(self, df, limit_by_altaz=True):
158
+ # import geopandas as gpd
159
+
158
160
  stars_apparent = self.observe(SkyfieldStar.from_dataframe(df)).apparent()
159
161
  nearby_stars_alt, nearby_stars_az, _ = stars_apparent.altaz()
160
162
  df["x"], df["y"] = (
161
163
  nearby_stars_az.degrees,
162
164
  nearby_stars_alt.degrees,
163
165
  )
164
- if limit_by_altaz:
165
- extent = self._extent_mask_altaz()
166
- df["_geometry_az_alt"] = gpd.points_from_xy(df.x, df.y)
167
- df = df[df["_geometry_az_alt"].intersects(extent)]
166
+ # if limit_by_altaz:
167
+ # extent = self._extent_mask_altaz()
168
+ # df["_geometry_az_alt"] = gpd.points_from_xy(df.x, df.y)
169
+ # df = df[df["_geometry_az_alt"].intersects(extent)]
168
170
 
169
171
  return df
170
172
 
@@ -373,6 +375,11 @@ class HorizonPlot(
373
375
  label,
374
376
  (x, patch_y + 0.027),
375
377
  xycoords=self.ax.transAxes,
378
+ xytext=(
379
+ style.label.offset_x * self.scale,
380
+ style.label.offset_y * self.scale,
381
+ ),
382
+ textcoords="offset points",
376
383
  **style.label.matplot_kwargs(self.scale),
377
384
  clip_on=False,
378
385
  )
@@ -427,7 +434,6 @@ class HorizonPlot(
427
434
  label_style_kwargs.pop("ha")
428
435
 
429
436
  line_style_kwargs = style.line.matplot_kwargs()
430
-
431
437
  gridlines = self.ax.gridlines(
432
438
  draw_labels=show_labels,
433
439
  x_inline=False,
@@ -492,7 +498,7 @@ class HorizonPlot(
492
498
  "|",
493
499
  (x, -0.011 * self.scale),
494
500
  xycoords=self.ax.transAxes,
495
- **self.style.gridlines.label.matplot_kwargs(self.scale / 2),
501
+ **style.label.matplot_kwargs(self.scale / 2),
496
502
  )
497
503
 
498
504
  @cache
starplot/map.py CHANGED
@@ -14,7 +14,7 @@ from starplot.coordinates import CoordinateSystem
14
14
  from starplot import geod
15
15
  from starplot.base import BasePlot, DPI
16
16
  from starplot.mixins import ExtentMaskMixin
17
- from starplot.observer import Observer
17
+ from starplot.models.observer import Observer
18
18
  from starplot.plotters import (
19
19
  ConstellationPlotterMixin,
20
20
  StarPlotterMixin,
@@ -459,10 +459,6 @@ class MapPlot(
459
459
  self.logger.debug(f"Projection = {self.projection.__class__.__name__.upper()}")
460
460
 
461
461
  self._fit_to_ax()
462
-
463
- # if self.gradient_preset:
464
- # self.apply_gradient_background(self.gradient_preset)
465
-
466
462
  self._plot_background_clip_path()
467
463
 
468
464
  def _ax_to_radec(self, x, y):
starplot/mixins.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from functools import cache
2
2
 
3
3
  from shapely import Polygon, MultiPolygon
4
+ from starplot.profile import profile
4
5
 
5
6
 
6
7
  class ExtentMaskMixin:
@@ -56,6 +57,288 @@ class ExtentMaskMixin:
56
57
  )
57
58
 
58
59
 
60
+ class HorizonExtentMaskMixin:
61
+ """Experimental"""
62
+
63
+ @cache
64
+ def _extent_mask_original(self):
65
+ """
66
+ Returns shapely geometry objects of extent (RA = 0...360)
67
+
68
+ If the extent crosses equinox, then a MultiPolygon will be returned
69
+ """
70
+ if self.ra_max <= 360:
71
+ coords = [
72
+ [self.ra_min, self.dec_min],
73
+ [self.ra_max, self.dec_min],
74
+ [self.ra_max, self.dec_max],
75
+ [self.ra_min, self.dec_max],
76
+ [self.ra_min, self.dec_min],
77
+ ]
78
+ return Polygon(coords)
79
+
80
+ else:
81
+ coords_1 = [
82
+ [self.ra_min, self.dec_min],
83
+ [360, self.dec_min],
84
+ [360, self.dec_max],
85
+ [self.ra_min, self.dec_max],
86
+ [self.ra_min, self.dec_min],
87
+ ]
88
+ coords_2 = [
89
+ [0, self.dec_min],
90
+ [(self.ra_max - 360), self.dec_min],
91
+ [(self.ra_max - 360), self.dec_max],
92
+ [0, self.dec_max],
93
+ [0, self.dec_min],
94
+ ]
95
+
96
+ return MultiPolygon(
97
+ [
98
+ Polygon(coords_1),
99
+ Polygon(coords_2),
100
+ ]
101
+ )
102
+
103
+ @cache
104
+ def _extent_mask2(self):
105
+ locations = [
106
+ self.location.at(self.observer.timescale).from_altaz(
107
+ alt_degrees=self.alt[0], az_degrees=self._az[0]
108
+ ), # lower left
109
+ self.location.at(self.observer.timescale).from_altaz(
110
+ alt_degrees=self.alt[0], az_degrees=self._az[1]
111
+ ), # lower right
112
+ self.location.at(self.observer.timescale).from_altaz(
113
+ alt_degrees=self.alt[1], az_degrees=self._az[1]
114
+ ), # upper right
115
+ self.location.at(self.observer.timescale).from_altaz(
116
+ alt_degrees=self.alt[1], az_degrees=self.center_az
117
+ ), # top center
118
+ # self.location.at(self.observer.timescale).from_altaz(
119
+ # alt_degrees=self.center_alt, az_degrees=self.center_az
120
+ # ), # center
121
+ self.location.at(self.observer.timescale).from_altaz(
122
+ alt_degrees=self.alt[1], az_degrees=self._az[0]
123
+ ), # upper left
124
+ self.location.at(self.observer.timescale).from_altaz(
125
+ alt_degrees=self.alt[0], az_degrees=self._az[0]
126
+ ), # lower left
127
+ ]
128
+
129
+ # self.ra_min = None
130
+ # self.ra_max = None
131
+ # self.dec_max = None
132
+ # self.dec_min = None
133
+ from pprint import pprint
134
+ from shapely import segmentize
135
+
136
+ self.location.at(self.observer.timescale).from_altaz(
137
+ alt_degrees=self.center_alt, az_degrees=self.center_az
138
+ ) # center
139
+ print(self.alt)
140
+ print(self._az)
141
+
142
+ coords = []
143
+ for location in locations:
144
+ ra, dec, _ = location.radec()
145
+ ra = ra.hours * 15
146
+ if ra < 180:
147
+ ra += 360
148
+ dec = dec.degrees
149
+ coords.append([float(ra), float(dec)])
150
+
151
+ pprint(coords)
152
+ # coords = reversed(coords)
153
+ extent = Polygon(coords)
154
+
155
+ extent = segmentize(extent, max_segment_length=2)
156
+
157
+ self.polygon(style__fill_color="red", style__alpha=0.3, geometry=extent)
158
+ # print(extent)
159
+
160
+ return extent
161
+
162
+ @profile
163
+ @cache
164
+ def _extent_mask2(self):
165
+ """generally working"""
166
+ coords = []
167
+
168
+ alt0, alt1 = self._alt
169
+ az0, az1 = self._az
170
+
171
+ for alt in range(0, 90, 5):
172
+ for az in range(az0 - 30, az1 + 30, 5):
173
+ ra, dec, _ = (
174
+ self.location.at(self.observer.timescale)
175
+ .from_altaz(alt_degrees=alt, az_degrees=az)
176
+ .radec()
177
+ )
178
+ ra = ra.hours * 15
179
+ if ra < 180:
180
+ ra += 360
181
+ dec = dec.degrees
182
+ coords.append([float(ra), float(dec)])
183
+
184
+ extent = Polygon(coords)
185
+ from shapely import segmentize
186
+
187
+ extent = segmentize(extent, max_segment_length=1)
188
+
189
+ self.polygon(style__fill_color="red", style__alpha=0.3, geometry=extent)
190
+ # print(extent)
191
+
192
+ return extent
193
+
194
+ @profile
195
+ @cache
196
+ def _extent_mask1(self):
197
+ from shapely import segmentize
198
+
199
+ mask_altaz = self._extent_mask_altaz()
200
+
201
+ altaz_polygons = []
202
+
203
+ if str(mask_altaz.geom_type) == "MultiPolygon":
204
+ altaz_polygons = [
205
+ segmentize(p, max_segment_length=5) for p in mask_altaz.geoms
206
+ ]
207
+ else:
208
+ altaz_polygons = [segmentize(mask_altaz, max_segment_length=5)]
209
+
210
+ radec_polygons = []
211
+
212
+ for p in altaz_polygons:
213
+ coords = []
214
+
215
+ for az, alt in list(zip(*p.exterior.coords.xy)):
216
+ ra, dec, _ = (
217
+ self.location.at(self.observer.timescale)
218
+ .from_altaz(alt_degrees=alt, az_degrees=az)
219
+ .radec()
220
+ )
221
+ ra = ra.hours * 15
222
+ if ra < 180:
223
+ ra += 360
224
+ dec = dec.degrees
225
+ coords.append([float(ra), float(dec)])
226
+
227
+ radec_polygons.append(Polygon(coords))
228
+
229
+ mp = MultiPolygon(radec_polygons)
230
+ extent = mp.convex_hull
231
+
232
+ # extent = segmentize(extent, max_segment_length=1)
233
+
234
+ print(extent.area)
235
+
236
+ # self.polygon(
237
+ # style__fill_color="red",
238
+ # style__alpha=0.3,
239
+ # geometry=extent
240
+ # )
241
+ # print(extent)
242
+
243
+ return extent
244
+
245
+ def _axes_to_azalt(self, x: float, y: float) -> tuple[float, float]:
246
+ trans = self.ax.transAxes + self.ax.transData.inverted()
247
+ x_projected, y_projected = self.ax.transAxes.inverted().transform((x, y))
248
+ x_projected, y_projected = trans.transform((x, y)) # axes to data
249
+ az, alt = self._crs.transform_point(x_projected, y_projected, self._proj)
250
+ return float(az), float(alt)
251
+
252
+ @profile
253
+ @cache
254
+ def _extent_mask(self):
255
+ coords = []
256
+ azalt = []
257
+
258
+ az0, az1 = int(self.az[0]), int(self.az[1])
259
+ alt0, alt1 = int(self.alt[0]), int(self.alt[1])
260
+
261
+ for az in range(az0, az1, 5):
262
+ for alt in range(alt0, alt1, 5):
263
+ # ax = x / 100
264
+ # ay = y / 100
265
+
266
+ # az, alt = self._axes_to_azalt(ax, ay)
267
+
268
+ if az > 360:
269
+ az -= 360
270
+
271
+ azalt.append([az, alt])
272
+ ra, dec, _ = (
273
+ self.location.at(self.observer.timescale)
274
+ .from_altaz(alt_degrees=alt, az_degrees=az)
275
+ .radec()
276
+ )
277
+ ra = float(ra.hours * 15)
278
+ dec = float(dec.degrees)
279
+
280
+ if dec > 75:
281
+ dec = 90
282
+
283
+ if ra < 180:
284
+ ra += 360
285
+ coords.append([float(ra), float(dec)])
286
+
287
+ # if prev_ra is not None and abs(ra - prev_ra) > 180:
288
+ # current_polygon_coords += [current_polygon_coords[0]]
289
+ # polygon_coords.append(
290
+ # current_polygon_coords
291
+ # )
292
+ # current_polygon_coords = [[ra, dec]]
293
+ # else:
294
+ # current_polygon_coords.append([ra, dec])
295
+
296
+ # prev_ra = ra
297
+
298
+ # if current_polygon_coords:
299
+ # current_polygon_coords += [current_polygon_coords[0]]
300
+ # polygon_coords.append(current_polygon_coords)
301
+ # print(current_polygon_coords)
302
+
303
+ # print(len(polygon_coords))
304
+ from starplot.geometry import split_polygon_at_360
305
+
306
+ # polygons = split_polygon_at_zero(extent)
307
+
308
+ from shapely import convex_hull, MultiPoint
309
+ from pprint import pprint
310
+
311
+ # extent = MultiPolygon([Polygon(c) for c in polygon_coords])
312
+ # extent = Polygon(coords)
313
+ extent = convex_hull(MultiPoint(coords))
314
+ polygons = split_polygon_at_360(extent)
315
+
316
+ pprint(polygons)
317
+
318
+ # extent = extent.convex_hull
319
+ # from shapely import segmentize
320
+ # polygons = [segmentize(p, max_segment_length=1) for p in polygons]
321
+ mpoly = MultiPolygon(polygons)
322
+
323
+ for p in mpoly.geoms:
324
+ self.polygon(style__fill_color="red", style__alpha=0.3, geometry=p)
325
+
326
+ # print(extent)
327
+
328
+ return mpoly
329
+
330
+ def _is_global_extent(self):
331
+ """Returns True if the plot's RA/DEC range is the entire celestial sphere"""
332
+ return all(
333
+ [
334
+ self.ra_min == 0,
335
+ self.ra_max == 360,
336
+ self.dec_min == -90,
337
+ self.dec_max == 90,
338
+ ]
339
+ )
340
+
341
+
59
342
  class CreateMapMixin:
60
343
  def create_map(self, height_degrees: float, width_degrees: float, *args, **kwargs):
61
344
  """
@@ -1,7 +1,19 @@
1
- from .constellation import Constellation # noqa: F401,F403
2
- from .dso import DSO, DsoType # noqa: F401,F403
3
- from .star import Star # noqa: F401,F403
4
- from .planet import Planet # noqa: F401,F403
5
- from .moon import Moon # noqa: F401,F403
6
- from .sun import Sun # noqa: F401,F403
7
- from .objects import ObjectList # noqa: F401,F403
1
+ # ruff: noqa: F401,F403
2
+ from .constellation import Constellation
3
+ from .comet import Comet
4
+ from .dso import DSO, DsoType
5
+ from .star import Star
6
+ from .planet import Planet
7
+ from .moon import Moon
8
+ from .sun import Sun
9
+ from .optics import (
10
+ Optic,
11
+ Scope,
12
+ Reflector,
13
+ Refractor,
14
+ Binoculars,
15
+ Camera,
16
+ )
17
+ from .objects import ObjectList
18
+ from .satellite import Satellite
19
+ from .observer import Observer