mirror of
https://expo.survex.com/repositories/expoweb/.git/
synced 2024-12-22 16:32:22 +00:00
moving conversion tools from expofiles/tools
This commit is contained in:
parent
b5bc0c9075
commit
429eb4a1a5
28530
scripts/convert/height_from_utm.js
Normal file
28530
scripts/convert/height_from_utm.js
Normal file
File diff suppressed because it is too large
Load Diff
156
scripts/convert/index.html
Normal file
156
scripts/convert/index.html
Normal file
@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
input[type=text], select {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
textarea, select {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
width: 100%;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 14px 20px;
|
||||
margin: 8px 0;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=submit]:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
table{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td{
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="module">
|
||||
import { fromLatLon, toLatLon } from "./utm_converter.js";
|
||||
|
||||
import { heightFromUTM } from "./height_from_utm.js";
|
||||
|
||||
function findDigitGroupings(str) {
|
||||
const digitGroupings = str.match(/[\d.]+/g);
|
||||
return digitGroupings || [];
|
||||
}
|
||||
|
||||
function toDMSString(decimalDegrees) {
|
||||
const degrees = Math.floor(decimalDegrees);
|
||||
const decimalMinutes = (decimalDegrees - degrees) * 60;
|
||||
const minutes = Math.floor(decimalMinutes);
|
||||
const seconds = (decimalMinutes - minutes) * 60;
|
||||
|
||||
return `${degrees}° ${minutes}' ${seconds.toFixed(2)}"`;
|
||||
}
|
||||
|
||||
function fromUnknown(str)
|
||||
{
|
||||
var lines = str.split('\n');
|
||||
let latlongs = lines.map(line => {
|
||||
let digits = findDigitGroupings(line).map(x => parseFloat(x));
|
||||
if(digits.length == 2)
|
||||
{
|
||||
return digits
|
||||
}
|
||||
if(digits.length == 4)
|
||||
{
|
||||
return [
|
||||
digits[0] + (1.0/60)*digits[1],
|
||||
digits[2] + (1.0/60)*digits[3]
|
||||
]
|
||||
}
|
||||
if(digits.length == 6)
|
||||
{
|
||||
return [
|
||||
digits[0] + (1.0/60)*digits[1] + (1.0/3600)*digits[2],
|
||||
digits[3] + (1.0/60)*digits[4] + (1.0/3600)*digits[5]
|
||||
]
|
||||
}
|
||||
if(digits.length == 3)
|
||||
{
|
||||
let zone = line.match(/\d\d[A-Z]/g)[0];
|
||||
let res = fromUTM(digits[1],digits[2],digits[0],zone[2])
|
||||
return [res['latitude'],res['longitude']]
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var table_cells = latlongs.map(x => {
|
||||
let utm = fromLatLon(x[0],x[1]);
|
||||
let utmString = `${utm.zoneNum}${utm.zoneLetter} ${utm.easting.toFixed(2)} ${utm.northing.toFixed(2)}`
|
||||
let latlonString = `${x[0].toFixed(6)} N ${x[1].toFixed(6)} E`
|
||||
let dmsString = `${toDMSString(x[0])} N ${toDMSString(x[1])} E`
|
||||
return [utmString,latlonString, dmsString, heightFromUTM(utm.easting,utm.northing)]
|
||||
})
|
||||
|
||||
table_cells = [['utm','lat/lon','lat/lon','height']].concat(table_cells)
|
||||
|
||||
let resultsbox = document.getElementById("results");
|
||||
resultsbox.replaceChildren();
|
||||
|
||||
const table = document.createElement("table");
|
||||
for(var i=0;i < table_cells.length; i++)
|
||||
{
|
||||
const row = document.createElement("tr");
|
||||
for(var j=0;j < table_cells[i].length; j++)
|
||||
{
|
||||
const cell = document.createElement("td");
|
||||
const cellText = document.createTextNode(table_cells[i][j]);
|
||||
cell.appendChild(cellText);
|
||||
row.appendChild(cell);
|
||||
}
|
||||
table.appendChild(row);
|
||||
}
|
||||
resultsbox.appendChild(table);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.fromLatLon = fromLatLon
|
||||
window.fromUTM = toLatLon
|
||||
window.fromUnknown = fromUnknown
|
||||
window.heightFromUTM = heightFromUTM
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<form action>
|
||||
<label for="input">Enter coordinates: <span class="delicate">(one
|
||||
per line: lat-lon (decimal degrees or not), UTM)</span></label>
|
||||
<textarea name="input" id="input" rows="4">52° 13' 46.8336'' N 21° 0' 44.0244'' E
|
||||
52.229676 N 21.012229 E
|
||||
34U 500835.29 5786584.44</textarea>
|
||||
|
||||
<input type="button" id="convert_button" name="convert_button"
|
||||
value="Convert!"
|
||||
onclick="fromUnknown(document.getElementById('input').value)">
|
||||
|
||||
</form>
|
||||
|
||||
<div id="results"></div>
|
||||
|
||||
</body>
|
208
scripts/convert/utm_converter.js
Normal file
208
scripts/convert/utm_converter.js
Normal file
@ -0,0 +1,208 @@
|
||||
'use strict'
|
||||
|
||||
// This code is MIT licensed.
|
||||
// use link for source:
|
||||
// https://github.com/TimothyGu/utm
|
||||
|
||||
var K0 = 0.9996;
|
||||
|
||||
var E = 0.00669438;
|
||||
var E2 = Math.pow(E, 2);
|
||||
var E3 = Math.pow(E, 3);
|
||||
var E_P2 = E / (1 - E);
|
||||
|
||||
var SQRT_E = Math.sqrt(1 - E);
|
||||
var _E = (1 - SQRT_E) / (1 + SQRT_E);
|
||||
var _E2 = Math.pow(_E, 2);
|
||||
var _E3 = Math.pow(_E, 3);
|
||||
var _E4 = Math.pow(_E, 4);
|
||||
var _E5 = Math.pow(_E, 5);
|
||||
|
||||
var M1 = 1 - E / 4 - 3 * E2 / 64 - 5 * E3 / 256;
|
||||
var M2 = 3 * E / 8 + 3 * E2 / 32 + 45 * E3 / 1024;
|
||||
var M3 = 15 * E2 / 256 + 45 * E3 / 1024;
|
||||
var M4 = 35 * E3 / 3072;
|
||||
|
||||
var P2 = 3 / 2 * _E - 27 / 32 * _E3 + 269 / 512 * _E5;
|
||||
var P3 = 21 / 16 * _E2 - 55 / 32 * _E4;
|
||||
var P4 = 151 / 96 * _E3 - 417 / 128 * _E5;
|
||||
var P5 = 1097 / 512 * _E4;
|
||||
|
||||
var R = 6378137;
|
||||
|
||||
var ZONE_LETTERS = 'CDEFGHJKLMNPQRSTUVWXX';
|
||||
|
||||
export function toLatLon(easting, northing, zoneNum, zoneLetter, northern, strict) {
|
||||
strict = strict !== undefined ? strict : true;
|
||||
|
||||
if (!zoneLetter && northern === undefined) {
|
||||
throw new Error('either zoneLetter or northern needs to be set');
|
||||
} else if (zoneLetter && northern !== undefined) {
|
||||
throw new Error('set either zoneLetter or northern, but not both');
|
||||
}
|
||||
|
||||
if (strict) {
|
||||
if (easting < 100000 || 1000000 <= easting) {
|
||||
throw new RangeError('easting out of range (must be between 100 000 m and 999 999 m)');
|
||||
}
|
||||
if (northing < 0 || northing > 10000000) {
|
||||
throw new RangeError('northing out of range (must be between 0 m and 10 000 000 m)');
|
||||
}
|
||||
}
|
||||
if (zoneNum < 1 || zoneNum > 60) {
|
||||
throw new RangeError('zone number out of range (must be between 1 and 60)');
|
||||
}
|
||||
if (zoneLetter) {
|
||||
zoneLetter = zoneLetter.toUpperCase();
|
||||
if (zoneLetter.length !== 1 || ZONE_LETTERS.indexOf(zoneLetter) === -1) {
|
||||
throw new RangeError('zone letter out of range (must be between C and X)');
|
||||
}
|
||||
northern = zoneLetter >= 'N';
|
||||
}
|
||||
|
||||
var x = easting - 500000;
|
||||
var y = northing;
|
||||
|
||||
if (!northern) y -= 1e7;
|
||||
|
||||
var m = y / K0;
|
||||
var mu = m / (R * M1);
|
||||
|
||||
var pRad = mu +
|
||||
P2 * Math.sin(2 * mu) +
|
||||
P3 * Math.sin(4 * mu) +
|
||||
P4 * Math.sin(6 * mu) +
|
||||
P5 * Math.sin(8 * mu);
|
||||
|
||||
var pSin = Math.sin(pRad);
|
||||
var pSin2 = Math.pow(pSin, 2);
|
||||
|
||||
var pCos = Math.cos(pRad);
|
||||
|
||||
var pTan = Math.tan(pRad);
|
||||
var pTan2 = Math.pow(pTan, 2);
|
||||
var pTan4 = Math.pow(pTan, 4);
|
||||
|
||||
var epSin = 1 - E * pSin2;
|
||||
var epSinSqrt = Math.sqrt(epSin);
|
||||
|
||||
var n = R / epSinSqrt;
|
||||
var r = (1 - E) / epSin;
|
||||
|
||||
var c = _E * pCos * pCos;
|
||||
var c2 = c * c;
|
||||
|
||||
var d = x / (n * K0);
|
||||
var d2 = Math.pow(d, 2);
|
||||
var d3 = Math.pow(d, 3);
|
||||
var d4 = Math.pow(d, 4);
|
||||
var d5 = Math.pow(d, 5);
|
||||
var d6 = Math.pow(d, 6);
|
||||
|
||||
var latitude = pRad - (pTan / r) *
|
||||
(d2 / 2 -
|
||||
d4 / 24 * (5 + 3 * pTan2 + 10 * c - 4 * c2 - 9 * E_P2)) +
|
||||
d6 / 720 * (61 + 90 * pTan2 + 298 * c + 45 * pTan4 - 252 * E_P2 - 3 * c2);
|
||||
var longitude = (d -
|
||||
d3 / 6 * (1 + 2 * pTan2 + c) +
|
||||
d5 / 120 * (5 - 2 * c + 28 * pTan2 - 3 * c2 + 8 * E_P2 + 24 * pTan4)) / pCos;
|
||||
|
||||
return {
|
||||
latitude: toDegrees(latitude),
|
||||
longitude: toDegrees(longitude) + zoneNumberToCentralLongitude(zoneNum)
|
||||
};
|
||||
}
|
||||
|
||||
export function fromLatLon(latitude, longitude, forceZoneNum) {
|
||||
if (latitude > 84 || latitude < -80) {
|
||||
throw new RangeError('latitude out of range (must be between 80 deg S and 84 deg N)');
|
||||
}
|
||||
if (longitude > 180 || longitude < -180) {
|
||||
throw new RangeError('longitude out of range (must be between 180 deg W and 180 deg E)');
|
||||
}
|
||||
|
||||
var latRad = toRadians(latitude);
|
||||
var latSin = Math.sin(latRad);
|
||||
var latCos = Math.cos(latRad);
|
||||
|
||||
var latTan = Math.tan(latRad);
|
||||
var latTan2 = Math.pow(latTan, 2);
|
||||
var latTan4 = Math.pow(latTan, 4);
|
||||
|
||||
var zoneNum;
|
||||
|
||||
if (forceZoneNum === undefined) {
|
||||
zoneNum = latLonToZoneNumber(latitude, longitude);
|
||||
} else {
|
||||
zoneNum = forceZoneNum;
|
||||
}
|
||||
|
||||
var zoneLetter = latitudeToZoneLetter(latitude);
|
||||
|
||||
var lonRad = toRadians(longitude);
|
||||
var centralLon = zoneNumberToCentralLongitude(zoneNum);
|
||||
var centralLonRad = toRadians(centralLon);
|
||||
|
||||
var n = R / Math.sqrt(1 - E * latSin * latSin);
|
||||
var c = E_P2 * latCos * latCos;
|
||||
|
||||
var a = latCos * (lonRad - centralLonRad);
|
||||
var a2 = Math.pow(a, 2);
|
||||
var a3 = Math.pow(a, 3);
|
||||
var a4 = Math.pow(a, 4);
|
||||
var a5 = Math.pow(a, 5);
|
||||
var a6 = Math.pow(a, 6);
|
||||
|
||||
var m = R * (M1 * latRad -
|
||||
M2 * Math.sin(2 * latRad) +
|
||||
M3 * Math.sin(4 * latRad) -
|
||||
M4 * Math.sin(6 * latRad));
|
||||
var easting = K0 * n * (a +
|
||||
a3 / 6 * (1 - latTan2 + c) +
|
||||
a5 / 120 * (5 - 18 * latTan2 + latTan4 + 72 * c - 58 * E_P2)) + 500000;
|
||||
var northing = K0 * (m + n * latTan * (a2 / 2 +
|
||||
a4 / 24 * (5 - latTan2 + 9 * c + 4 * c * c) +
|
||||
a6 / 720 * (61 - 58 * latTan2 + latTan4 + 600 * c - 330 * E_P2)));
|
||||
if (latitude < 0) northing += 1e7;
|
||||
|
||||
return {
|
||||
easting: easting,
|
||||
northing: northing,
|
||||
zoneNum: zoneNum,
|
||||
zoneLetter: zoneLetter
|
||||
};
|
||||
}
|
||||
|
||||
function latitudeToZoneLetter(latitude) {
|
||||
if (-80 <= latitude && latitude <= 84) {
|
||||
return ZONE_LETTERS[Math.floor((latitude + 80) / 8)];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function latLonToZoneNumber(latitude, longitude) {
|
||||
if (56 <= latitude && latitude < 64 && 3 <= longitude && longitude < 12) return 32;
|
||||
|
||||
if (72 <= latitude && latitude <= 84 && longitude >= 0) {
|
||||
if (longitude < 9) return 31;
|
||||
if (longitude < 21) return 33;
|
||||
if (longitude < 33) return 35;
|
||||
if (longitude < 42) return 37;
|
||||
}
|
||||
|
||||
return Math.floor((longitude + 180) / 6) + 1;
|
||||
}
|
||||
|
||||
function zoneNumberToCentralLongitude(zoneNum) {
|
||||
return (zoneNum - 1) * 6 - 180 + 3;
|
||||
}
|
||||
|
||||
function toDegrees(rad) {
|
||||
return rad / Math.PI * 180;
|
||||
}
|
||||
|
||||
function toRadians(deg) {
|
||||
return deg * Math.PI / 180;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user