Skip to content

Instantly share code, notes, and snippets.

@k-nut
Last active June 27, 2022 16:58
Show Gist options
  • Save k-nut/58692cdd339766806c22469922b36c5f to your computer and use it in GitHub Desktop.
Save k-nut/58692cdd339766806c22469922b36c5f to your computer and use it in GitHub Desktop.
CriticalTracks
import sqlite3
import json
import sys
FILENAME = "./criticaltracks.sqlite"
def get_distane(point, other_point):
from math import sin, cos, sqrt, atan2, radians
# approximate radius of earth in m
R = 6373.0 * 1_000
lon1, lat1 = [radians(x) for x in point["geometry"]["coordinates"]]
lon2, lat2 = [radians(x) for x in other_point["geometry"]["coordinates"]]
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
return R * c
def may_show(point, points):
NEIGHBORS = 3
DISTANCE = 100
found = 0
for candidate in points:
if get_distane(candidate, point) < DISTANCE:
found += 1
if found == NEIGHBORS:
return True
return False
def create_point(key, values):
lat = values["latitude"] / 1_000_000
lon = values["longitude"] / 1_000_000
return {
"type": "Feature",
"geometry": {"type": "Point", "coordinates": [lon, lat]},
}
def main():
con = sqlite3.connect(FILENAME)
cur = con.cursor()
rows = []
for row in cur.execute('select * from tracks'):
timestamp, data = row
print(timestamp, file=sys.stderr)
points = [create_point(key, value) for key, value in json.loads(data)['locations'].items()]
filtered_points = [point for point in points if may_show(point, points)]
if len(filtered_points):
rows.append({"timestamp": timestamp, "data": filtered_points})
print(json.dumps(rows))
if __name__ == "__main__":
main()
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src='https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.css' rel='stylesheet'/>
<body>
<div id='map'></div>
<div id="controls">
<div>
<span id="time">17:55</span>
<button class="play">⏸</button>
</div>
<input type="range" id="timeselector" min="0" value=0>
</div>
<style>
body {
display: flex;
width: 98vw;
height: 98vh;
}
#map {
flex-grow: 1;
}
#controls {
font-size: 1.5em;
position: absolute;
top: 20px;
left: 20px;
color: white;
font-family: sans-serif;
}
.play {
font-size: 1em;
background: none;
border: none;
outline: none;
padding: 0;
}
</style>
<script>
mapboxgl.accessToken = 'YOUR_TOKEN';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/dark-v10', // style URL
center: [13.4047, 52.5147],
zoom: 12
});
const animateRow = (row) => {
const data = {
"type": "FeatureCollection",
features: row
};
map.getSource('bikes').setData(data)
};
fetch('data.json')
.then(response => response.json())
.then(json => {
map.on('load', () => {
map.addSource('bikes', {
'type': 'geojson',
data: {
"type": "FeatureCollection",
features: []
}
});
map.addLayer({
'id': 'bikes',
'source': 'bikes',
'type': 'circle',
'paint': {
'circle-radius': 5,
'circle-color': 'rgba(241,202,17,0.69)'
}
});
const input = document.querySelector('input')
input.max = json.length;
let interval;
const autoAnimate = () => {
interval = setInterval(() => {
if (input.value >= json.length){
clearInterval(interval);
return
}
input.value++;
showBasedOnInput();
}, 100);
}
const button = document.querySelector('.play');
const startButton = () => {
button.innerText = '⏸'
autoAnimate();
};
const stopButton = () => {
button.innerText = '▶️'
clearInterval(interval)
}
button.onclick = () => {
const isPlaying = button.innerText === '⏸';
if (isPlaying){
stopButton();
} else {
startButton();
}
}
const display = (row) => {
const {timestamp, data} = row;
const time = new Date(timestamp.replace(" ", "T") + "Z").toLocaleTimeString().slice(0,5);
document.querySelector('#time').innerText = time;
animateRow(data);
}
const showBasedOnInput = () => {
display(json[input.value]);
}
input.addEventListener('input', () => {
stopButton();
showBasedOnInput();
})
autoAnimate();
})
})
</script>
</body>
</head>
import urllib.request
import sqlite3
from time import sleep
URL = 'https://api.criticalmaps.net/postv2'
FILENAME = "criticaltracks.sqlite"
def get_data():
with urllib.request.urlopen(URL) as url:
return url.read().decode()
def add_row(cur, con, data: str):
cur.execute('insert into tracks (data) values(?);', (data,))
con.commit()
def main():
con = sqlite3.connect(FILENAME)
cur = con.cursor()
cur.execute('CREATE TABLE IF NOT EXISTS tracks (timestamp datetime default current_timestamp, data text);')
con.commit()
while True:
data = get_data()
add_row(cur, con, data)
sleep(5)
print(".", end="")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment