Created
August 31, 2016 22:24
-
-
Save Redchards/f0b2cd2c3f4669717c8c671b2d4ddb33 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
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <script src="potato.js"></script> | |
| </head> | |
| <body onload="init();"> | |
| </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 graphZone; | |
| var ctx; | |
| var axes; | |
| var container; | |
| var points = new Array(); | |
| var pointsRef = new Array(); | |
| var graphZoneBaseHeight = 200; | |
| var graphZoneBaseWidth = 600; | |
| var test2DSpline = [{x : 1.31, y : -1.94}, | |
| {x : 2.89, y : 1.50}, | |
| {x : 2.05, y : 1.47}, | |
| {x : 1.67, y : 1.40}, | |
| {x : 3.12, y : 1.77}, | |
| {x : 2.05, y : 0.07}, | |
| {x : 0.23, y : 0.77}, | |
| {x : 3.04, y : 0.41}, | |
| {x : 1.31, y : -1.94}]; | |
| var test2DSpline2 = [{x : 2.5, y : 0}, | |
| {x : 1.3, y : -0.25}, | |
| {x : -0.25, y : 1.3}, | |
| {x : 0, y : 2.5}, | |
| {x : 0.25, y : 1.3}, | |
| {x : -1.3, y : -0.25}, | |
| {x : -2.5, y : 0}, | |
| {x : -1.3, y : 0.25}, | |
| {x : 0.25, y : -1.3}, | |
| {x : 0, y : -2.5}, | |
| {x : -0.25, y : -1.3}, | |
| {x : 1.3, y : 0.25}, | |
| {x : 2.5, y : 0}]; | |
| function assert(cond, msg) { | |
| if(!cond) { | |
| msg = msg || "Assert failed"; | |
| if(typeof Error !== "undefined") { | |
| throw new Error(msg); | |
| } | |
| throw message; | |
| } | |
| } | |
| function ProxyArray() { | |
| //Object.setPrototypeOf(this, Array.prototype); | |
| this.innerArray = new Array(); | |
| this.innerArray.__proto__ = ProxyArray.prototype; | |
| return new Proxy(this, | |
| { | |
| set : function(target, property, value) { | |
| target.innerArray[property] = value; | |
| console.log("Set"); | |
| } | |
| }) | |
| } | |
| ProxyArray.prototype = new Array; | |
| function onHandlersClick() { | |
| alert("clicked !"); | |
| } | |
| function init() { | |
| //graphZone = document.getElementById("graph"); | |
| //borders = document.createElement("div"); | |
| //borders.style.border = "1px dotted grey"; | |
| //handlers.addEventListener("click", onHandlersClick); | |
| //borders.style.width = graphZoneBaseWidth + "px"; | |
| //borders.style.height = graphZoneBaseHeight + "px"; | |
| //borders.style.position = "relative"; | |
| //document.body.appendChild(borders); | |
| container = document.createElement("div"); | |
| document.body.appendChild(container); | |
| graphZone = document.createElement("canvas"); | |
| graphZone.setAttribute("id", "graph"); | |
| graphZone.setAttribute("width", graphZoneBaseWidth); | |
| graphZone.setAttribute("height", graphZoneBaseHeight); | |
| graphZone.style.top = "0px"; | |
| graphZone.style.left = "0px"; | |
| graphZone.style.position = "absolute"; | |
| graphZone.style.border = "1px dotted grey"; | |
| graphZone.style.float = "left"; | |
| container.appendChild(graphZone); | |
| //<canvas id="graph" width="500" height="200"></canvas> | |
| //console.log(handlers.offsetHeight); | |
| ctx = graphZone.getContext("2d"); | |
| ctx.strokeStyle = "black"; | |
| var topLeftHandler = createHandler(); | |
| topLeftHandler.style.top = "0"; | |
| topLeftHandler.style.left = "0"; | |
| container.appendChild(topLeftHandler); | |
| initGraph(); | |
| //plotFunction(Math.cos, -5, 5, 100); | |
| //plotFunction(Math.sin, -5, 5, 100); | |
| //plotFunction(Math.exp, -5, 5, 100); | |
| var addPointButton = document.createElement("div"); | |
| addPointButton.style.width = "100px"; | |
| addPointButton.style.height = "20px"; | |
| addPointButton.style.border = "1px solid black"; | |
| addPointButton.style.float = "right"; | |
| addPointButton.addEventListener("click", addPointButtonClick); | |
| addPointButton.style.cursor = "pointer"; | |
| addPointButton.innerHTML = "Add point"; | |
| addPointButton.style.textAlign = "center"; | |
| document.body.appendChild(addPointButton); | |
| addPoint(1, 1); | |
| addPoint(1.35, 1.25); | |
| addPoint(2.36, -1.3); | |
| addPoint(3.56, -1.7); | |
| addPoint(4.56, -1.7); | |
| addPoint(4.96, -1.0); | |
| addPoint(5.96, -1.45); | |
| addPoint(-5.96, -1.45); | |
| plot([1, 2, 3, -2], [0, 2, 1, 2]); | |
| draw2DSplinesFrom(test2DSpline2, 20); | |
| /*ctx.moveTo(axes.origin.x, axes.origin.y); | |
| ctx.lineTo(axes.origin.x -1*axes.scale.x, axes.origin.y + 1*axes.scale.y); | |
| ctx.moveTo(axes.origin.x, axes.origin.y); | |
| ctx.lineTo(axes.origin.x +1*axes.scale.x, axes.origin.y + 1*axes.scale.y); | |
| ctx.moveTo(axes.origin.x, axes.origin.y - 1*axes.scale.y); | |
| ctx.lineTo(axes.origin.x -1*axes.scale.x, axes.origin.y - 1*axes.scale.y); | |
| ctx.moveTo(axes.origin.x, axes.origin.y - 1*axes.scale.y); | |
| ctx.lineTo(axes.origin.x +1*axes.scale.x, axes.origin.y - 1*axes.scale.y); | |
| ctx.moveTo(axes.origin.x + 0.5*axes.scale.x, axes.origin.y - 1.5*axes.scale.y); | |
| ctx.arc(axes.origin.x, axes.origin.y - 1.5*axes.scale.y, 1*axes.scale.y/2, 0, 2 * Math.PI, false); | |
| ctx.stroke();*/ | |
| //console.log(computeSecondSplineDerivatives(points)); | |
| drawSplinesFrom(pointsRef); | |
| } | |
| function initGraph() { | |
| drawAxes(); | |
| drawGrid({x:2, y:2}); | |
| } | |
| function plotFunction(func, from, to, samples) { | |
| console.log(from, to); | |
| assert(from < to, "'from' should be greater than 'to' !"); | |
| var interval = (to - from); | |
| var beginPosition = axes.origin.x + from*axes.scale.x + 0.5; | |
| var endPosition = axes.origin.x + to*axes.scale.x + 0.5; | |
| var scale = interval / samples; | |
| ctx.beginPath(); | |
| ctx.moveTo(beginPosition, axes.origin.y - func(from)*axes.scale.y); | |
| //console.log("From : " + from); | |
| for(var i = scale; i < interval; i += scale) { | |
| ctx.lineTo(beginPosition + i*axes.scale.x, axes.origin.y - func(from + i)*axes.scale.y - 0.5); | |
| //console.log((beginPosition) + " : " + (from + i) + " : " + func(from + i)); | |
| } | |
| ctx.lineTo(endPosition, axes.origin.y - func(to)*axes.scale.y - 0.5); | |
| ctx.stroke(); | |
| } | |
| function plot(x, y) { | |
| assert(x.length == y.length, "x and y arrays should contain the same number of arguments"); | |
| var beginXPosition = axes.origin.x + x[0]*axes.scale.x + 0.5; | |
| var beginYPosition = axes.origin.y - y[0]*axes.scale.y - 0.5; | |
| ctx.beginPath(); | |
| ctx.moveTo(beginXPosition, beginYPosition); | |
| for(var i = 1; i < x.length; ++i) { | |
| ctx.lineTo(axes.origin.x + x[i]*axes.scale.x + 0.5, axes.origin.y - y[i]*axes.scale.y - 0.5); | |
| } | |
| ctx.stroke(); | |
| } | |
| function drawAxes() { | |
| axes = new Object(); | |
| axes.origin = new Object(); | |
| axes.scale = new Object(); | |
| axes.origin.x = graphZone.width * 0.5; | |
| axes.origin.y = graphZone.height * 0.5; | |
| axes.scale.x = 50; | |
| axes.scale.y = 50; | |
| ctx.beginPath(); | |
| ctx.moveTo(0.5, axes.origin.y + 0.5); | |
| ctx.lineTo(graphZone.width + 0.5, axes.origin.y + 0.5); | |
| ctx.moveTo(axes.origin.x + 0.5, -0.5); | |
| ctx.lineTo(axes.origin.x + 0.5, graphZone.height - 0.5); | |
| ctx.stroke(); | |
| } | |
| function drawGrid(resolution) { | |
| var oldStrokeStyle = new String(ctx.strokeStyle); | |
| var oldLineWidth = new Number(ctx.lineWidth); | |
| ctx.strokeStyle = "grey"; | |
| ctx.lineWidth = 0.5; | |
| ctx.beginPath(); | |
| var beginXValue = (axes.scale.x / resolution.x); | |
| var beginYValue = (axes.scale.y / resolution.y); | |
| var tmp = parseInt(graphZone.width)/axes.scale.x; | |
| var floored = Math.floor(tmp); | |
| var diffX = (tmp - floored); | |
| //console.log(diffX); | |
| // = parseInt(graphZone.; | |
| if(tmp != floored) { | |
| // DO adjustment | |
| beginXValue = diffX; | |
| //console.log(beginXValue); | |
| } | |
| tmp = parseInt(graphZone.height)/axes.scale.y; | |
| floored = Math.floor(tmp); | |
| var diffY = (tmp - floored); | |
| //console.log(diffY); | |
| if(tmp != floored) { | |
| beginYValue = diffY; | |
| //console.log(beginYValue); | |
| } | |
| for(var i = beginXValue + 0.5; i < graphZone.width; i += axes.scale.x/resolution.x) { | |
| ctx.moveTo(i, 0); | |
| ctx.lineTo(i, graphZone.height); | |
| } | |
| for(var i = Math.floor(beginYValue) - 0.5; i < graphZone.height; i += axes.scale.y/resolution.y) { | |
| ctx.moveTo(0, i); | |
| ctx.lineTo(graphZone.width, i); | |
| } | |
| ctx.stroke(); | |
| ctx.strokeStyle = oldStrokeStyle; | |
| ctx.lineWidth = oldLineWidth; | |
| } | |
| function onHandlerDrag(e) { | |
| console.log("drag"); | |
| } | |
| function log2DPosition(x, y) { | |
| console.log(x + " : " + y); | |
| } | |
| function startMove(e) { | |
| e = e || window.event; | |
| var origPosX = e.clientX; | |
| var origPosY = e.clientY; | |
| log2DPosition(origPosX, origPosY); | |
| var target = e.target; | |
| var parent = target.parentElement; | |
| var parentOrigHeight = parseInt(graphZone.height); | |
| var parentOrigWidth = parseInt(graphZone.width); | |
| var parentOrigLeft = (parseInt(graphZone.style.left) || 0); | |
| var parentOrigTop = (parseInt(graphZone.style.top) || 0 ); | |
| var topPosition = parseInt(target.style.top.replace("px", "")) | |
| || parseInt(target.style.bottom.replace("px", "")) | |
| || 0; | |
| var leftPosition = parseInt(target.style.left.replace("px", "")) | |
| || parseInt(target.style.right.replace("px", "")) | |
| || 0; | |
| document.onmousemove = function(e) { | |
| e = e || window.event; | |
| var posX = e.clientX; | |
| var posY = e.clientY; | |
| var diffX = posX - origPosX; | |
| var diffY = posY - origPosY; | |
| targetX = diffX + leftPosition; | |
| targetY = diffY + topPosition; | |
| doMove(target, targetX, targetY); | |
| //log2DPosition(parentOrigWidth - diffX + "px", parentOrigHeight - diffY); | |
| graphZone.width = parentOrigWidth - diffX; | |
| graphZone.height = parentOrigHeight - diffY; | |
| log2DPosition(parentOrigWidth) | |
| graphZone.style.left = parentOrigLeft + diffX + "px"; | |
| graphZone.style.top = parentOrigTop + diffY + "px"; | |
| //console.log("Top : " + parent.style.top); | |
| } | |
| //console.log("left : " + leftPosition + "\ntop : " + topPosition); | |
| } | |
| function stopMove() { | |
| console.log("Unhook event"); | |
| document.onmousemove = function(){} | |
| initGraph(); | |
| } | |
| function doMove(e, x, y) { | |
| e.style.left = x + "px"; | |
| e.style.top = y + "px"; | |
| } | |
| function startMovePoint(e) { | |
| e = e || window.event; | |
| var origPosX = e.clientX; | |
| var origPosY = e.clientY; | |
| var target = e.target; | |
| var point = target; | |
| var origPointX = point.x; | |
| var origPointY = point.y; | |
| var topPosition = parseInt(target.style.top.replace("px", "")) || 0; | |
| var leftPosition = parseInt(target.style.left.replace("px", "")) || 0; | |
| document.onmousemove = function(e) { | |
| e = e || window.event; | |
| var diffX = e.clientX - origPosX; | |
| var diffY = e.clientY - origPosY; | |
| target.style.top = topPosition + diffY + "px"; | |
| target.style.left = leftPosition + diffX + "px"; | |
| point.x = origPointX + diffX/axes.scale.x; | |
| point.y = origPointY - diffY/axes.scale.y; | |
| clearCanvas(); | |
| initGraph(); | |
| pointsRef.sort(comparePoints); | |
| drawSplinesFrom(pointsRef); | |
| } | |
| document.onmouseup = stopMovePoint; | |
| } | |
| function stopMovePoint(e) { | |
| document.onmousemove = function() {} | |
| } | |
| function clearCanvas() { | |
| ctx.clearRect(0, 0, graphZone.width, graphZone.height); | |
| } | |
| function createHandler() { | |
| var handler = document.createElement("div"); | |
| handler.style.border = "1px solid black"; | |
| handler.style.position = "absolute"; | |
| handler.style.height = "5px"; | |
| handler.style.width = "5px"; | |
| handler.addEventListener('mousedown', startMove); | |
| handler.addEventListener('mouseup', stopMove); | |
| handler.setAttribute("draggable", "true"); | |
| return handler; | |
| } | |
| function addPoint(x, y) { | |
| var point = document.createElement("div"); | |
| point.style.top = axes.origin.y - y*axes.scale.y - 3 + "px"; | |
| point.style.left = axes.origin.x + x*axes.scale.x - 3 + "px"; | |
| console.log(point.style.left); | |
| point.style.border = "1px solid black"; | |
| point.style.borderRadius = "100%"; | |
| point.style.height = "6px"; | |
| point.style.width = "6px"; | |
| point.style.position = "absolute"; | |
| point.addEventListener("mousedown", startMovePoint); | |
| point.style.cursor = "all-scroll"; | |
| //point.id = points.length || "0"; | |
| point.x = x; | |
| point.y = y; | |
| pointsRef.push(point); | |
| container.appendChild(point); | |
| points.push({x:x, y:y, htmlElement:point}); | |
| pointsRef.sort(comparePoints); | |
| for(var elem of pointsRef) { | |
| console.log(elem); | |
| } | |
| return point; | |
| } | |
| function comparePoints(p1, p2) { | |
| log2DPosition(p1.x, p2.x); | |
| console.log(p1.x > p2.x); | |
| if(p1.x > p2.x) { | |
| return 1; | |
| } | |
| else if(p1.x < p2.x) { | |
| return -1; | |
| } | |
| return 0; | |
| /*if((greater && (parseInt(p1.id) < parseInt(p2.id))) || (!greater && (parseInt(p1.id) > parseInt(p2.id)))) { | |
| var tmp = new String(p1.htmlElement.id); | |
| p1.htmlElement.id = new String(p2.htmlElement.id); | |
| p2.htmlElement.id = tmp; | |
| } | |
| return greater;*/ | |
| } | |
| function addPointButtonClick(e) { | |
| x = e.clientX/axes.scale.x - axes.origin.x/axes.scale.x ; | |
| y = axes.origin.y/axes.scale.y - e.clientY/axes.scale.y; | |
| log2DPosition(e.clientX, y) | |
| var newPoint = addPoint(x, y); | |
| startMovePoint({target: newPoint, clientX: e.clientX, clientY: e.clientY}); | |
| } | |
| function drawSplinesFrom(points) { | |
| // Should check if sorted first. | |
| // points.sort(comparePoints); | |
| var splines = generateSplineFrom(points); | |
| for(var i = 0; i < points.length - 1; ++i) { | |
| plotFunction(splines[i], points[i].x, points[i + 1].x, 20); | |
| } | |
| } | |
| function euclideanNorm(u) { | |
| return Math.sqrt(u.x*u.x + u.y*u.y); | |
| } | |
| function draw2DSplinesFrom(points, samples) { | |
| var parameters = new Array(); | |
| var xPoints = new Array(); | |
| var yPoints = new Array(); | |
| parameters.push(0); | |
| var xSpline, ySpline; | |
| for(var i = 1; i < points.length; ++i) { | |
| //console.log({x : points[i].x - points[i - 1].x, y : points[i].y * points[i - 1].y}) | |
| parameters[i] = parameters[i - 1] + euclideanNorm({x : points[i].x - points[i - 1].x, y : points[i].y - points[i - 1].y}); | |
| } | |
| console.log(parameters); | |
| for(var i = 0; i < points.length; ++i) { | |
| xPoints.push({y : points[i].x, x : parameters[i]}); | |
| } | |
| for(var i = 0; i < points.length; ++i) { | |
| yPoints.push({y : points[i].y, x : parameters[i]}) | |
| } | |
| xSpline = generate2DSplineFrom(xPoints); | |
| ySpline = generate2DSplineFrom(yPoints); | |
| var xCoord = new Array(), | |
| yCoord = new Array(); | |
| for(var i = 0; i < parameters.length - 1; ++i) { | |
| var interval = parameters[i + 1] - parameters[i]; | |
| var step = interval / samples; | |
| for(var j = 1; j <= samples; ++j) { | |
| //console.log(j*step) | |
| xCoord.push(xSpline[i](parameters[i] + j*step)); | |
| yCoord.push(ySpline[i](parameters[i] + j*step)); | |
| } | |
| console.log(xCoord, yCoord); | |
| } | |
| plot(xCoord, yCoord); | |
| } | |
| function generate2DSplineFrom(points) { | |
| var splines = new Array(); | |
| var curvatures = computeSecondPeriodicSplineDerivatives(points); | |
| var splineGenerator = function(i) { | |
| return { | |
| function(x) { | |
| var hi = (points[i + 1].x - points[i].x); | |
| var A = (curvatures[i + 1] - curvatures[i])/(6*hi); | |
| var B = (curvatures[i]/2); | |
| var C = ((-(hi)*curvatures[i + 1])/6) - (hi)*curvatures[i]/3 + (points[i + 1].y - points[i].y)/(hi); | |
| var xxi = (x - points[i].x); | |
| var res = points[i].y + (xxi)*(C + (xxi)*(B + (xxi)*A)); | |
| return res; | |
| } | |
| } | |
| } | |
| for(var i = 0; i < points.length - 1; ++i) { | |
| splines[i] = splineGenerator(i).function; | |
| } | |
| return splines; | |
| } | |
| function generateSplineFrom(points) { | |
| var splines = new Array(); | |
| var curvatures = computeSecondSplineDerivatives(points); | |
| var splineGenerator = function(i) { | |
| return { | |
| function(x) { | |
| var hi = (points[i + 1].x - points[i].x); | |
| var A = (curvatures[i + 1] - curvatures[i])/(6*hi); | |
| var B = (curvatures[i]/2); | |
| var C = ((-(hi)*curvatures[i + 1])/6) - (hi)*curvatures[i]/3 + (points[i + 1].y - points[i].y)/(hi); | |
| var xxi = (x - points[i].x); | |
| var res = points[i].y + (xxi)*(C + (xxi)*(B + (xxi)*A)); | |
| return res; | |
| } | |
| } | |
| } | |
| for(var i = 0; i < points.length - 1; ++i) { | |
| splines[i] = splineGenerator(i).function; | |
| } | |
| return splines; | |
| } | |
| function evalSpline(splineFunc, from, to, samples) { | |
| var step = (to - from)/samples; | |
| var evalValues = new Array(); | |
| for(var i = from; i < to; i += step) { | |
| evalValue.push(splineFunc(i)); | |
| } | |
| } | |
| function tridiagonalSolve(a, b, c, d) { | |
| //assert(a.length == d.lenght) | |
| } | |
| function solveTridiagonal(a, b, c, d) { | |
| // Condition implies c.length == d.length | |
| // assert(b.length == (c.length + 1) && b.length == (d.length + 1) && a.length == b.length, | |
| // "The system is not tridiagonal"); | |
| //console.log(a, b, c, d) | |
| var results = new Array(); | |
| c[0] = c[0]/b[0]; | |
| d[0] = d[0]/b[0]; | |
| for(var i = 1; i < d.length; ++i) { | |
| //console.log(d.length + " " + c.length) | |
| var div = b[i] - a[i - 1] * c[i - 1]; | |
| c[i] = c[i] / (div); | |
| d[i] = (d[i] - (a[i - 1] * d[i - 1])) / div; | |
| //console.log("After " + d[i] + a[i]) | |
| } | |
| results[d.length - 1] = d[d.length - 1]; | |
| for(var i = d.length - 2; i >= 0; --i) { | |
| //console.log(d.length - 1 - i) | |
| results[i] = d[i] - c[i] * results[i + 1]; | |
| } | |
| //console.log(results); | |
| return results; | |
| } | |
| // Solving the tridiagonal system using Thomas algorithm. | |
| function computeSecondSplineDerivatives(points) { | |
| var a = new Array(), | |
| b = new Array(), | |
| c = new Array(), | |
| d = new Array(); | |
| var point2 = points[2]; | |
| var x2 = (point2 && point2.x) || 0; | |
| var y2 = (point2 && point2.y) || 0; | |
| b.push(2 * (x2 - points[0].x)); | |
| c.push(x2 - points[1].x); | |
| d.push(6 * (((y2 - points[1].y) / (x2 - points[1].x)) | |
| - ((points[1].y - points[0].y) / (points[1].x - points[0].x)))); | |
| var hi, him; | |
| for(var i = 2; i < points.length - 2; ++i) { | |
| hi = (points[i+1].x - points[i].x); | |
| him = (points[i].x - points[i - 1].x); | |
| a.push(points[i].x - points[i - 1].x); | |
| b.push(2*(hi + him)); | |
| c.push(hi); | |
| d.push((6*(((points[i + 1].y - points[i].y) / (hi)) | |
| - ((points[i].y - points[i - 1].y) / (him))))); | |
| } | |
| var i = points.length - 2; | |
| hi = (points[i+1].x - points[i].x); | |
| him = (points[i].x - points[i - 1].x); | |
| a.push(points[i].x - points[i - 1].x); | |
| b.push(2*(hi + him)); | |
| d.push((6*(((points[i + 1].y - points[i].y) / (hi)) | |
| - ((points[i].y - points[i - 1].y) / (him))))); | |
| var results = new Array(); | |
| var toConcat = solveTridiagonal(a, b, c, d); | |
| results[0] = 0; | |
| results = results.concat(toConcat); | |
| //console.log(toConcat); | |
| results.push(0); | |
| return results; | |
| } | |
| function computeSecondPeriodicSplineDerivatives(points) { | |
| var a = new Array(), | |
| b = new Array(), | |
| c = new Array(), | |
| d1 = new Array(), | |
| d2 = new Array(); | |
| var results = new Array(); | |
| var point2 = points[2]; | |
| var x2 = (point2 && point2.x) || 0; | |
| var y2 = (point2 && point2.y) || 0; | |
| b.push(2 * (x2 - points[0].x)); | |
| c.push(x2 - points[1].x); | |
| d1.push(6 * (((y2 - points[1].y) / (x2 - points[1].x)) | |
| - ((points[1].y - points[0].y) / (points[1].x - points[0].x)))); | |
| d2.push(-(points[points.length - 1].x - points[points.length - 2].x)); | |
| var hi, him; | |
| for(var i = 2; i < points.length - 3; ++i) { | |
| hi = (points[i+1].x - points[i].x); | |
| him = (points[i].x - points[i - 1].x); | |
| a.push(points[i].x - points[i - 1].x); | |
| b.push(2*(hi + him)); | |
| c.push(hi); | |
| d1.push((6*(((points[i + 1].y - points[i].y) / (hi)) | |
| - ((points[i].y - points[i - 1].y) / (him))))); | |
| d2.push(0); | |
| } | |
| var i = points.length - 3; | |
| hi = (points[i+1].x - points[i].x); | |
| him = (points[i].x - points[i - 1].x); | |
| a.push(points[i].x - points[i - 1].x); | |
| b.push(2*(hi + him)); | |
| d1.push((6*(((points[i + 1].y - points[i].y) / (hi)) | |
| - ((points[i].y - points[i - 1].y) / (him))))); | |
| //d2.push(-(points[0].x - points[1].x)); | |
| d2.push(-(points[points.length - 1].x - points[points.length - 2].x)); | |
| var firstSolution = solveTridiagonal(a, b, c, d1); | |
| var secondSolution = solveTridiagonal(a, b, c, d2); | |
| ++i; | |
| hi = (points[i+1].x - points[i].x); | |
| him = (points[i].x - points[i - 1].x); | |
| xn = (6*(((points[i + 1].y - points[i].y) / (hi)) - ((points[i].y - points[i - 1].y) / (him))) | |
| - hi*firstSolution[0] - him*firstSolution[firstSolution.length - 1]) / | |
| (2*(hi + him) + hi*secondSolution[0] + him*secondSolution[secondSolution.length - 1]); | |
| console.log(xn) | |
| results.push(xn) | |
| for(var i = 1; i < firstSolution.length + 1; ++i) { | |
| results[i] = firstSolution[i - 1] + secondSolution[i - 1]*xn | |
| } | |
| results.push(xn); | |
| results.push(results[1]); | |
| console.log(results.length) | |
| return results; | |
| } | |
| // The old routine to compute second derivative. The new is a bit slower, but cleaner. | |
| function computeSecondSplineDerivativesOld(points) { | |
| // Add check if there is only one point. | |
| var | |
| c = new Array(), | |
| d = new Array(); | |
| var results = new Array(); | |
| var point2 = points[2]; | |
| var x2 = (point2 && point2.x) || 0; | |
| var y2 = (point2 && point2.y) || 0; | |
| var b0 = 2 * (x2 - points[0].x) | |
| c[0] = (x2 - points[1].x)/ b0; | |
| d[0] = 6 * (((y2 - points[1].y) / (x2 - points[1].x)) | |
| - ((points[1].y - points[0].y) / (points[1].x - points[0].x))) / b0; | |
| for(var i = 2; i < points.length - 1; ++i) { | |
| var hi = (points[i+1].x - points[i].x); | |
| var him = (points[i].x - points[i - 1].x); | |
| var ai = points[i].x - points[i - 1].x; | |
| var bi = 2*(hi + him); | |
| c[i - 1] = (hi / (bi - ai*c[i - 2])); | |
| d[i - 1] = (6*(((points[i + 1].y - points[i].y) / (hi)) | |
| - ((points[i].y - points[i - 1].y) / (him))) - ai*d[i - 2]) / (bi - ai*c[i - 2]); | |
| } | |
| results[0] = 0; | |
| results[points.length - 1] = 0; | |
| results[points.length - 2] = d[points.length - 3] || 0; | |
| for(var i = points.length - 3; i > 0; --i) { | |
| //console.log(i); | |
| results[i] = d[i-1] - c[i-1]*(results[i + 1]); | |
| } | |
| return results; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment