@@ -316,22 +316,38 @@ def _add_tan_pts_if_in_pa_range(
316316 return coord_list
317317
318318
319- def _validate_vertices_ordering (verts , gc , centroid ):
320- pas_verts = gc .center .position_angle (verts ).to (u .deg )
319+ def _check_edge_lt_pi (pas_verts , wrap_ang ):
320+ pas_verts_wrap = pas_verts .wrap_at (wrap_ang )
321+
322+ is_valid_arc_length = ((pas_verts_wrap [1 ] - pas_verts_wrap [0 ]).to (u .deg ) <= 180 * u .deg )
323+
324+ return pas_verts_wrap , is_valid_arc_length
325+
326+
327+ def _validate_vertices_ordering (verts , gc , gc_center = None ):
328+ if gc is not None :
329+ gc_center = gc .center
330+ pas_verts = gc_center .position_angle (verts ).to (u .deg )
321331
322- # Check ordering of vertices pas:
323- pa_centroid = gc .center .position_angle (centroid ).to (u .deg )
324332 wrap_ang = pas_verts [0 ]
325- pas_verts_wrap = pas_verts .wrap_at (wrap_ang )
326- pa_centroid_wrap = pa_centroid .wrap_at (wrap_ang )
327- in_range_lon = (pa_centroid_wrap >= pas_verts_wrap [0 ]) & (
328- pa_centroid_wrap <= pas_verts_wrap [1 ]
329- )
330- if not in_range_lon :
331- # If not in range, invert the vertices PA ordering:
332- pas_verts = pas_verts [::- 1 ]
333- wrap_ang = pas_verts [0 ]
334- pas_verts_wrap = pas_verts .wrap_at (wrap_ang )
333+
334+ # Check ordering of vertices pas:
335+
336+ # Principle: ALL EDGES must be <= 180 deg of length
337+ # So difference of pa[1] - pa[0] <= 180 deg
338+ # If not, swap the order.
339+
340+ pas_verts_wrap , is_valid_arc_length = _check_edge_lt_pi (pas_verts , wrap_ang )
341+
342+ if not is_valid_arc_length :
343+ wrap_ang_opp = pas_verts [- 1 ]
344+ pas_verts_wrap_opp , is_valid_arc_length_opp = _check_edge_lt_pi (
345+ pas_verts [::- 1 ], wrap_ang_opp
346+ )
347+ if is_valid_arc_length_opp :
348+ return pas_verts_wrap_opp , wrap_ang_opp
349+
350+ raise ValueError ('Invalid arc' ) # should never occur
335351
336352 return pas_verts_wrap , wrap_ang
337353
@@ -400,7 +416,7 @@ def get_edge_raw_lonlat_bounds_circ_edges(vertices, centroid, gcs):
400416 # PAs from gc center to vertices:
401417 verts = SkyCoord (np .concatenate ([[vertices [i - 1 ]], [vertices [i ]]]))
402418
403- pas_verts_wrap , wrap_ang = _validate_vertices_ordering (verts , gc , centroid )
419+ pas_verts_wrap , wrap_ang = _validate_vertices_ordering (verts , gc )
404420
405421 # --------------------------------------------------------
406422 # Latitude tangent points from bound circle as len 2 SkyCoord:
@@ -409,7 +425,8 @@ def get_edge_raw_lonlat_bounds_circ_edges(vertices, centroid, gcs):
409425 tan_lat_pts = _get_circle_latitude_tangent_points (gc .center , gc .radius )
410426
411427 lats_list = _add_tan_pts_if_in_pa_range (
412- lats_list , tan_lat_pts , gc , wrap_ang , pas_verts_wrap , coord = 'lat'
428+ lats_list , tan_lat_pts , gc , wrap_ang , pas_verts_wrap ,
429+ coord = 'lat'
413430 )
414431
415432 # --------------------------------------------------------
@@ -419,7 +436,8 @@ def get_edge_raw_lonlat_bounds_circ_edges(vertices, centroid, gcs):
419436 tan_lon_pts = _get_circle_longitude_tangent_points (gc .center , gc .radius )
420437 if tan_lon_pts is not None :
421438 lons_list = _add_tan_pts_if_in_pa_range (
422- lons_list , tan_lon_pts , gc , wrap_ang , pas_verts_wrap , coord = 'lon'
439+ lons_list , tan_lon_pts , gc , wrap_ang , pas_verts_wrap ,
440+ coord = 'lon'
423441 )
424442
425443 lons_arr = [lons_list .min (), lons_list .max ()]
@@ -432,7 +450,13 @@ def get_edge_raw_lonlat_bounds_circ_edges(vertices, centroid, gcs):
432450 return Longitude (lons_arr ).to (u .deg ), Latitude (lats_arr ).to (u .deg )
433451
434452
435- def _discretize_edge_boundary (vertices , circ , centroid , n_points ):
453+ def _discretize_edge_boundary (vertices , circ , n_points ,
454+ circ_center = None , circ_radius = None ):
455+
456+ if circ is not None :
457+ circ_center = circ .center
458+ circ_radius = circ .radius
459+
436460 # Discretize an edge boundary defined by a circle, geodetic or not:
437461 # either great circle arc, or a span of a non-great circle
438462 # (e.g., constant lat edges of RangeSphericalSkyRegion)
@@ -441,7 +465,9 @@ def _discretize_edge_boundary(vertices, circ, centroid, n_points):
441465 # connecting circle center to the two vertices bounding that edge:
442466 pas_verts = circ .center .position_angle (vertices ).to (u .deg )
443467
444- pas_verts_wrap , wrap_ang = _validate_vertices_ordering (vertices , circ , centroid )
468+ pas_verts_wrap , wrap_ang = _validate_vertices_ordering (
469+ vertices , circ , gc_center = circ_center ,
470+ )
445471
446472 # Need to wrap angles to calculate span: wrap at lower value:
447473 pas_verts_wrap = pas_verts .wrap_at (wrap_ang )
@@ -453,12 +479,47 @@ def _discretize_edge_boundary(vertices, circ, centroid, n_points):
453479
454480 # Calculate directional offsets to get boundary discretization,
455481 # with vertices as SkyCoords
456- bound_verts = circ .center .directional_offset_by (theta , circ . radius )
482+ bound_verts = circ .center .directional_offset_by (theta , circ_radius )
457483
458484 return bound_verts
459485
460486
461- def discretize_all_edge_boundaries (vertices , circs , centroid , n_points ):
487+ def discretize_line_boundary (coords , n_points ):
488+ """
489+ Discretize all edge boundaries for spherical sky regions.
490+
491+ Parameters
492+ ----------
493+ coords : `~astropy.coordinates.SkyCoord`
494+ The start, end of the line as a SkyCoord.
495+
496+ n_points : int
497+ The number of points for discretization along each edge.
498+
499+ Returns
500+ -------
501+ edge_bound_verts : `~astropy.coordinates.SkyCoord`
502+ The discretized boundary edge vertices.
503+ """
504+ # Iterate over full set of vertices & boundary circles for
505+ # a region (polygon or range)
506+
507+ gc_center = cross_product_skycoord2skycoord (coords [0 ], coords [1 ])
508+ gc_radius = 90 * u .deg
509+
510+ bound_verts = _discretize_edge_boundary (coords , None , n_points ,
511+ circ_center = gc_center , circ_radius = gc_radius )
512+
513+ return SkyCoord (
514+ SkyCoord (
515+ bound_verts ,
516+ representation_type = UnitSphericalRepresentation ,
517+ ),
518+ representation_type = SphericalRepresentation ,
519+ )
520+
521+
522+ def discretize_all_edge_boundaries (vertices , circs , n_points ):
462523 """
463524 Discretize all edge boundaries for spherical sky regions.
464525
@@ -470,9 +531,6 @@ def discretize_all_edge_boundaries(vertices, circs, centroid, n_points):
470531 circs : `~regions.CircleSphericalSkyRegion`
471532 The circle boundaries as CircleSphericalSkyRegion instances.
472533
473- centroid : `~astropy.coordinates.SkyCoord`
474- The region centroid as a SkyCoord.
475-
476534 n_points : int
477535 The number of points for discretization along each edge.
478536
@@ -489,7 +547,7 @@ def discretize_all_edge_boundaries(vertices, circs, centroid, n_points):
489547 # PAs from gc center to vertices:
490548 verts = SkyCoord (np .concatenate ([[vertices [i - 1 ]], [vertices [i ]]]))
491549
492- bound_verts = _discretize_edge_boundary (verts , circ , centroid , n_points )
550+ bound_verts = _discretize_edge_boundary (verts , circ , n_points )
493551
494552 if all_edge_bound_verts is None :
495553 all_edge_bound_verts = bound_verts
0 commit comments