Created
March 23, 2018 00:53
-
-
Save dnomadb/4255f780da50bd982ed1b2eecb7b4a5c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var offsetPoint = function(p1,a,d){ | |
var brng = a*(Math.PI/180.0); | |
var R = 41807040; | |
var lat1 = (Math.PI/180.0)*p1.lat; | |
var lon1 = (Math.PI/180.0)*p1.lng; | |
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) + | |
Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng)); | |
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), | |
Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2)); | |
return {"lat":lat2*(180.0/Math.PI),"lng":lon2*(180.0/Math.PI)} | |
} | |
var bearingDegrees = function(p1,p2){ | |
var dLon = (Math.PI/180.0)*((p2.lng-p1.lng)); | |
var lat1 = (Math.PI/180.0)*p1.lat; | |
var lat2 = (Math.PI/180.0)*p2.lat; | |
var y = Math.sin(dLon) * Math.cos(lat2); | |
var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); | |
var brng = Math.atan2(y, x)*(180.0/Math.PI); | |
return brng; | |
} | |
var bearingRadians = function(p1,p2){ | |
var dLon = (Math.PI/180.0)*((p2.lng-p1.lng)); | |
var lat1 = (Math.PI/180.0)*p1.lat; | |
var lat2 = (Math.PI/180.0)*p2.lat; | |
var y = Math.sin(dLon) * Math.cos(lat2); | |
var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); | |
var brng = Math.atan2(y, x); | |
return brng; | |
} | |
var latLng2tile = function(lat,lon,zoom){ | |
var eLng = (lon+180)/360*Math.pow(2,zoom); | |
var eLat = (1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom); | |
//x coord in image tile of lat/lng | |
var xInd = Math.round((eLng-Math.floor(eLng))*256); | |
//y coord in image tile of lat/lng | |
var yInd = Math.round((eLat-Math.floor(eLat))*256); | |
//flattened index for clamped array in imagedata | |
var fInd = yInd*256+xInd; | |
//for calling tile from array | |
var eLng = Math.floor(eLng); | |
var eLat = Math.floor(eLat); | |
return {"tileCall":""+zoom+"/"+eLng+"/"+eLat,"tileX":eLng,"tileY":eLat,"pX":xInd,"pY":yInd,"arrInd":fInd} | |
} | |
function drawChart(divID){ | |
var divH = document.getElementById(divID).clientHeight, | |
divW = document.getElementById(divID).clientWidth, | |
chartSRC = '<iframe src="chart.html" id="chartframe" frameborder=0 height="'+divH+'" width ="'+divW+'" scrolling="no"></iframe>'; | |
document.getElementById(divID).innerHTML = chartSRC; | |
} | |
function distance(p1,p2){ | |
var R = 41807040; | |
var dLat = (Math.PI/180.0)*((p2.lat-p1.lat)); | |
var dLon = (Math.PI/180.0)*((p2.lng-p1.lng)); | |
var lat1 = (Math.PI/180.0)*p1.lat, | |
lat2 = (Math.PI/180.0)*p2.lat; | |
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); | |
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); | |
var d = R * c; | |
return d; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> | |
<title>Sweep Snap</title> | |
<style type="text/css"> | |
html { height: 100%; width: 100%} | |
body { | |
height: 100%; | |
width: 100%; | |
margin: 0; | |
padding: 0; | |
} | |
#map_canvas { | |
width: 100%; | |
height: 100%; | |
} | |
</style> | |
<link href='https://www.mapbox.com/base/latest/base.css' rel='stylesheet'> | |
<script src='https://api.tiles.mapbox.com/mapbox.js/v1.6.3/mapbox.js'></script> | |
<link href='https://api.tiles.mapbox.com/mapbox.js/v1.6.3/mapbox.css' rel='stylesheet' /> | |
</head> | |
<body> | |
<div id="map_canvas"></div> | |
<script type="text/javascript" src="general-geo-utils.js"></script> | |
<script type="text/javascript" src="path-edge-detect.js"></script> | |
<!--<script type="text/javascript" src="sweep-search.js"></script>worker: have to reference it in development for it to not cache--> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var tileSize, | |
locationHash, | |
everyOther = true; | |
var loadHash = window.location.hash.replace('#','').split('/'); | |
if (loadHash.length != 3){ | |
loadHash = [37.77872,-122.26403,18]; | |
history.pushState(null,null,'#'+loadHash[0]+'/'+loadHash[1]+'/'+loadHash[2]) | |
} | |
var map = L.map('map_canvas',{ | |
center: [loadHash[0], loadHash[1]], | |
zoom: loadHash[2], | |
worldCopyJump: true, | |
doubleClickZoom: false | |
}); | |
var tiles = new L.TileLayer.Canvas({ | |
unloadInvisibleTiles:true, | |
attribution: '<a href="http://www.mapbox.com/about/maps/" target="_blank">Terms & Feedback</a>' | |
}); | |
var worker = new Worker('sweep-search.js'); | |
worker.addEventListener('message', function(response) { | |
// Take the 'edge' response, set the cursor | |
//cursMark.setLatLng(response.data); | |
}, false); | |
var drawStyles = { | |
color: 'red' | |
} | |
var hoverStyle = { | |
color: 'white' | |
} | |
var lineArr = [L.polyline([],drawStyles)], | |
startPoint = L.circleMarker([],drawStyles) | |
.on('mouseover',function() { | |
this.setRadius(10) | |
.setStyle(hoverStyle); | |
}) | |
.on('mouseout',function() { | |
this.setRadius(8) | |
.setStyle(drawStyles); | |
}) | |
.on("click", endDraw), | |
currPoint = L.circleMarker([],drawStyles); | |
lineArr[0].addTo(map); | |
function drawShape(e){ | |
lineArr[lineArr.length-1].addLatLng(e.latlng); | |
worker.postMessage({ | |
'data':{ | |
'lat': e.latlng.lat, | |
'lng': e.latlng.lng | |
}, | |
type: 'firstpoint' | |
}); | |
currPoint.setStyle(hoverStyle); | |
setTimeout(function(){ | |
currPoint.setStyle(drawStyles); | |
},100) | |
} | |
var edgePoints = L.layerGroup([]) | |
.addTo(map); | |
worker.addEventListener('message', function(response) { | |
// TODO - Edge correlation sensitive to first mouse move after click - need to work out a method to straighten. | |
if (response.data.type == "movepoint"){ | |
lineArr[lineArr.length-1].spliceLatLngs(-1,1,response.data.data); | |
currPoint.setLatLng(response.data.data); | |
} | |
else if (response.data.type == "edgepoint"){ | |
edgePoints.addLayer(L.circleMarker(response.data.data,{radius:3})); | |
} | |
else { | |
edgePoints.clearLayers(); | |
} | |
}, false); | |
function updatePoint(e){ | |
worker.postMessage({ | |
'data':{ | |
'lat': e.latlng.lat, | |
'lng': e.latlng.lng, | |
'zoom': map.getZoom() | |
}, | |
type: 'mouseevent' | |
}); | |
} | |
function startDraw(e) { | |
lineArr[lineArr.length-1].addTo(map) | |
drawShape(e); | |
map.on("mousemove", updatePoint); | |
currPoint | |
.setLatLng(e.latlng) | |
.setRadius(5) | |
.addTo(map); | |
startPoint | |
.setLatLng(e.latlng) | |
.setRadius(10) | |
.addTo(map); | |
} | |
function endDraw() { | |
lineArr[lineArr.length-1].spliceLatLngs(-1,1,startPoint.getLatLng()); | |
map.removeLayer(startPoint); | |
map.removeLayer(currPoint); | |
lineArr.push(L.polyline([],drawStyles)); | |
map.off('mousemove'); | |
map.once("click", startDraw); | |
} | |
map.once("click", startDraw) | |
map.on("click", drawShape); | |
map.on('moveend',function(){ | |
// Set url with lat/lng/zoom | |
locationHash = '#'+''+map.getCenter().toString().replace('LatLng(','').replace(')','').replace(', ','/')+'/'+map.getZoom(); | |
history.replaceState(null,null,locationHash); | |
}); | |
tiles.on('tileunload', function(e){ | |
//Send tile unload data to worker to delete un-needed pixel data | |
worker.postMessage({'data':e.tile._tilePoint.id,'type':'tileunload'}) | |
}); | |
tiles.drawTile = function (canvas, tile, zoom) { | |
tileSize = this.options.tileSize; | |
var context = canvas.getContext('2d'), | |
imageObj = new Image(), | |
tileUID = ''+zoom+'/'+tile.x+'/'+tile.y; | |
// To access / delete tiles later | |
tile.id = tileUID; | |
imageObj.onload = function() { | |
// Draw Image Tile | |
context.drawImage(imageObj, 0, 0); | |
// Get Image Data | |
var imageData = context.getImageData(0, 0, tileSize, tileSize); | |
worker.postMessage({ | |
'data':{ | |
'tileUID':tileUID, | |
'tileSize':tileSize, | |
'array':imageData.data}, | |
'type':'tiledata'}, | |
[imageData.data.buffer]); | |
} | |
// Source of image tile | |
imageObj.crossOrigin = 'Anonymous'; | |
imageObj.src = `https://b.tiles.mapbox.com/v4/mapbox.satellite/${zoom}/${tile.x}/${tile.y}.jpg?access_token=pk.eyJ1IjoibWF0dCIsImEiOiJTUHZkajU0In0.oB-OGTMFtpkga8vC48HjIg` | |
} | |
tiles.addTo(map); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
importScripts('general-geo-utils.js'); | |
// Variables to be defined later, but needed in this context | |
var firstPoint, | |
currBearing, | |
currZoom, | |
currDist, | |
newBearing, | |
lastMoveDist, | |
kernelSamples, | |
lastPoint; | |
// Tile Data Holder | |
var tileData = {}; | |
//Interval (ft) upon which to sample | |
var sampInter = 4; | |
// Maximum Search Factor - search distance = sampInter*searchFactor; | |
var searchFactor = 24; | |
// Minimum mouse distane to re-search | |
var mouseMoveThreshold = 30; | |
// Minimum segment length before re-searching | |
var minimumEdgeLength = 70; | |
// Density on the line to sample | |
var searchDensity = 10; | |
//Listen for events | |
self.addEventListener('message', function(e) { | |
// obect to hold various methods based on message to worker | |
var edgeFind = { | |
// If event is a mouse event | |
mouseevent: function (inPoint) { | |
var currPoint = { | |
lat: inPoint.lat, | |
lng: inPoint.lng | |
} | |
currZoom = inPoint.zoom; | |
currDist = distance(currPoint,firstPoint); | |
kernelSamples = Math.round(currDist/searchDensity); | |
if (currDist<minimumEdgeLength) { | |
// send message to set point at mouse move position | |
self.postMessage({ | |
type:'movepoint', | |
data:currPoint | |
}); | |
lastMoveDist = mouseMoveThreshold+1; | |
lastPoint = currPoint; | |
} | |
else if (lastMoveDist>mouseMoveThreshold) { | |
//send message to clear edge points | |
self.postMessage({ | |
type:'clearedgepoints' | |
}); | |
currBearing = bearingDegrees(currPoint,firstPoint); | |
distInterval = currDist/(kernelSamples+1); | |
var lastSamplePoint = firstPoint, | |
accBearing = 0, | |
accX = 0, | |
accY = 0; | |
for (var k = 1;k<kernelSamples+1;k++) { | |
var tempSamplePt = offsetPoint(firstPoint,currBearing-180,k*distInterval), | |
alignKern = [0,0,0], | |
edgeAlignArr = []; | |
alignPositions = []; | |
for (var i = -1*searchFactor*sampInter;i<sampInter*searchFactor+1;i+=sampInter) { | |
var tempPoint = offsetPoint(tempSamplePt,currBearing+90,i), | |
tileInfo = latLng2tile(tempPoint.lat,tempPoint.lng,currZoom); | |
alignKern.pop(); | |
alignKern.splice(0,0,tileData[tileInfo.tileCall][tileInfo.arrInd]); | |
if (i>=-1*searchFactor*sampInter+2*sampInter) { | |
edgeAlignArr.push(((searchFactor*sampInter)-Math.abs(i))*Math.abs(-1*alignKern[0]+1*alignKern[2])); | |
alignPositions.push(tempPoint); | |
} | |
} | |
var maxArrayIndex = edgeAlignArr.indexOf(Math.max.apply(null, edgeAlignArr)); | |
if (maxArrayIndex!=-1) { | |
var currEdgeBearing = bearingRadians(lastSamplePoint,alignPositions[maxArrayIndex]); | |
accX+=Math.sin(currEdgeBearing); | |
accY+=Math.cos(currEdgeBearing); | |
lastSamplePoint = alignPositions[maxArrayIndex]; | |
// Send message to make an "edge point" | |
self.postMessage({ | |
type: 'edgepoint', | |
data: lastSamplePoint | |
}); | |
} | |
} | |
newBearing = 180+(Math.atan2(accX,accY)*180/Math.PI); | |
lastPoint = offsetPoint(firstPoint,newBearing,-1*currDist); | |
lastMoveDist = 0; | |
} | |
else { | |
newPoint = offsetPoint(firstPoint,newBearing,-1*currDist); | |
// Corrected point at mean angle, and current distance | |
self.postMessage({ | |
type: 'movepoint', | |
data: newPoint | |
}); | |
lastMoveDist = distance(currPoint, lastPoint); | |
} | |
}, | |
// If it is the first click on a segment | |
firstpoint: function (inPoint) { | |
firstPoint = { | |
lat: inPoint.lat, | |
lng: inPoint.lng | |
} | |
}, | |
// If tile data was sent, add to data object | |
tiledata: function (inTile) { | |
var dataArray = new Uint16Array(65536); | |
for (var i=0;i<inTile.array.length/4;i++) { | |
// Only use R and G for speed | |
var tDataVal = (inTile.array[i*4]+inTile.array[i*4+1]); | |
dataArray[i] = (tDataVal); | |
} | |
delete inTile.array; | |
tileData[inTile.tileUID] = dataArray; | |
}, | |
// If a tile unload event was sent, delete the corresponding data | |
tileunload: function (tileUnloadID) { | |
delete tileData[tileUnloadID]; | |
} | |
} | |
// Call function based on message, send data. | |
edgeFind[e.data.type](e.data.data); | |
}, false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment