emulator mvp

course parsed and displayed!
pull/1678/head
Jason Dekarske 2022-04-02 22:23:48 -07:00
parent caa5629ae3
commit e3cc8717e6
8 changed files with 261 additions and 0 deletions

1
apps/golfview/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App! Very limited course support.

21
apps/golfview/README.md Normal file
View File

@ -0,0 +1,21 @@
# App Name
Describe the app...
Add screen shots (if possible) to the app folder and link then into this file with ![](<name>.png)
## Usage
Select your course of interest upon loading this app.
## Contributions
The performance of this app depends on the accuracy and consistency of user-submitted maps. Please contribute to Open Street Map using these guidelines and provide input in ways to support this application.
## Controls
Swipe to change holes and tap to see a green closeup.
## Requests/Creator
[Jason Dekarske](https://github.com/jdekarske)

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("AAkCpMkyQCBwANGggLCAQYOOpAONpMgBwgLFHxAOJyVABwt/8QRGBwsv/mREAwOEkv/K4IOFyBZE3/ypMiHwwODy/+AYOJPowFD//Jkh9HAodf/IsGAQMSAoVL/4FD7dtBwWCCgd/6QOE2wjGl/6AoVbBwJDBBwh6BGQYOB7ZBG3/pAoUtBwNkBwuX/ojDBwNsZw3/0gFCBwJcDPQn0AoYOB2QOFpf+AoZcCNYx6ELgRrGAQoOB7IONPQUJBxB6CAoNBBxB6CRINIBYdJlIOIggODkiJFU4UABwmSAoWWU4cAfwQOCpSJDBwcCBAOJHQRNDBwUggAIByIKCJoYCCBwJ6CLAYOHgIFBogKCLgYCCgEAAoNIA4WUBw56CkRrFAQWAB4J6FqQOEyAOBPQRrCPQYCCBwJ6CNYYOFoAPBAoQOIpAOBPQRcCRIwOBPQRcCTBB6CFIoOGeoYCIBwJ6DARCJCNYQOIRIRrDARAOCLgckydtAQaJDLgttcwICCRIRNFpu0AQYOEJpQODVQYOLTZKYCHw4OKHw4NFAAS8ELIgABA=="))

51
apps/golfview/golfview.js Normal file
View File

@ -0,0 +1,51 @@
let course = require("Storage").readJSON("course_data_hole1.json");
console.log(Object.keys(course));
g.clear();
for (var feature of course.features) {
//console.log(Object.keys(feature));
if (feature.type === "fairway"){
g.setColor(0,0,1);
} else if ( feature.type === "tee"){
g.setColor(1,0,0);
} else if (feature.type === "green"){
g.setColor(0,1,0);
} else if (feature.type === "bunker"){
g.setColor(1,1,0);
} else {
continue;
}
var nodelist = [];
feature.nodesXY.forEach(function (node) {
nodelist.push(node.x);
nodelist.push(node.y);
});
newnodelist = g.transformVertices(nodelist,{
x: 150, // x offset (default 0)
y: 150, // y offset (default 0)
scale: 0.45, // scale factor (default 1)
rotate: course.angle - 1.57, // angle in radians (default 0)
});
g.fillPoly(newnodelist, true);
console.log(feature.type);
console.log(nodelist);
}
var nodelist = [];
course.nodesXY.forEach(function (node) {
nodelist.push(node.x);
nodelist.push(node.y);
});
newnodelist = g.transformVertices(nodelist,{
x: 150, // x offset (default 0)
y: 150, // y offset (default 0)
scale: 0.45, // scale factor (default 1)
rotate: course.angle - 1.57, // angle in radians (default 0)
});
g.setColor(0,1,1);
g.drawPoly(newnodelist);

BIN
apps/golfview/golfview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

114
apps/golfview/index.html Normal file
View File

@ -0,0 +1,114 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</head>
<body>
<button id="upload" class="btn btn-primary">Upload</button>
<script src="../../core/lib/customize.js"></script>
<script src="./maptools.js"></script>
<script>
const url = "https://overpass-api.de/api/interpreter";
let query = `[out:json][timeout:5];relation["name"="Davis Golf Course"];way(r)["golf"="hole"];foreach->.a(.a out;way(around.a:40.0)["golf"];out;>>;out;)`; // this gets everything at least
let course_input = null;
function findNodeCoordinates(elements, id) {
for (let i = 0; i < elements.length; i++) {
if (elements[i].type === "node" && elements[i].id === id) {
let thing = (({ lat, lon }) => ({ lat, lon }))(elements[i]);
return thing;
}
}
console.error("node id: ", id, " not found");
}
function processFeatures(course_verbose) {
let course_processed = {
holes: {}
};
let current_hole = 0;
for (let i = 0; i < course_verbose.length; i++) {
const element = course_verbose[i];
if (element.type === "way") {
// if we find a high-level hole feature
if (element.tags.golf === "hole") {
if (element.tags.ref in course_processed.holes) continue; // the around picks up hole ways that mess everything up
current_hole = parseInt(element.tags.ref); //subsequent way features should be applied to the current hole
let nodes = [];
for (const node_id of element.nodes) {
nodes.push(findNodeCoordinates(course_verbose, node_id));
}
var hole = {
hole_number: current_hole,
handicap: parseInt(element.tags.handicap),
par: parseInt(element.tags.par),
nodes: nodes,
features: [],
}
course_processed.holes[current_hole.toString()] = hole;
}
// if we find a feature add it to the corresponding hole
if (/(green)|(bunker)|(tee)|(teebox)|(fairway)|(water_hazard)/.test(element.tags.golf)) { //TODO missing cartpath
let nodes = []
for (const node_id of element.nodes) {
nodes.push(findNodeCoordinates(course_verbose, node_id));
}
let new_feature = {
nodes: nodes,
type: element.tags.golf,
id: element.id,
}
course_processed.holes[current_hole.toString()].features.push(new_feature);
}
}
}
return course_processed;
}
function preprocessCoords(course_input) {
// first do the high-level way
for (var hole in course_input.holes) {
course_input.holes[hole].nodesXY = arraytoXY(course_input.holes[hole].nodes, course_input.holes[hole].nodes[0])
// then do the shapes in the features
for (var feature in course_input.holes[hole].features) {
course_input.holes[hole].features[feature].nodesXY = arraytoXY(course_input.holes[hole].features[feature].nodes, course_input.holes[hole].nodes[0]);
}
// find out how the hole is angled
course_input.holes[hole].angle = angle(course_input.holes[hole].nodesXY[0], course_input.holes[hole].nodesXY[course_input.holes[hole].nodesXY.length - 1])
}
return course_input;
}
var out = {};
// download info from the course
$.post(url, query, function (result) {
course_input = result;
out = processFeatures(course_input.elements);
out = preprocessCoords(out);
console.log(course_input);
console.log(out);
})
// When the 'upload' button is clicked...
document.getElementById("upload").addEventListener("click", function () {
downloadObjectAsJSON(out.holes["1"], "course_data");
sendCustomizedApp({
storage: courses
});
});
</script>
</body>
</html>

59
apps/golfview/maptools.js Normal file
View File

@ -0,0 +1,59 @@
const EARTHRADIUS = 6371000; //km
function radians(a) {
return a * Math.PI / 180;
}
function degrees(a) {
let d = a * 180 / Math.PI;
return (d + 360) % 360;
}
function toXY(a, origin) {
let pt = {
x: 0,
y: 0
};
pt.x = EARTHRADIUS * radians(a.lon - origin.lon) * Math.cos(radians((a.lat + origin.lat) / 2));
pt.y = EARTHRADIUS * radians(origin.lat - a.lat);
return pt;
}
function arraytoXY(array, origin) {
let out = [];
for (var j in array) {
let newpt = toXY(array[j], origin);
out.push(newpt);
}
return out;
}
function angle(a, b) {
let x = b.x - a.x;
let y = b.y - a.y;
return Math.atan2(-y, x);
}
function rotateVec(a, theta) {
let pt = {
x: 0,
y: 0
};
c = Math.cos(theta);
s = Math.sin(theta);
pt.x = c * a.x - s * a.y;
pt.y = s * a.x + c * a.y;
return pt;
}
// https://stackoverflow.com/questions/19721439/download-json-object-as-a-file-from-browser
function downloadObjectAsJSON(exportObj, exportName) {
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
var downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", exportName + ".json");
document.body.appendChild(downloadAnchorNode); // required for firefox
downloadAnchorNode.click();
downloadAnchorNode.remove();
}

View File

@ -0,0 +1,14 @@
{ "id": "glfview",
"name": "Golf View",
"version":"0.01",
"description": "This app will provide you with on course data to support your golf game! All information comes from OpenStreetMap. Please contribute by drawing your course using these guidelines: [guidelines](guidelines.com)",
"icon": "golfview.png",
"tags": "",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"custom": "index.html",
"storage": [
{"name":"glfview.app.js","url":"golfview.js"},
{"name":"glfview.img","url":"golfview-icon.js","evaluate":true}
]
}