Skip to content

Commit

Permalink
Allow Horizon constraints to use lists instead of tuples (#413)
Browse files Browse the repository at this point in the history
Closes #394

Awesome, thanks @jermainegug !
  • Loading branch information
jermainegug authored and wtgee committed Jan 24, 2018
1 parent 2cff654 commit e366ec5
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 47 deletions.
44 changes: 22 additions & 22 deletions examples/notebooks/Horizon Obstruction Limits.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
"\n",
"This notebook will demonstrate how the horizon line works.\n",
"\n",
"A `Horizon` accepts a list of `obstruction_points` as well as a `base_horizon` (with 30° as default). The `obstruction_points` is a list of at least two tuples where each tuple is an alt/az coordinate. The idea is that you are defining a list of obstructions that will be interpolated between the given points. Thus, you have a \"start\" point and an \"end\" point (given in alt/az) for each obstruction. You can have as many obstructions as you want and obstructions can also contain \"middle\" points. See examples below for more details.\n",
"A `Horizon` accepts a list of `obstruction_points` as well as a `default_horizon` (with 30° as default). The `obstruction_points` is a list of at least two tuples where each tuple is an alt/az coordinate. The idea is that you are defining a list of obstructions that will be interpolated between the given points. Thus, you have a \"start\" point and an \"end\" point (given in alt/az) for each obstruction. You can have as many obstructions as you want and obstructions can also contain \"middle\" points. See examples below for more details.\n",
"\n",
"The `Horizon` class automatically builds a `horizon_line` that is a list with 360 elements where each index of the list corresponds to an azimuth degree (0-360) and the value corresponds to the minimum allowed altitude for that azimuth.\n",
"\n",
"An example `obstruction_point` list might be (see below for plot of this example):\n",
"```\n",
"[\n",
" ((40, 30), (40, 75)), # From azimuth 30° to 75° there is an \n",
" [[40, 30], [40, 75]], # From azimuth 30° to 75° there is an \n",
" # obstruction that is at 40° altitude \n",
" ((50, 180), (40, 200)), # From azimuth 180° to 200° there is \n",
" [[50, 180], [40, 200]], # From azimuth 180° to 200° there is \n",
" # an obstruction that slopes from 50° \n",
" # to 40° altitude\n",
"]\n",
Expand Down Expand Up @@ -173,8 +173,8 @@
"source": [
"# Intro example\n",
"points = [\n",
" ((40, 30), (40, 75)), \n",
" ((50, 180), (40, 200))\n",
" [[40, 30], [40, 75]], \n",
" [[50, 180], [40, 200]]\n",
"]\n",
"h3 = Horizon(points)\n",
"plot_horizon(h3.horizon_line)"
Expand All @@ -199,11 +199,11 @@
"source": [
"# Example with three points\n",
"points = [\n",
" ((25.0, 50.0), (25.0, 100.0)), # Below base horizon\n",
" ((40.0, 180.0), (50.0, 190.0), (45., 200.)), # Three points\n",
" ((33.0, 10.0), (40.0, 20.0)), \n",
" [[25.0, 50.0], [25.0, 100.0]], # Below default horizon\n",
" [[40.0, 180.0], [50.0, 190.0], [45., 200.]], # Three points\n",
" [[33.0, 10.0], [40.0, 20.0]], \n",
"]\n",
"h4 = Horizon(points, base_horizon=33)\n",
"h4 = Horizon(points, default_horizon=33)\n",
"plot_horizon(h4.horizon_line)"
]
},
Expand All @@ -226,7 +226,7 @@
"source": [
"# Radio tower\n",
"points = [\n",
" ((75.0, 300.0), (75.0, 302.0)),\n",
" [[75.0, 300.0], [75.0, 302.0]],\n",
"]\n",
"plot_horizon(Horizon(points).horizon_line)"
]
Expand All @@ -250,15 +250,15 @@
"source": [
"# Funky buildings; overlapping azimuths, negative azimuths; out of order\n",
"points = [\n",
" ((75.0, 300.0), (75.0, 305.0)), # Far right overlapping\n",
" ((70.0, 295.0), (60.0, 310.0)),\n",
" [[75.0, 300.0], [75.0, 305.0]], # Far right overlapping\n",
" [[70.0, 295.0], [60.0, 310.0]],\n",
" \n",
" ((75.0, -165.0), (75.0, -160.0)), # Middle funky\n",
" ((70.0, -165.0), (60.0, -150.0)), \n",
" [[75.0, -165.0], [75.0, -160.0]], # Middle funky\n",
" [[70.0, -165.0], [60.0, -150.0]], \n",
" \n",
" ((75.0, 15.0), (75.0, 25.0)), # Left side 1\n",
" ((65.0, 55.0), (65.0, 65.0)), # Left side 2 \n",
" ((55.0, 105.0), (55.0, 115.0)), # Left side 3 \n",
" [[75.0, 15.0], [75.0, 25.0]], # Left side 1\n",
" [[65.0, 55.0], [65.0, 65.0]], # Left side 2 \n",
" [[55.0, 105.0], [55.0, 115.0]], # Left side 3 \n",
"]\n",
"plot_horizon(Horizon(points).horizon_line)"
]
Expand All @@ -282,11 +282,11 @@
"source": [
"# Pyramids! Note order of obstruction points doesn't matter\n",
"points = [\n",
" ((10.0, 50.0), (45., 80.), (10.0, 110.0)), # Big\n",
" ((10.0, 300.0), (25., 320.), (10.0, 340.0)), # Medium\n",
" ((10.0, 200.0), (15., 205.), (10.0, 210.0)), # Tiny\n",
" [[10.0, 50.0], [45., 80.], [10.0, 110.0]], # Big\n",
" [[10.0, 300.0], [25., 320.], [10.0, 340.0]], # Medium\n",
" [[10.0, 200.0], [15., 205.], [10.0, 210.0]], # Tiny\n",
"]\n",
"plot_horizon(Horizon(points, base_horizon=10).horizon_line)"
"plot_horizon(Horizon(points, default_horizon=10).horizon_line)"
]
},
{
Expand All @@ -309,7 +309,7 @@
"# Random horizon\n",
"import random\n",
"range_length = 360\n",
"points = [tuple(zip(\n",
"points = [list(list(a) for a in zip(\n",
" [random.randrange(15, 50) for _ in range(range_length)], # Random height\n",
" np.arange(1, range_length, 25) # Set azimuth\n",
" ))]\n",
Expand Down
4 changes: 2 additions & 2 deletions pocs/tests/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def test_custom_altitude(observer, field_list, horizon_line):
# Then check veto with block
horizon_line = horizon_utils.Horizon(
obstructions=[
((40, 70), (40, 80))
[[40, 70], [40, 80]]
],
)
ac = Altitude(horizon_line)
Expand All @@ -156,7 +156,7 @@ def test_big_wall(observer, field_list):
time = Time('2018-01-19 07:10:00')
horizon_line = horizon_utils.Horizon(
obstructions=[
((90, 0), (90, 359))
[[90, 0], [90, 359]]
],
)

Expand Down
30 changes: 15 additions & 15 deletions pocs/tests/test_horizon_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

def test_normal():
hp = Horizon(obstructions=[
((20, 10), (40, 70))
[[20, 10], [40, 70]]
])
assert isinstance(hp, Horizon)

hp2 = Horizon(obstructions=[
((40, 45), (50, 50), (60, 45))
[[40, 45], [50, 50], [60, 45]]
])
assert isinstance(hp2, Horizon)

Expand All @@ -23,37 +23,37 @@ def test_normal():
def test_bad_length_tuple():
with pytest.raises(AssertionError):
Horizon(obstructions=[
((20), (40, 70))
[[20], [40, 70]]
])


def test_bad_length_list():
with pytest.raises(AssertionError):
Horizon(obstructions=[
((40, 70))
[[40, 70]]
])


def test_bad_string():
with pytest.raises(AssertionError):
Horizon(obstructions=[
(("x", 10), (40, 70))
[["x", 10], [40, 70]]
])


def test_too_many_points():
with pytest.raises(AssertionError):
Horizon(obstructions=[((120, 60, 300))])
Horizon(obstructions=[[[120, 60, 300]]])


def test_wrong_bool():
with pytest.raises(AssertionError):
Horizon(obstructions=[((20, 200), (30, False))])
Horizon(obstructions=[[[20, 200], [30, False]]])


def test_numpy_ints():
range_length = 360
points = [tuple(zip(
points = [list(list(a) for a in zip(
[random.randrange(15, 50) for _ in range(range_length)], # Random height
np.arange(1, range_length, 25) # Set azimuth
))]
Expand All @@ -64,34 +64,34 @@ def test_numpy_ints():
def test_negative_alt():
with pytest.raises(AssertionError):
Horizon(obstructions=[
((10, 20), (-1, 30))
[[10, 20], [-1, 30]]
])


def test_good_negative_az():
hp = Horizon(obstructions=[
((50, -10), (45, -20))
[[50, -10], [45, -20]]
])
assert isinstance(hp, Horizon)

hp2 = Horizon(obstructions=[
((10, -181), (20, -190))
[[10, -181], [20, -190]]
])
assert isinstance(hp2, Horizon)


def test_bad_negative_az():
with pytest.raises(AssertionError):
Horizon(obstructions=[
((10, -361), (20, -350))
[[10, -361], [20, -350]]
])


def test_sorting():
points = [
((10., 10.), (20., 20.)),
((30., 190.), (10., 180.)),
((10., 50.), (30., 60.)),
[[10., 10.], [20., 20.]],
[[30., 190.], [10., 180.]],
[[10., 50.], [30., 60.]],
]
hp = Horizon(obstructions=points)
assert hp.obstructions == [[(10.0, 10.0), (20.0, 20.0)],
Expand Down
16 changes: 8 additions & 8 deletions pocs/utils/horizon.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class Horizon(object):
"""A simple class to define some coordinate points.
Accepts a list of tuples where each tuple consists of two points corresponding
Accepts a list of lists where each list consists of two points corresponding
to an altitude (0-90) and an azimuth (0-360). If azimuth is a negative number
(but greater than -360) then 360 will be added to put it in the correct
range.
Expand All @@ -20,18 +20,18 @@ def __init__(self, obstructions=list(), default_horizon=30):
An example `obstruction_point` list:
```
[
((40, 30), (40, 75)), # From azimuth 30° to 75° there is an
[[40, 30], [40, 75]], # From azimuth 30° to 75° there is an
# obstruction that is at 40° altitude
((50, 180), (40, 200)), # From azimuth 180° to 200° there is
[[50, 180], [40, 200]], # From azimuth 180° to 200° there is
# an obstruction that slopes from 50°
# to 40° altitude
]
```
Args:
obstructions (list(tuple(tuple)), optional): A list of obstructions
where each obstruction consists of a set of tuples. The individual
tuples are alt/az pairs. Defaults to empty list in which case the
obstructions (list(list(list)), optional): A list of obstructions
where each obstruction consists of a set of lists. The individual
lists are alt/az pairs. Defaults to empty list in which case the
`default_horizon` defines a flat horizon.
default_horizon (float, optional): A default horizon to be used whenever
there is no obstruction.
Expand All @@ -41,12 +41,12 @@ def __init__(self, obstructions=list(), default_horizon=30):

obstruction_list = list()
for obstruction in obstructions:
assert isinstance(obstruction, tuple), "Obstructions must be tuples"
assert isinstance(obstruction, list), "Obstructions must be lists"
assert len(obstruction) >= 2, "Obstructions must have at least 2 points"

obstruction_line = list()
for point in obstruction:
assert isinstance(point, tuple), "Obstruction points must be tuples"
assert isinstance(point, list), "Obstruction points must be lists"
assert len(point) == 2, "Obstruction points must be 2 points"

assert type(point[0]) is not bool, "Bool not allowed"
Expand Down

0 comments on commit e366ec5

Please sign in to comment.