1
0
Fork 0

Window calculations on new observations and view.

merge-requests/64/head
Pierros Papadeas 2014-10-26 20:07:42 +00:00
parent 14275ba484
commit 60c7ba424d
7 changed files with 232 additions and 39 deletions

View File

@ -5,7 +5,7 @@ from django.shortcuts import get_object_or_404, render
from django.utils.timezone import now
from django.http import JsonResponse
from .models import Station, Observation, Data, Satellite
from .models import Station, Transponder, Observation, Data, Satellite
def index(request):
@ -29,13 +29,22 @@ def observations_list(request):
return render(request, 'base/observations.html', {'observations': observations})
def observation_new(request):
"""View for new observation"""
satellites = Satellite.objects.all()
transponders = Transponder.objects.filter(alive=True)
return render(request, 'base/observation_new.html', {'satellites': satellites,
'transponders': transponders})
def prediction_windows(request, sat_id, start_date, end_date):
sat = get_object_or_404(Satellite, norad_cat_id=sat_id)
satellite = ephem.readtle(str(sat.tle0), str(sat.tle1), str(sat.tle2))
end_date = datetime.strptime(end_date, '%Y-%m-%d %H:%M')
data = {'windows': []}
data = []
stations = Station.objects.all()
for station in stations:
@ -45,58 +54,41 @@ def prediction_windows(request, sat_id, start_date, end_date):
observer.elevation = station.alt
observer.date = str(start_date)
station_match = False
while True:
satellite.compute(observer)
window = observer.next_pass(satellite)
keep_digging = True
while keep_digging:
tr, azr, tt, altt, ts, azs = observer.next_pass(satellite)
if not _check_window_sanity(window):
window_new = list(window)
window_new[0] = window[4] # replace 0 with 4
window_new[1] = window[1]
window_new[2] = window[2]
window_new[3] = window[3]
window_new[4] = window[0] # replace 4 with 0
window_new[5] = window[5]
window = window_new
if ephem.Date(window[0]).datetime() < end_date:
if ephem.Date(tr).datetime() < end_date:
if not station_match:
station_windows = {
'station_id': station.id,
'station_name': station.name,
'id': station.id,
'name': station.name,
'window': []
}
station_match = True
if ephem.Date(ts).datetime() > end_date:
ts = end_date
keep_digging = False
else:
time_start_new = ephem.Date(ts).datetime() + timedelta(minutes=1)
observer.date = time_start_new.strftime("%Y-%m-%d %H:%M:%S.%f")
station_windows['window'].append(
{
'start': ephem.Date(window[0]).datetime().strftime("%Y-%m-%d %H:%M:%S.%f"),
'end': ephem.Date(window[4]).datetime().strftime("%Y-%m-%d %H:%M:%S.%f"),
'az_start': window[1]
'start': ephem.Date(tr).datetime().strftime("%Y-%m-%d %H:%M:%S.%f"),
'end': ephem.Date(ts).datetime().strftime("%Y-%m-%d %H:%M:%S.%f"),
'az_start': azr
})
if ephem.Date(window[4]).datetime() > end_date:
# window end outside of window bounds; break
break
else:
time_start_new = ephem.Date(window[4]).datetime() + timedelta(seconds=1)
observer.date = time_start_new.strftime("%Y-%m-%d %H:%M:%S.%f")
else:
# window start outside of window bounds
break
if station_match:
data['windows'].append(station_windows)
data.append(station_windows)
return JsonResponse(data)
def _check_window_sanity(window):
"""
Weird bug in ephem library's next_pass function
returns set time earlier than rise time, leads to infinite loop
"""
if ephem.Date(window[0]).datetime() > ephem.Date(window[4]).datetime():
return False
return True
return JsonResponse(data, safe=False)
def view_observation(request, id):

View File

@ -0,0 +1,5 @@
/*!
* Datetimepicker for Bootstrap v3
//! version : 3.1.3
* https://github.com/Eonasdan/bootstrap-datetimepicker/
*/.bootstrap-datetimepicker-widget{top:0;left:0;width:250px;padding:4px;margin-top:1px;z-index:99999!important;border-radius:4px}.bootstrap-datetimepicker-widget.timepicker-sbs{width:600px}.bootstrap-datetimepicker-widget.bottom:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:7px}.bootstrap-datetimepicker-widget.bottom:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:8px}.bootstrap-datetimepicker-widget.top:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.top:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;position:absolute;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget .dow{width:14.2857%}.bootstrap-datetimepicker-widget.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget>ul{list-style-type:none;margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:700;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator{width:4px;padding:0;margin:0}.bootstrap-datetimepicker-widget .datepicker>div{display:none}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget td,.bootstrap-datetimepicker-widget th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget td.cw{font-size:10px;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget td.day:hover,.bootstrap-datetimepicker-widget td.hour:hover,.bootstrap-datetimepicker-widget td.minute:hover,.bootstrap-datetimepicker-widget td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget td.old,.bootstrap-datetimepicker-widget td.new{color:#777}.bootstrap-datetimepicker-widget td.today{position:relative}.bootstrap-datetimepicker-widget td.today:before{content:'';display:inline-block;border-left:7px solid transparent;border-bottom:7px solid #428bca;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget td.active,.bootstrap-datetimepicker-widget td.active:hover{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget td.disabled,.bootstrap-datetimepicker-widget td.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget td span:hover{background:#eee}.bootstrap-datetimepicker-widget td span.active{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td span.old{color:#777}.bootstrap-datetimepicker-widget td span.disabled,.bootstrap-datetimepicker-widget td span.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget th.picker-switch{width:145px}.bootstrap-datetimepicker-widget th.next,.bootstrap-datetimepicker-widget th.prev{font-size:21px}.bootstrap-datetimepicker-widget th.disabled,.bootstrap-datetimepicker-widget th.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget thead tr:first-child th:hover{background:#eee}.input-group.date .input-group-addon span{display:block;cursor:pointer;width:16px;height:16px}.bootstrap-datetimepicker-widget.left-oriented:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.left-oriented:after{left:auto;right:7px}.bootstrap-datetimepicker-widget ul.list-unstyled li div.timepicker div.timepicker-picker table.table-condensed tbody>tr>td{padding:0!important}@media screen and (max-width:767px){.bootstrap-datetimepicker-widget.timepicker-sbs{width:283px}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,78 @@
$(function () {
$('#datetimepicker-start').datetimepicker();
$('#datetimepicker-end').datetimepicker();
$('#satellite-selection').change( function() {
var norad = $(this).find(':selected').data("norad");
$('#transponder-selection').prop("disabled", false);
$('#transponder-selection option').hide();
$('#transponder-selection option[data-satellite="'+norad+'"]').show().prop("selected", true);
if($('#transponder-selection option:visible').length === 0) {
$('#transponder-selection').prop("disabled", true);
$('#transponder-selection option[id="no-transponder"]').show().prop("selected", true);
}
});
});
$( document ).ready( function(){
$('#calculate-observation').click( function(){
var satellite = $('#satellite-selection').val();
var start_time = $('#datetimepicker-start input').val();
var end_time = $('#datetimepicker-end input').val();
$.ajax({
url: '/prediction_windows/'+satellite+'/'+start_time+'/'+end_time
}).done(function(data) {
var suggested_data = [];
$.each(data, function( i,k ){
label = k.id + " - " + k.name;
var times = [];
console.log(k);
$.each(k.window, function( m,n ){
var starting_time = moment(n.start).valueOf();
var ending_time = moment(n.end).valueOf();
times.push({starting_time: starting_time, ending_time: ending_time})
});
suggested_data.push({label : label, times : times});
//console.log(k);
//console.log(k.name);
});
/*data.each(function( index ){
var data_groundstation = $(this).data('groundstation');
var data_time_start = 1000 * $(this).data('start');
var data_time_end = 1000 * $(this).data('end');
observation_data.push({label : data_groundstation, times : [{starting_time: data_time_start, ending_time: data_time_end}]});
});*/
timeline_init(start_time, end_time, suggested_data);
});
});
});
function timeline_init( start, end, payload ){
var start_time_timeline = moment(start).valueOf();
var end_time_timeline = moment(end).valueOf();
$('#timeline').empty();
var chart = d3.timeline()
.stack()
.beginning(start_time_timeline)
.ending(end_time_timeline)
.hover(function (d, i, datum) {
// d is the current rendering object
// i is the index during d3 rendering
// datum is the id object
var div = $('#hoverRes');
var colors = chart.colors();
div.find('.coloredDiv').css('background-color', colors(i))
div.find('#name').text(datum.label);
})
.margin({left:140, right:10, top:0, bottom:50})
.tickFormat({format: d3.time.format("%H:%M"), tickTime: d3.time.minutes, tickInterval: 30, tickSize: 6})
;
var svg = d3.select("#timeline").append("svg").attr("width", 1140)
.datum(payload).call(chart);
}

View File

@ -0,0 +1,109 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}New Observation{% endblock %}
{% block css %}
<link href="{% static 'css/bootstrap-datetimepicker.min.css' %}" rel="stylesheet">
{% endblock css %}
{% block content %}
<div class="row">
<div class="col-md-12">
<h2>New Observation</h2>
</div>
</div>
<div class="row">
<form class="form-horizontal" role="form">
<div class="col-md-6">
<div class="form-group">
<label class="col-sm-3 control-label">Satellite</label>
<div class="col-sm-9">
<select id="satellite-selection" class="form-control" name="satellite">
<option value="" disabled selected>Select a satellite</option>
{% for satellite in satellites %}
<option data-norad="{{ satellite.norad_cat_id }}" value="{{ satellite.norad_cat_id }}">
{{ satellite.norad_cat_id }} - {{ satellite.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Transponder</label>
<div class="col-sm-9">
<select id="transponder-selection" class="form-control" disabled name="transponder" >
<option id="no-transponder" value="" disabled selected>No transponder available</option>
{% for transponder in transponders %}
<option data-satellite="{{ transponder.satellite.norad_cat_id }}"
value="{{ transponder.satellite.norad_cat_id }}">
{{ transponder.description }} - {{ transponder.downlink_low}} - {{ transponder.mode }}
</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="col-sm-3 control-label">Start Time</label>
<div class="col-sm-9">
<div class='input-group date' id='datetimepicker-start'>
<input type="text"
class="form-control"
name="start-time"
data-date-format="YYYY-MM-DD HH:mm" />
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">End Time</label>
<div class="col-sm-9">
<div class='input-group date' id='datetimepicker-end'>
<input type="text"
class="form-control"
name="end-time"
data-date-format="YYYY-MM-DD HH:mm" />
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col-md-12">
<button type="button" id="calculate-observation" class="btn btn-primary pull-right">
Calculate Observation
</button>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3>Suggested Timeline</h3>
<div id="timeline"></div>
<div id="hoverRes">
<div class="coloredDiv"></div>
<div id="name"></div>
<div id="scrolled_date"></div>
</div>
</div>
</div>
{% endblock content %}
{% block javascript %}
<script src="{% static 'js/d3.v3.min.js' %}"></script>
<script src="{% static 'js/d3-timeline.js' %}"></script>
<script src="{% static 'js/moment.min.js' %}"></script>
<script src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
<script src="{% static 'js/observation_new.js' %}"></script>
{% endblock javascript %}

View File

@ -19,6 +19,7 @@ urlpatterns = patterns(
'base.views.view_observation', name='observations_view_observation'),
url(r'^observations/$', 'base.views.observations_list',
name='observations'),
url(r'^observations/new/$', 'base.views.observation_new', name='observation_new'),
url(r'^about/$',
TemplateView.as_view(template_name='base/about.html'),
name='about'),