Commit c0ac78d4 authored by Julian Frosch's avatar Julian Frosch
Browse files

First working approximation; references Issue #7

parent d643d040
......@@ -9,7 +9,7 @@ function Approximator(paths, precision) {
/**
Returns the distance between two points in 2D-Space
*/
var getDistance = function(x1, y1, x2, y2) {
method.getDistance = function(x1, y1, x2, y2) {
var xd = x2 - x1;
var yd = y2 - y1;
return Math.sqrt(xd * xd + yd * yd);
......@@ -19,10 +19,11 @@ var getDistance = function(x1, y1, x2, y2) {
Returns the midpoint between two given points in 2D-Space.
Midpoint is returned as an Array: [x,y]
*/
var getMidpoint = function(x1, y1, x2, y2) {
method.getMidpoint = function(x1, y1, x2, y2) {
var ret = [];
ret.push((x1+x2)/2);
ret.push((y1+y2)/2);
return ret;
}
/**
......@@ -30,9 +31,22 @@ var getMidpoint = function(x1, y1, x2, y2) {
Returns an array containing two arrays with the points for the curves:
[curve1, curve2] where each curve is [p0,p1,p2,p3] and each point is [x,y].
*/
var approximateCurve = function(points) {
var nPoints = [];
// TODO: implement
method.approximateCurve = function(p00, p01, p02, p03) {
// first layer midpoints
var p10 = this.getMidpoint(p00[0], p00[1], p01[0], p01[1]);
var p11 = this.getMidpoint(p01[0], p01[1], p02[0], p02[1]);
var p12 = this.getMidpoint(p02[0], p02[1], p03[0], p03[1]);
// second layer midpoints
var p20 = this.getMidpoint(p10[0], p10[1], p11[0], p11[1]);
var p21 = this.getMidpoint(p11[0], p11[1], p12[0], p12[1]);
// third layer midpoint
var p30 = this.getMidpoint(p20[0], p20[1], p21[0], p21[1]);
var c1 = [p00, p10, p20, p30];
var c2 = [p30, p21, p12, p03];
return [c1, c2];
}
/**
......@@ -41,18 +55,22 @@ var approximateCurve = function(points) {
If it is reached, a "LineTo"-command will be created, else another curve-command.
Both are absolute; this method does not create relative commands.
*/
var buildCurveCommands = function(curves) {
method.buildCurveCommands = function(curves) {
var commands = [];
curves.forEach(function(curve) {
if (getDistance(curve[0][0], curve[0][1], curve[3][0], curve[3][1]) <= this._precision.getPrecision(curve[0][0], curve[0][1])) {
for (var i = 0; i < curves.length; i++) {
var curve = curves[i];
var d = this.getDistance(curve[0][0], curve[0][1], curve[3][0], curve[3][1]);
var p = this._precision.getPrecision(curve[0][0], curve[0][1]);
if (d <= p) {
// transform into "L"-command from p0 -> p3
commands.push(["L", curve[0][0], curve[0][1], curve[3][0], curve[3][1]]);
} else {
// build "C"-command and push it
commands.push(["C", curve[0][0], curve[0][1], curve[1][0], curve[1][1], curve[2][0], curve[2][1], curve[3][0], curve[3][1]]);
}
})
}
return commands;
}
......@@ -60,71 +78,96 @@ var buildCurveCommands = function(curves) {
/**
This method approximates one specific path and returns the approximation as a new SVG-Path.
*/
var approximatePath = function(pathNo) {
// TODO: Maybe change this to only work with the "available" data instead of "copying"
//var path = this._paths[pathNo];
method.approximatePath = function(pathNo) {
var path = this._paths[pathNo];
var nPath = [];
var sPoint = [];
var curveFound = false;
var sPoint = [0,0];
var curveFound = true;
// TODO: Whole thing is not really DRY... maybe find a better solution?
for (var i = 0; i < this._paths[pathNo].length; i++) {
// get every command, approximate curves
var cmd = this._paths[pathNo][i];
switch (cmd[0]) {
case "m":
// adjust sPoint to values (relative)
sPoint[0] += cmd[1];
sPoint[1] += cmd[2];
nPath.push(cmd);
break;
case "M":
// adjust sPoint to values (absolute)
sPoint[0] = cmd[1];
sPoint[1] = cmd[2];
nPath.push(cmd);
break;
case "c":
// approximate one cycle (relative)
curveFound = true;
var p1 = [sPoint[0]+cmd[1],sPoint[1]+cmd[2]];
var p2 = [p1[0]+cmd[3],p1[1]+cmd[4]];
var p3 = [p2[0]+cmd[5],p2[1]+cmd[6]];
var ret = buildCurveCommands(approximatePath(sPoint, p1, p2, p3));
// TODO: Test this
ret.forEach(function(command) {
nPath.push(command);
});
// TODO: set new sPoint!
break;
case "C":
// approximate one cycle (absolute)
curveFound = true;
var p1 = [cmd[1],cmd[2]];
var p2 = [cmd[3],cmd[4]];
var p3 = [cmd[5],cmd[6]];
var ret = buildCurveCommands(approximatePath(sPoint, p1, p2, p3));
// TODO: Test this
ret.forEach(function(command) {
nPath.push(command);
});
break;
case "l":
// copy values, set sPoint (relative)
sPoint[0] += cmd[1];
sPoint[1] += cmd[2];
nPath.push(cmd);
break;
case "L":
// copy values, set sPoint (absolute)
sPoint[0] = cmd[1];
sPoint[1] = cmd[2];
nPath.push(cmd);
break;
default:
// TODO: implement default/failure-behaviour
while (curveFound) {
curveFound = false;
for (var i = 0; i < path.length; i++) {
// get every command, approximate curves
var cmd = path[i];
switch (cmd[0]) {
case "m":
// adjust sPoint to values (relative)
sPoint[0] += cmd[1];
sPoint[1] += cmd[2];
// then push it as an absolute command
nPath.push(["M", sPoint[0], sPoint[1]]);
break;
case "M":
// adjust sPoint to values (absolute)
sPoint[0] = cmd[1];
sPoint[1] = cmd[2];
nPath.push(cmd);
break;
case "c":
// approximate one cycle (relative)
curveFound = true;
var p1 = [sPoint[0]+cmd[1],sPoint[1]+cmd[2]];
var p2 = [p1[0]+cmd[3],p1[1]+cmd[4]];
var p3 = [p2[0]+cmd[5],p2[1]+cmd[6]];
var curves = this.approximateCurve(sPoint, p1, p2, p3);
// set new startingpoint to last point of second curve
sPoint[0] = curves[1][3][0];
sPoint[1] = curves[1][3][1];
// build commands
var commands = this.buildCurveCommands(curves);
// TODO: Test this
// add commands to "new" path
commands.forEach(function(command) {
nPath.push(command);
});
break;
case "C":
// approximate one cycle (absolute)
curveFound = true;
var p1 = [cmd[1],cmd[2]];
var p2 = [cmd[3],cmd[4]];
var p3 = [cmd[5],cmd[6]];
var curves = this.approximateCurve(sPoint, p1, p2, p3);
// set new startingpoint to last point of second curve
sPoint[0] = curves[1][3][0];
sPoint[1] = curves[1][3][1];
// build commands
var commands = this.buildCurveCommands(curves);
// TODO: Test this
// add commands to "new" path
commands.forEach(function(command) {
nPath.push(command);
});
break;
case "l":
// copy values, set sPoint (relative)
sPoint[0] += cmd[1];
sPoint[1] += cmd[2];
// push it as an absolute command
nPath.push(["L", sPoint[0], sPoint[1]]);
break;
case "L":
// copy values, set sPoint (absolute)
sPoint[0] = cmd[1];
sPoint[1] = cmd[2];
nPath.push(cmd);
break;
case "Z":
// just copy z-commands
nPath.push(cmd);
default:
// TODO: implement default/failure-behaviour
// ignore other commands, maybe warn user about it!
}
}
// "reset" values for a new cycle
path = nPath;
nPath = [];
sPoint = [0,0];
}
// when this point of code is reached, all curves in this path have been replaced by lines.
return path;
}
/**
......@@ -132,7 +175,7 @@ var approximatePath = function(pathNo) {
*/
method.approximateData = function(callback) {
for (var i = 0; i < this._paths.length; i++) {
var retPath = approximatePath(i);
var retPath = this.approximatePath(i);
this._paths[i] = retPath;
}
callback(null, this._paths);
......
......@@ -2,26 +2,32 @@ var method = PrecisionMap.prototype;
// constructor
function PrecisionMap(data, min, max) {
this._data = data;
if ((typeof data) == 'object') {
this._data = data;
/*
FYI - NDArray Format: ((x),(y),(r,g,b,a))
Access pixel with ....get(x,y,c)
e.g.:
console.log("Red", pixels.get(0,0,0), pixels.get(0,0,1), pixels.get(0,0,2), pixels.get(0,0,3));
console.log("Blue", pixels.get(1,0,0), pixels.get(1,0,1), pixels.get(1,0,2), pixels.get(1,0,3));
console.log("Black", pixels.get(2,0,0), pixels.get(2,0,1), pixels.get(2,0,2), pixels.get(2,0,3));
*/
/*
FYI - NDArray Format: ((x),(y),(r,g,b,a))
Access pixel with ....get(x,y,c)
e.g.:
console.log("Red", pixels.get(0,0,0), pixels.get(0,0,1), pixels.get(0,0,2), pixels.get(0,0,3));
console.log("Blue", pixels.get(1,0,0), pixels.get(1,0,1), pixels.get(1,0,2), pixels.get(1,0,3));
console.log("Black", pixels.get(2,0,0), pixels.get(2,0,1), pixels.get(2,0,2), pixels.get(2,0,3));
*/
// get the dimensions
var shape = this._data.shape.slice();
this._w = shape[0];
this._h = shape[1];
this._c = shape[2];
// get the dimensions
var shape = this._data.shape.slice();
this._w = shape[0];
this._h = shape[1];
this._c = shape[2];
this._min = min;
this._max = max;
this._diff = max-min;
this._min = min;
this._max = max;
this._diff = max-min;
} else {
// no heatmap provided, we only have the "max"-value
this._data = null;
this._max = data;
}
}
/**
......@@ -29,6 +35,9 @@ function PrecisionMap(data, min, max) {
x and y are floored in the method.
*/
method.getPrecision = function(x, y) {
if (this._data == null) {
return this._max;
}
var value = this._data.get(Math.floor(x), Math.floor(y), 0);
var p = this._max + this._diff * (x/255);
return p;
......
......@@ -50,6 +50,8 @@ $(function(){
console.log("Data fetched, printing:");
console.dir(result);
var PrecisionMap = require('./js/approximation/precisionMap.js');
if (heatmap != null) {
// the user has provided a heatmap, so we need to consider the precision-values from it:
// first, parse the file:
......@@ -65,7 +67,6 @@ $(function(){
console.log(pMax);
var pMin = document.getElementById('pMin').value;
var PrecisionMap = require('./js/approximation/precisionMap.js');
var map = new PrecisionMap(pixels, pMin, pMax);
console.log(map.getPrecision(0,0));
......@@ -74,13 +75,19 @@ $(function(){
var approximator = new Approximator(result, map);
approximator.approximateData(function(err, nPaths) {
// do something more :)
console.dir(nPaths);
});
});
} else {
// the user did not provide a heatmap, so just start the approximator
var approximator = new Approximator(result, null);
// get the pMax-value, this will be the precision for all positions
var pMax = document.getElementById('pMax').value;
var map = new PrecisionMap(pMax);
var approximator = new Approximator(result, map);
approximator.approximateData(function(err, nPaths) {
// do something more :)
console.dir(nPaths);
});
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment