commit
c24547746e
24
apps.json
24
apps.json
|
|
@ -1400,5 +1400,29 @@
|
||||||
{"name":"rclock.app.js","url":"rclock.app.js"},
|
{"name":"rclock.app.js","url":"rclock.app.js"},
|
||||||
{"name":"rclock.img","url":"app-icon.js","evaluate":true}
|
{"name":"rclock.img","url":"app-icon.js","evaluate":true}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{ "id": "hamloc",
|
||||||
|
"name": "QTH Locator / Maidenhead Locator System",
|
||||||
|
"shortName": "QTH Locator",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Convert your current GPS location to the Maidenhead locator system used by HAM amateur radio operators",
|
||||||
|
"tags": "tool,outdoors,gps",
|
||||||
|
"storage": [
|
||||||
|
{"name":"hamloc.app.js","url":"app.js"},
|
||||||
|
{"name":"hamloc.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "id": "osmpoi",
|
||||||
|
"name": "POI Compass",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.",
|
||||||
|
"tags": "tool,outdoors,gps",
|
||||||
|
"custom": "osmpoi.html",
|
||||||
|
"storage": [
|
||||||
|
{"name":"osmpoi.app.js"},
|
||||||
|
{"name":"osmpoi.img"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
# QTH Locator
|
||||||
|
|
||||||
|
Convert your current GPS location to the [Maidenhead](https://en.wikipedia.org/wiki/Maidenhead_Locator_System) locator system used by HAM amateur radio operators.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
A Maidenhead locator compresses latitude and longitude into a short string of characters, which is similar in concept to the World Geographic Reference System or GEOREF. This position information is presented in a limited level of precision to limit the number of characters needed for its transmission using voice, Morse code, or any other operating mode.
|
||||||
|
|
||||||
|
The chosen coding uses alternating pairs of letters and digits, like so:
|
||||||
|
|
||||||
|
* BL11bh
|
||||||
|
##
|
||||||
|
* support Paul Brewer KI6CQ HamGridSquare.js
|
||||||
|
* support Chris Veness 2002-2012 LatLon library
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AH4ACwVeAAM6nQECJsYqDFYItCAgQ0DFrxWE2ZhBxOJA4ICBGwhbbxGtAYOz2etnWt2YwBnQCBGgWtxBjXJQQpBLgQABEQIDBMAgwE2YYBwRcUxOtDwgABGgYvGTQQLCMSRNGEQaODF4SQDHgYwUFIlfAgY2DYQQGDsouCGAQSEGBouEKANl1onEwQvGA4QACA4IwQaIISFFwIwDXwI2ExL2BB4YABJgwwKnQAkRpzYDAAbuBA4oABe4aaDD44uGxCNEQwStEdwgAFR4IHGF4iRBxJeLBwIdCcwgvJxLwFFIRgLBo4dBcwj2CF45xIKIxeLAww4FAAuINIYbKMAteso8FAwovPCQllQQtlF4gLFUYwvDsq/HfIShEDhCQDIgIAFnQHGBBITRnWIXwdfAAYGFSYblBNI5KBsobEDo4GCdxyFDr2tR4+tDQrwNF5YlEnQvJaZIvKr4RIEoovaSAIvyXArbBF6OJR6mCXAgvBDwIlFd5IfBd6tfSQQRGCgeIBJE6DIIAFDoIGGF4OCAgIAEnQHGBBITRnWIF4P+V4ZMCWxBoBRw5PBNI7IGnQuCSAIfE1oSB1oADF4WIXxAvHsoIFH4IvEdIJWEDg4vICRTuJSAwABxAcJF5A5C1ovKRwhgCwSQGF6CpEXxBeGMA59JZIIvGA4hhBLw+JF4xRFSBBNDFIhHFe4VfLxhgCAEguIMAJSB1oABSA4HEB4RwBAgQXHss6LxKRDPQTxBsovIRIdexCOGRpwwIr5gFAwbuEAoheBFyQwFRIrwDLwZuBdwgTBC4IuRYYowGRAq+BAoeCAoRABFyIABD4IsCGAgpFGoguBd4eIFyRiEFoIwCEoKJDRwYqCCAJcUGJICBK4JgDKgOtOIQtce4s6AAI2EBAgteAAizBGgYECwQsiAD4"))
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
latLonToGridSquare=function(o,a){var t,e,n,s,l,i,r,h,M,f=-100,g=0,u="ABCDEFGHIJKLMNOPQRSTUVWX",d=u.toLowerCase();function N(o){return"number"==typeof o?o:"string"==typeof o?parseFloat(o):"function"==typeof o?parseFloat(o()):void E.showMessage("can't convert \ninput: "+o)}return"object"==typeof o?2===o.length?(f=N(o[0]),g=N(o[1])):"lat"in o&&"lon"in o?(f=N(o.lat),g=N(o.lon)):"latitude"in o&&"longitude"in o?(f=N(o.latitude),g=N(o.longitude)):E.showMessage("can't convert \nobject "+o):(f=N(o),g=N(a)),isNaN(f)&&E.showMessage("lat is NaN"),isNaN(g)&&E.showMessage("lon is NaN"),90===Math.abs(f)&&E.showMessage("grid invalid \nat N/S"),90<Math.abs(f)&&E.showMessage("invalid lat: \n"+f),180<Math.abs(g)&&E.showMessage("invalid lon: \n"+g),t=f+90,e=g+180,n=u[Math.floor(t/10)],s=u[Math.floor(e/20)],l=""+Math.floor(t%10),i=""+Math.floor(e/2%10),h=60*(t-Math.floor(t)),M=60*(e-2*Math.floor(e/2)),r=d[Math.floor(h/2.5)],s+n+i+l+d[Math.floor(M/5)]+r};
|
||||||
|
|
||||||
|
Bangle.setGPSPower(1);
|
||||||
|
var fix;
|
||||||
|
Bangle.removeAllListeners();
|
||||||
|
Bangle.on('GPS',function(f) {
|
||||||
|
fix=f;
|
||||||
|
g.clear();
|
||||||
|
g.setFontAlign(0,0);
|
||||||
|
if (!f.fix) {
|
||||||
|
g.setFont("6x8",3);
|
||||||
|
g.drawString("Waiting for",120,70);
|
||||||
|
g.drawString("GPS Fix",120,110);
|
||||||
|
g.setFont("6x8",2);
|
||||||
|
g.drawString(f.satellites+" satellites",120,170);
|
||||||
|
} else {
|
||||||
|
g.setFont("6x8",5);
|
||||||
|
var maidenhead = latLonToGridSquare(fix.lat,fix.lon);
|
||||||
|
g.drawString(maidenhead,120,120);
|
||||||
|
}
|
||||||
|
});
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Points Of Interest Compass
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -0,0 +1,228 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
|
||||||
|
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
html, body, #map {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#map { z-index: 1; }
|
||||||
|
#controls {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
border: 1px solid black;
|
||||||
|
position:absolute;
|
||||||
|
right:0px;top:0px;
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="map">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="controls">
|
||||||
|
<select id="amenity">
|
||||||
|
<option value="drinking_water">Drinking Water</option>
|
||||||
|
<option value="bicycle_parking">Bicycle Park</option>
|
||||||
|
<option value="post_box">Post Box</option>
|
||||||
|
<option value="bar">Bars</option>
|
||||||
|
<option value="bbq">Barbecue</option>
|
||||||
|
<option value="cafe">Café</option>
|
||||||
|
<option value="fast_food">Fast food</option>
|
||||||
|
<option value="restaurant">restaurant</option>
|
||||||
|
<option value="bicycle_repair_station">Bicycle Repair</option>
|
||||||
|
<option value="bicycle_rental">Bicycle rental</option>
|
||||||
|
<option value="bus_station">Bus station</option>
|
||||||
|
<option value="atm">Bank</option>
|
||||||
|
<option value="pharmacy">Pharmacy</option>
|
||||||
|
<option value="interner_cafe">Cybercafé</option>
|
||||||
|
</select>
|
||||||
|
<p>Click <button id="poi" class="btn btn-primary">Find P.O.I.</button></p>
|
||||||
|
<p>If ok, Click <button id="upload" class="btn btn-primary">Upload</button></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../../lib/customize.js"></script>
|
||||||
|
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/osmtogeojson@2.2.12/osmtogeojson.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/*
|
||||||
|
|
||||||
|
https://overpass-turbo.eu/ to check queries.
|
||||||
|
Run:
|
||||||
|
|
||||||
|
node
|
||||||
|
({{bbox}});
|
||||||
|
out;
|
||||||
|
|
||||||
|
Over the area you're interested in, click on the POI and find out
|
||||||
|
what you need to search for, eg.
|
||||||
|
|
||||||
|
node
|
||||||
|
[amenity=pub]
|
||||||
|
({{bbox}});
|
||||||
|
out;
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var map = L.map('map').locate({setView: true, maxZoom: 16});
|
||||||
|
var features = [];
|
||||||
|
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 18,
|
||||||
|
attribution: 'Map data © <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors</a>'
|
||||||
|
}).addTo(map);
|
||||||
|
function buildOverpassApiUrl(map, overpassQuery) {
|
||||||
|
var bounds = map.getBounds().getSouth() + ',' + map.getBounds().getWest() + ',' + map.getBounds().getNorth() + ',' + map.getBounds().getEast();
|
||||||
|
var nodeQuery = 'node[' + overpassQuery + '](' + bounds + ');';
|
||||||
|
var wayQuery = 'way[' + overpassQuery + '](' + bounds + ');';
|
||||||
|
var relationQuery = 'relation[' + overpassQuery + '](' + bounds + ');';
|
||||||
|
var query = '?data=[out:json][timeout:15];(' + nodeQuery + wayQuery + relationQuery + ');out body geom;';
|
||||||
|
var baseUrl = 'https://overpass-api.de/api/interpreter';
|
||||||
|
var resultUrl = baseUrl + query;
|
||||||
|
return resultUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("poi").addEventListener("click", function() {
|
||||||
|
//var overpassApiUrl = buildOverpassApiUrl(map, "highway=bus_stop");
|
||||||
|
var poi = document.getElementById("amenity").options[document.getElementById("amenity").selectedIndex].value;
|
||||||
|
var overpassApiUrl = buildOverpassApiUrl(map, "amenity="+poi);
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.responseType = 'json';
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
console.log("XMLHttpRequest", this.readyState);
|
||||||
|
if (this.readyState == 4) {
|
||||||
|
var osmDataAsJson = req.response;
|
||||||
|
features = [];
|
||||||
|
if (osmDataAsJson.elements) {
|
||||||
|
osmDataAsJson.elements.forEach(function(el) {
|
||||||
|
if (el.type!="node") return;
|
||||||
|
features.push({lat:el.lat, lon:el.lon,name:el.tags.name});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultAsGeojson = osmtogeojson(osmDataAsJson);
|
||||||
|
var resultLayer = L.geoJson(resultAsGeojson, {
|
||||||
|
style: function (feature) {
|
||||||
|
return {color: "#ff0000"};
|
||||||
|
},
|
||||||
|
filter: function (feature, layer) {
|
||||||
|
var isPolygon = (feature.geometry) && (feature.geometry.type !== undefined) && (feature.geometry.type === "Polygon");
|
||||||
|
if (isPolygon) {
|
||||||
|
feature.geometry.type = "Point";
|
||||||
|
var polygonCenter = L.latLngBounds(feature.geometry.coordinates[0]).getCenter();
|
||||||
|
feature.geometry.coordinates = [ polygonCenter.lat, polygonCenter.lng ];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
onEachFeature: function (feature, layer) {
|
||||||
|
var popupContent = "";
|
||||||
|
popupContent = popupContent + "<dt>@id</dt><dd>" + feature.properties.type + "/" + feature.properties.id + "</dd>";
|
||||||
|
var keys = Object.keys(feature.properties.tags);
|
||||||
|
keys.forEach(function (key) {
|
||||||
|
popupContent = popupContent + "<dt>" + key + "</dt><dd>" + feature.properties.tags[key] + "</dd>";
|
||||||
|
});
|
||||||
|
popupContent = popupContent + "</dl>"
|
||||||
|
layer.bindPopup(popupContent);
|
||||||
|
}
|
||||||
|
}).addTo(map);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
req.open("GET", overpassApiUrl, true);
|
||||||
|
req.send();
|
||||||
|
});
|
||||||
|
document.getElementById("upload").addEventListener("click", function() {
|
||||||
|
var app = `var features = ${JSON.stringify(features)};
|
||||||
|
var img_nofix = require("heatshrink").decompress(atob("mEwxH+AH4A0PgYurg9kr0rGM4nBg9dsgADmUHGUYtHAAddGIJcgFpIxEMTsAlYtMAAZiaLh4AFmQwXLiSTaLiosBnMymUrGCYTBAAgvPCgjwaMh4raF/4v/F/4vUg4vulZgDgAAIF8EyEQUAh0cAAkVisHGA4+HF6gVBiwwFjkONo0HAAMOAAIvTnIhEiovMFQQADNgYvQroUDg4uGjj9EF448DF6a+HAAS+EF5CQCF6SMIeAQvFXYYwHF59eLpSOBF4hgKGAIvPskAFxKOFF80VM4KOFSBs5F6EWRY4xBF43+F5UyF6DuEizZBKwIuHSBQvXdIwvKMYsHlYvQW4IuPYAYRBMggvRgIvCFxwwCTYZlEg4vPlcHjkVFx6WJF6YuXMoTwCF58yVgIvXY4YvQrqqDGDAvvPYIvPsguaYQYv/F7owBF/4vfg4AGTIIAHF7gA/AH4AwA="));
|
||||||
|
var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG2JnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA="));
|
||||||
|
|
||||||
|
// https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js
|
||||||
|
function project(latlong) {
|
||||||
|
var d = Math.PI / 180,
|
||||||
|
max = 85.0511287798,
|
||||||
|
R = 6378137, // earth radius in m
|
||||||
|
lat = Math.max(Math.min(max, latlong.lat), -max),
|
||||||
|
sin = Math.sin(lat * d);
|
||||||
|
return {x:R * latlong.lon * d,
|
||||||
|
y:R * Math.log((1 + sin) / (1 - sin)) / 2};
|
||||||
|
}
|
||||||
|
|
||||||
|
features.forEach(function(f) {
|
||||||
|
f.p = project(f);
|
||||||
|
});
|
||||||
|
var fix = {fix:false,satellites:0};
|
||||||
|
var nearest = undefined;
|
||||||
|
var nearestangle = 0;
|
||||||
|
var nearestdist = 0;
|
||||||
|
|
||||||
|
Bangle.on('GPS', function(f) {
|
||||||
|
fix = f;
|
||||||
|
fix.p = project(fix);
|
||||||
|
nearest = undefined;
|
||||||
|
nearestangle = 0;
|
||||||
|
nearestdist = 5000; // 5km
|
||||||
|
features.forEach(function(f) {
|
||||||
|
var dx = f.p.x - fix.p.x;
|
||||||
|
var dy = f.p.y - fix.p.y;
|
||||||
|
var d = Math.sqrt(dx*dx + dy*dy);
|
||||||
|
if (d<nearestdist) {
|
||||||
|
nearestdist = d;
|
||||||
|
nearest = f;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (nearest) {
|
||||||
|
var dx = nearest.p.x - fix.p.x;
|
||||||
|
var dy = nearest.p.y - fix.p.y;
|
||||||
|
nearestangle = Math.atan2(dy,dx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on('mag', function(m) {
|
||||||
|
if (!Bangle.isLCDOn()) return;
|
||||||
|
var headingrad = m.heading*Math.PI/180; // in radians
|
||||||
|
if (!isFinite(headingrad)) headingrad=0;
|
||||||
|
if (nearest)
|
||||||
|
g.drawImage(img_fix,120,120,{
|
||||||
|
rotate: (Math.PI/2)+headingrad-nearestangle,
|
||||||
|
scale:3,
|
||||||
|
});
|
||||||
|
else
|
||||||
|
g.drawImage(img_nofix,120,120,{
|
||||||
|
rotate: headingrad,
|
||||||
|
scale:2,
|
||||||
|
});
|
||||||
|
g.clearRect(60,0,180,24);
|
||||||
|
g.setFontAlign(0,0);
|
||||||
|
g.setFont("6x8");
|
||||||
|
if (fix.fix) {
|
||||||
|
g.drawString(nearest ? nearest.name : "---",120,4);
|
||||||
|
g.setFont("6x8",2);
|
||||||
|
g.drawString(nearest ? Math.round(nearestdist)+"m" : "---",120,16);
|
||||||
|
} else {
|
||||||
|
g.drawString(fix.satellites+" satellites",120,4);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Bangle.setCompassPower(1);
|
||||||
|
Bangle.setGPSPower(1);
|
||||||
|
g.clear();`;
|
||||||
|
var icon = `require("heatshrink").decompress(atob("mEwxH+AH4A0PgYurg9kr0rGM4nBg9dsgADmUHGUYtHAAddGIJcgFpIxEMTsAlYtMAAZiaLh4AFmQwXLiSTaLiosBnMymUrGCYTBAAgvPCgjwaMh4raF/4v/F/4vUg4vulZgDgAAIF8EyEQUAh0cAAkVisHGA4+HF6gVBiwwFjkONo0HAAMOAAIvTnIhEiovMFQQADNgYvQroUDg4uGjj9EF448DF6a+HAAS+EF5CQCF6SMIeAQvFXYYwHF59eLpSOBF4hgKGAIvPskAFxKOFF80VM4KOFSBs5F6EWRY4xBF43+F5UyF6DuEizZBKwIuHSBQvXdIwvKMYsHlYvQW4IuPYAYRBMggvRgIvCFxwwCTYZlEg4vPlcHjkVFx6WJF6YuXMoTwCF58yVgIvXY4YvQrqqDGDAvvPYIvPsguaYQYv/F7owBF/4vfg4AGTIIAHF7gA/AH4AwA="))`;
|
||||||
|
|
||||||
|
sendCustomizedApp({
|
||||||
|
storage:[
|
||||||
|
{name:"osmpoi.app.js", content:app},
|
||||||
|
{name:"osmpoi.img", content:icon, evaluate:true},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue