Skip to content

Instantly share code, notes, and snippets.

@theKashey
Created April 15, 2019 07:36
Show Gist options
  • Save theKashey/8f69b8c682a1e7ba8b87c7bbfc5f6948 to your computer and use it in GitHub Desktop.
Save theKashey/8f69b8c682a1e7ba8b87c7bbfc5f6948 to your computer and use it in GitHub Desktop.
osme geometry encoder
var codingCoefficient = 1000000,
base64 = require('./ybase64.js'); // this is just atob
function getShiftsPoint (path, codingCoefficient) {
var res = [];
for (var i = 0, l = path.length, prev = [0, 0]; i < l; i++) {
res.push([
Math.round((path[i][0] - prev[0]) * codingCoefficient),
Math.round((path[i][1] - prev[1]) * codingCoefficient)
]);
prev = path[i];
}
return res;
}
function encodeNbytes (x, N) {
N = N || 4;
var chr = [];
for (var i = 0; i < N; i++) {
chr[i] = x & 0x000000ff;
x = x >> 8;
}
return chr;
}
function decodeNbytes (x, N) {
var point = 0;
N = N || 4;
for (var i = 0; i < N; ++i) {
point |= (x.charCodeAt(i) << (i * 8));
}
return point;
}
function mergeBits (a, b, N) {
var r = 0;
for (var i = 0; i < N; ++i) {
r |= ((a >> i) & 1 | ((b >> i) & 1) << 1) << (i * 2);
}
return r;
}
function revjoinBits (a, b, N) {
var r = a | 0;
for (var i = 0; i < N; ++i) {
r |= ((b >> (N - i)) & 1) << (N + i * 2);
}
return r;
}
function howManyBits (a) {
if (a < Math.pow(2, 8))return 1;
if (a < Math.pow(2, 16))return 2;
if (a < Math.pow(2, 24))return 3;
if (a < Math.pow(2, 32))return 4;
}
function deltacode (to, values) {
// console.log(values);sdf();
var max = 0, st = values[0], deltas = [], delta, deltaSt = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 8: 0};
for (var i = 1, l = values.length; i < l; ++i) {
delta = values[i - 1] - values[i];
deltaSt[howManyBits(Math.abs(delta))]++;
// console.log('d',delta);
deltas.push(delta);
max = Math.max(max, Math.abs(delta));
}
console.log('max delta', max, values.length, deltaSt);
var nb = 3;
{
for (var i = 1, l = values.length; i < l; ++i) {
to.push.apply(to, encodeNbytes(deltas[i], nb));
}
}
}
function encodePath (path, codingCoefficient) {
var shifts = getShiftsPoint(path, codingCoefficient),
result = [];
result = result.concat(
encodeNbytes(shifts[0][0]),
encodeNbytes(shifts[0][1])
);
for (var i = 1, l = shifts.length; i < l; i++) {
result.push.apply(result, encodeNbytes(shifts[i][0]));
result.push.apply(result, encodeNbytes(shifts[i][1]));
}
return base64.to(result);
}
function getBounds (path) {
var min = path[0].slice(0),
max = path[0].slice(0);
for (var i = 1, l = path.length; i < l; i++) {
min[0] = Math.min(min[0], path[i][0]);
min[1] = Math.min(min[1], path[i][1]);
max[0] = Math.max(max[0], path[i][0]);
max[1] = Math.max(max[1], path[i][1]);
}
return [min, max];
}
function encodeRectPath (path, sizeFactor) {
sizeFactor = sizeFactor || 0xFFFF;
var bounds = getBounds(path),
dim = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]],
result = [],
fraction = 2,
fx = sizeFactor / dim[0],
fy = sizeFactor / dim[1];
result = result.concat(
encodeNbytes(codingCoefficient * bounds[0][0], 4),
encodeNbytes(codingCoefficient * bounds[0][1], 4),
encodeNbytes(codingCoefficient * bounds[1][0], 4),
encodeNbytes(codingCoefficient * bounds[1][1], 4)
);
var lastpoint = [];
for (var i = 0, l = path.length; i < l; i++) {
var point = [
Math.round((path[i][0] - bounds[0][0]) * fx),
Math.round((path[i][1] - bounds[0][1]) * fy)
];
if (lastpoint[0] != point[0] || lastpoint[1] != point[1]) {
lastpoint = point;
result.push.apply(result, encodeNbytes(point[0], fraction));
result.push.apply(result, encodeNbytes(point[1], fraction));
}
}
return base64.to(result);
}
function encodeRect32Path (path, sizeFactor) {
sizeFactor = 0xFFFF;
var bounds = getBounds(path),
dim = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]],
result = [],
fraction = 4,
fx = sizeFactor / dim[0],
fy = sizeFactor / dim[1];
result = result.concat(
encodeNbytes(codingCoefficient * bounds[0][0], 4),
encodeNbytes(codingCoefficient * bounds[0][1], 4),
encodeNbytes(codingCoefficient * bounds[1][0], 4),
encodeNbytes(codingCoefficient * bounds[1][1], 4)
);
var lastpoint = [],
values = [];
for (var i = 0, l = path.length; i < l; i++) {
var point = [
Math.round((path[i][0] - bounds[0][0]) * fx),
Math.round((path[i][1] - bounds[0][1]) * fy)
];
if (lastpoint[0] != point[0] || lastpoint[1] != point[1]) {
lastpoint = point;
var dpoint = mergeBits(point[0], point[1], 16);
result.push.apply(result, encodeNbytes(dpoint, fraction));
}
}
return base64.to(result);
}
function encodeRectZPath (path, sizeFactor) {
var z = require('zcode.js');
var h = require('hilbertCode.js');
sizeFactor = 0xFFFF;
var bounds = getBounds(path),
dim = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]],
result = [],
fraction = 3,
fx = sizeFactor / dim[0],
fy = sizeFactor / dim[1];
result = result.concat(
encodeNbytes(codingCoefficient * bounds[0][0], 4),
encodeNbytes(codingCoefficient * bounds[0][1], 4),
encodeNbytes(codingCoefficient * bounds[1][0], 4),
encodeNbytes(codingCoefficient * bounds[1][1], 4)
);
var r1 = result.slice(0), r2 = result.slice(0), cx = 0;
var lastpoint = [],
values = [];
for (var i = 0, l = path.length; i < l; i++) {
var point = [
Math.round((path[i][0] - bounds[0][0]) * fx),
Math.round((path[i][1] - bounds[0][1]) * fy)
];
//var cz1 = z.z(point, [[0, 0], [0xFFFF, 0xFFFF]], 16).code;
// console.log(cz1,point);
//cz1 = cz1.code;
var cz1 = h.toCode([point[0] / sizeFactor, point[1] / sizeFactor]);
//console.log(cz1);
// dfg();
//var cz2 = z.z(point, [[0, 0xFFFF], [0, 0xFFFF]], 8).code;
if (cz1 != z) {
if (cx++ % 2 && 0) {
r1.push(revjoinBits(cz2, lastpoint, 8));
lastpoint = cz2;
} else {
lastpoint = cz1;
//values.push(cz1);
/*
var t = encodeNbytes(cz1, 8);
console.log(cz1,4,t);
var d = decodeNbytes(t, 4);
if (t != d) {
console.log(t, '!=', d, cz1);
}*/
r1.push.apply(r1, encodeNbytes(cz1, 4));
}
//r2.push(cz2);
}
}
//deltacode(r1, values);
return base64.to(r1);//[base64.to(r1), base64.to(r2)];
}
function decodeRectPath (encodedCoordinates) {
function decodeNbytes (x, N) {
var point = 0;
for (var i = 0; i < N; ++i) {
point |= (x.charCodeAt(i) << (i * 8));
}
return point;
}
var byteVector = base64.from(encodedCoordinates),
byteVectorLength = byteVector.length,
codingCoefficient = 1000000,
bounds = [
[decodeNbytes(byteVector.substr(0, 4), 4) / codingCoefficient, decodeNbytes(byteVector.substr(4, 4), 4) / codingCoefficient],
[decodeNbytes(byteVector.substr(8, 4), 4) / codingCoefficient, decodeNbytes(byteVector.substr(12, 4), 4) / codingCoefficient]
],
dim = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]],
result = [],
index = 16,
fraction = 2,
fx = dim[0] / 0xFFFF,
fy = dim[1] / 0xFFFF;
while (index < byteVectorLength) {
var x = byteVector.substr(index, fraction),
y = byteVector.substr(index + fraction, fraction),
pointx = decodeNbytes(x, fraction),
pointy = decodeNbytes(y, fraction);
result.push([pointx * fx + bounds[0][0], pointy * fy + bounds[0][1]]);
index += fraction * 2;
}
return result;
}
function decodePath (encodedCoordinates, codingCoefficient) {
var byteVector = base64.from(encodedCoordinates),
byteVectorLength = byteVector.length,
index = 0,
prev = [0, 0],
result = [];
while (index < byteVectorLength) {
var x = byteVector.substr(index, 4),
y = byteVector.substr(index + 4, 4),
pointx = decodeNbytes(x),
pointy = decodeNbytes(y);
var vector = [pointx / codingCoefficient, pointy / codingCoefficient],
point = [vector[0] + prev[0], vector[1] + prev[1]];
prev = point;
result.push(point);
index += 8;
}
return result;
};
exports.encodeRect32 = encodeRect32Path;
exports.encodeRectZ = encodeRectZPath;
exports.encodeRect = encodeRectPath;
exports.decodeRect = decodeRectPath;
exports.encode = function (path, components) {
if (components == 1) {
return encodeStrip(path, 1);
} else {
return encodePath(path, codingCoefficient);
}
}
exports.decode = function (string, components) {
if (components == 1) {
return decodeStrip(string, 1);
} else {
return decodePath(string, codingCoefficient);
}
}
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
Base64 = {
baseString: keyStr,
to: function (input) {
var inputIsString = typeof input == "string";
if (typeof btoa != "undefined") {
if (!inputIsString) {
input = String.fromCharCode.apply(String, input);
}
return btoa(input).replace(/\//g, '_').replace(/\+/g, '-');
} else {
var output = [],
chr1, chr2, chr3, enc1, enc2, enc3, enc4,
i = 0,
l = input.length;
while (i < l) {
if (inputIsString) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
} else {
chr1 = input[i++];
chr2 = input[i++];
chr3 = input[i++];
}
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output.push(keyStr.charAt(enc1), keyStr.charAt(enc2), keyStr.charAt(enc3), keyStr.charAt(enc4));
}
return output.join("");
}
},
from: function (input) {
if (typeof atob != "undefined") {
return atob(input.replace(/_/g, '/').replace(/-/g, '+'));
} else {
var output = [],
chr1, chr2, chr3,
enc1, enc2, enc3, enc4,
i = 0,
l = (input = input.replace(/[^A-Za-z0-9\-_\=]/g, "")).length;
while (i < l) {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output.push(String.fromCharCode(chr1));
if (enc3 != 64) {
output.push(String.fromCharCode(chr2));
}
if (enc4 != 64) {
output.push(String.fromCharCode(chr3));
}
}
return output.join("");
}
}
};
exports.to = Base64.to;
exports.from = Base64.from;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment