From 4a2cea1c3ce34a304977eb1ea34aafdbf745aec7 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 18 Feb 2018 15:56:27 +0100 Subject: [PATCH] Limit sin and cosin very small floats on 90/270 degrees (#4734) * so far ok * fix transformations decimal * remove some changes * less changes * test passing * less calculation * added shortcut * modified tests --- src/filters/hue_rotation.class.js | 2 +- src/mixins/object_geometry.mixin.js | 100 ++++++++++------- src/mixins/object_interactivity.mixin.js | 4 +- src/mixins/object_origin.mixin.js | 4 +- src/parser.js | 2 +- src/shapes/circle.class.js | 8 +- src/util/arc.js | 12 +- src/util/misc.js | 50 ++++++++- test/unit/object_geometry.js | 135 +++++++++++++++++++++-- test/unit/parser.js | 2 +- test/unit/path.js | 4 +- test/unit/util.js | 10 +- 12 files changed, 260 insertions(+), 73 deletions(-) diff --git a/src/filters/hue_rotation.class.js b/src/filters/hue_rotation.class.js index a00a5a1fdc4..01053be5c33 100644 --- a/src/filters/hue_rotation.class.js +++ b/src/filters/hue_rotation.class.js @@ -45,7 +45,7 @@ mainParameter: 'rotation', calculateMatrix: function() { - var rad = this.rotation * Math.PI, cos = Math.cos(rad), sin = Math.sin(rad), + var rad = this.rotation * Math.PI, cos = fabric.util.cos(rad), sin = fabric.util.sin(rad), aThird = 1 / 3, aThirdSqtSin = Math.sqrt(aThird) * sin, OneMinusCos = 1 - cos; this.matrix = [ 1, 0, 0, 0, 0, diff --git a/src/mixins/object_geometry.mixin.js b/src/mixins/object_geometry.mixin.js index bb9b9d7814f..8f30f7089f0 100644 --- a/src/mixins/object_geometry.mixin.js +++ b/src/mixins/object_geometry.mixin.js @@ -10,7 +10,8 @@ } var degreesToRadians = fabric.util.degreesToRadians, - multiplyMatrices = fabric.util.multiplyTransformMatrices; + multiplyMatrices = fabric.util.multiplyTransformMatrices, + transformPoint = fabric.util.transformPoint; fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { @@ -355,45 +356,55 @@ * @chainable */ calcCoords: function(absolute) { - var theta = degreesToRadians(this.angle), + var rotateMatrix = this._calcRotateMatrix(), + translateMatrix = this._calcTranslateMatrix(), + startMatrix = multiplyMatrices(translateMatrix, rotateMatrix), vpt = this.getViewportTransform(), - dim = absolute ? this._getTransformedDimensions() : this._calculateCurrentDimensions(), - currentWidth = dim.x, currentHeight = dim.y, - sinTh = theta ? Math.sin(theta) : 0, - cosTh = theta ? Math.cos(theta) : 1, - _angle = currentWidth > 0 ? Math.atan(currentHeight / currentWidth) : 0, - _hypotenuse = (currentWidth / Math.cos(_angle)) / 2, - offsetX = Math.cos(_angle + theta) * _hypotenuse, - offsetY = Math.sin(_angle + theta) * _hypotenuse, - center = this.getCenterPoint(), - // offset added for rotate and scale actions - coords = absolute ? center : fabric.util.transformPoint(center, vpt), - tl = new fabric.Point(coords.x - offsetX, coords.y - offsetY), - tr = new fabric.Point(tl.x + (currentWidth * cosTh), tl.y + (currentWidth * sinTh)), - bl = new fabric.Point(tl.x - (currentHeight * sinTh), tl.y + (currentHeight * cosTh)), - br = new fabric.Point(coords.x + offsetX, coords.y + offsetY); + finalMatrix = absolute ? startMatrix : multiplyMatrices(vpt, startMatrix), + dim = this._getTransformedDimensions(), + w = dim.x / 2, h = dim.y / 2, + tl = transformPoint({ x: -w, y: -h }, finalMatrix), + tr = transformPoint({ x: w, y: -h }, finalMatrix), + bl = transformPoint({ x: -w, y: h }, finalMatrix), + br = transformPoint({ x: w, y: h }, finalMatrix); if (!absolute) { + var padding = this.padding, angle = degreesToRadians(this.angle), + cos = fabric.util.cos(angle), sin = fabric.util.sin(angle), + cosP = cos * padding, sinP = sin * padding, cosPSinP = cosP + sinP, + cosPMinusSinP = cosP - sinP; + if (padding) { + tl.x -= cosPMinusSinP; + tl.y -= cosPSinP; + tr.x += cosPSinP; + tr.y -= cosPMinusSinP; + bl.x -= cosPSinP; + bl.y += cosPMinusSinP; + br.x += cosPMinusSinP; + br.y += cosPSinP; + } var ml = new fabric.Point((tl.x + bl.x) / 2, (tl.y + bl.y) / 2), mt = new fabric.Point((tr.x + tl.x) / 2, (tr.y + tl.y) / 2), mr = new fabric.Point((br.x + tr.x) / 2, (br.y + tr.y) / 2), mb = new fabric.Point((br.x + bl.x) / 2, (br.y + bl.y) / 2), - mtr = new fabric.Point(mt.x + sinTh * this.rotatingPointOffset, mt.y - cosTh * this.rotatingPointOffset); + mtr = new fabric.Point(mt.x + sin * this.rotatingPointOffset, mt.y - cos * this.rotatingPointOffset); } - // debugging - - /* setTimeout(function() { - canvas.contextTop.fillStyle = 'green'; - canvas.contextTop.fillRect(mb.x, mb.y, 3, 3); - canvas.contextTop.fillRect(bl.x, bl.y, 3, 3); - canvas.contextTop.fillRect(br.x, br.y, 3, 3); - canvas.contextTop.fillRect(tl.x, tl.y, 3, 3); - canvas.contextTop.fillRect(tr.x, tr.y, 3, 3); - canvas.contextTop.fillRect(ml.x, ml.y, 3, 3); - canvas.contextTop.fillRect(mr.x, mr.y, 3, 3); - canvas.contextTop.fillRect(mt.x, mt.y, 3, 3); - canvas.contextTop.fillRect(mtr.x, mtr.y, 3, 3); - }, 50); */ + // if (!absolute) { + // var canvas = this.canvas; + // setTimeout(function() { + // canvas.contextTop.clearRect(0, 0, 700, 700); + // canvas.contextTop.fillStyle = 'green'; + // canvas.contextTop.fillRect(mb.x, mb.y, 3, 3); + // canvas.contextTop.fillRect(bl.x, bl.y, 3, 3); + // canvas.contextTop.fillRect(br.x, br.y, 3, 3); + // canvas.contextTop.fillRect(tl.x, tl.y, 3, 3); + // canvas.contextTop.fillRect(tr.x, tr.y, 3, 3); + // canvas.contextTop.fillRect(ml.x, ml.y, 3, 3); + // canvas.contextTop.fillRect(mr.x, mr.y, 3, 3); + // canvas.contextTop.fillRect(mt.x, mt.y, 3, 3); + // canvas.contextTop.fillRect(mtr.x, mtr.y, 3, 3); + // }, 50); + // } var coords = { // corners @@ -437,16 +448,21 @@ */ _calcRotateMatrix: function() { if (this.angle) { - var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta); - // trying to keep rounding error small, ugly but it works. - if (cos === 6.123233995736766e-17 || cos === -1.8369701987210297e-16) { - cos = 0; - } + var theta = degreesToRadians(this.angle), cos = fabric.util.cos(theta), sin = fabric.util.sin(theta); return [cos, sin, -sin, cos, 0, 0]; } return fabric.iMatrix.concat(); }, + /** + * calculate the translation matrix for an object transform + * @return {Array} rotation matrix for the object + */ + _calcTranslateMatrix: function() { + var center = this.getCenterPoint(); + return [1, 0, 0, 1, center.x, center.y]; + }, + transformMatrixKey: function(skipGroup) { var sep = '_', prefix = ''; if (!skipGroup && this.group) { @@ -485,8 +501,7 @@ if (cache.key === key) { return cache.value; } - var center = this.getCenterPoint(), - matrix = [1, 0, 0, 1, center.x, center.y], + var matrix = this._calcTranslateMatrix(), rotateMatrix, dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true); if (this.angle) { @@ -542,8 +557,11 @@ if (typeof skewY === 'undefined') { skewY = this.skewY; } - var dimensions = this._getNonTransformedDimensions(), - dimX = dimensions.x / 2, dimY = dimensions.y / 2, + var dimensions = this._getNonTransformedDimensions(); + if (skewX === 0 && skewY === 0) { + return { x: dimensions.x * this.scaleX, y: dimensions.y * this.scaleY }; + } + var dimX = dimensions.x / 2, dimY = dimensions.y / 2, points = [ { x: -dimX, diff --git a/src/mixins/object_interactivity.mixin.js b/src/mixins/object_interactivity.mixin.js index 516c132c9e4..e1229d49349 100644 --- a/src/mixins/object_interactivity.mixin.js +++ b/src/mixins/object_interactivity.mixin.js @@ -79,8 +79,8 @@ /* Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2, */ /* 0.707106 stands for sqrt(2)/2 */ cornerHypotenuse = this.cornerSize * 0.707106, - cosHalfOffset = cornerHypotenuse * Math.cos(newTheta), - sinHalfOffset = cornerHypotenuse * Math.sin(newTheta), + cosHalfOffset = cornerHypotenuse * fabric.util.cos(newTheta), + sinHalfOffset = cornerHypotenuse * fabric.util.sin(newTheta), x, y; for (var point in coords) { diff --git a/src/mixins/object_origin.mixin.js b/src/mixins/object_origin.mixin.js index 71a7b78b93e..9f0bce39991 100644 --- a/src/mixins/object_origin.mixin.js +++ b/src/mixins/object_origin.mixin.js @@ -182,8 +182,8 @@ adjustPosition: function(to) { var angle = degreesToRadians(this.angle), hypotFull = this.getScaledWidth(), - xFull = Math.cos(angle) * hypotFull, - yFull = Math.sin(angle) * hypotFull, + xFull = fabric.util.cos(angle) * hypotFull, + yFull = fabric.util.sin(angle) * hypotFull, offsetFrom, offsetTo; //TODO: this function does not consider mixed situation like top, center. diff --git a/src/parser.js b/src/parser.js index 168debb266b..84880c11d95 100644 --- a/src/parser.js +++ b/src/parser.js @@ -186,7 +186,7 @@ */ fabric.parseTransformAttribute = (function() { function rotateMatrix(matrix, args) { - var cos = Math.cos(args[0]), sin = Math.sin(args[0]), + var cos = fabric.util.cos(args[0]), sin = fabric.util.sin(args[0]), x = 0, y = 0; if (args.length === 3) { x = args[1]; diff --git a/src/shapes/circle.class.js b/src/shapes/circle.class.js index 64515b5a044..5497e5dae88 100644 --- a/src/shapes/circle.class.js +++ b/src/shapes/circle.class.js @@ -96,10 +96,10 @@ ); } else { - var startX = Math.cos(this.startAngle) * this.radius, - startY = Math.sin(this.startAngle) * this.radius, - endX = Math.cos(this.endAngle) * this.radius, - endY = Math.sin(this.endAngle) * this.radius, + var startX = fabric.util.cos(this.startAngle) * this.radius, + startY = fabric.util.sin(this.startAngle) * this.radius, + endX = fabric.util.cos(this.endAngle) * this.radius, + endY = fabric.util.sin(this.endAngle) * this.radius, largeFlag = angle > pi ? '1' : '0'; markup.push( diff --git a/src/util/arc.js b/src/util/arc.js index ee56dec6db7..c4b81d24015 100644 --- a/src/util/arc.js +++ b/src/util/arc.js @@ -16,8 +16,8 @@ } var PI = Math.PI, th = rotateX * PI / 180, - sinTh = Math.sin(th), - cosTh = Math.cos(th), + sinTh = fabric.util.sin(th), + cosTh = fabric.util.cos(th), fromX = 0, fromY = 0; rx = Math.abs(rx); @@ -76,10 +76,10 @@ return segmentToBezierCache[argsString2]; } - var costh2 = Math.cos(th2), - sinth2 = Math.sin(th2), - costh3 = Math.cos(th3), - sinth3 = Math.sin(th3), + var costh2 = fabric.util.cos(th2), + sinth2 = fabric.util.sin(th2), + costh3 = fabric.util.cos(th3), + sinth3 = fabric.util.sin(th3), toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1, toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1, cp1X = fromX + mT * ( -cosTh * rx * sinth2 - sinTh * ry * costh2), diff --git a/src/util/misc.js b/src/util/misc.js index 6731e38bb2d..410aab8960a 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -4,13 +4,57 @@ atan2 = Math.atan2, pow = Math.pow, abs = Math.abs, - PiBy180 = Math.PI / 180; + PiBy180 = Math.PI / 180, + PiBy2 = Math.PI / 2; /** * @namespace fabric.util */ fabric.util = { + /** + * Calculate the cos of an angle, avoiding returning floats for known results + * @static + * @memberOf fabric.util + * @param {Number} angle the angle in radians or in degree + * @return {Number} + */ + cos: function(angle) { + if (angle === 0) { return 1; } + if (angle < 0) { + // cos(a) = cos(-a) + angle = -angle; + } + var angleSlice = angle / PiBy2; + switch (angleSlice) { + case 1: case 3: return 0; + case 2: return -1; + } + return Math.cos(angle); + }, + + /** + * Calculate the sin of an angle, avoiding returning floats for known results + * @static + * @memberOf fabric.util + * @param {Number} angle the angle in radians or in degree + * @return {Number} + */ + sin: function(angle) { + if (angle === 0) { return 0; } + var angleSlice = angle / PiBy2, sign = 1; + if (angle < 0) { + // sin(-a) = -sin(a) + sign = -1; + } + switch (angleSlice) { + case 1: return sign; + case 2: return 0; + case 3: return -sign; + } + return Math.sin(angle); + }, + /** * Removes value from an array. * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf` @@ -86,8 +130,8 @@ * @return {Object} The new rotated point */ rotateVector: function(vector, radians) { - var sin = Math.sin(radians), - cos = Math.cos(radians), + var sin = fabric.util.sin(radians), + cos = fabric.util.cos(radians), rx = vector.x * cos - vector.y * sin, ry = vector.x * sin + vector.y * cos; return { diff --git a/test/unit/object_geometry.js b/test/unit/object_geometry.js index 70efc2438d5..21ea2ba0de6 100644 --- a/test/unit/object_geometry.js +++ b/test/unit/object_geometry.js @@ -672,13 +672,132 @@ assert.deepEqual(coords[3], new fabric.Point(40, 47), 'return bottom left corner cached oCoords'); }); - // QUnit.test('getCoords return coordinate of object', function(assert) { - // var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40 }); - // var coords = cObj.getCoords(); - // assert.equal(coords[0], { x: 40, y: 30 }, 'return top left corner'); - // assert.equal(coords[1], { x: 1, y: 1 }, 'return top right corner'); - // assert.equal(coords[2], { x: 1, y: 1 }, 'return bottom right corner'); - // assert.equal(coords[3], { x: 1, y: 1 }, 'return bottom left corner'); - // }); + QUnit.test('getCoords absolute with angle', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, angle: 20 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(true); + assert.deepEqual(coords[0].x, 40, 'return top left absolute with angle X'); + assert.deepEqual(coords[1].x, 51.2763114494309, 'return top right absolute with angle X'); + assert.deepEqual(coords[2].x, 45.46196901289453, 'return bottom right absolute with angle X'); + assert.deepEqual(coords[3].x, 34.18565756346363, 'return bottom left absolute with angle X'); + assert.deepEqual(coords[0].y, 30, 'return top left absolute with angle Y'); + assert.deepEqual(coords[1].y, 34.104241719908025, 'return top right absolute with angle Y'); + assert.deepEqual(coords[2].y, 50.079016273268465, 'return bottom right absolute with angle Y'); + assert.deepEqual(coords[3].y, 45.97477455336044, 'return bottom left absolute with angle Y'); + }); + + QUnit.test('getCoords with angle', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, angle: 20 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(); + assert.deepEqual(coords[0].x, 115, 'return top left with angle X'); + assert.deepEqual(coords[1].x, 137.55262289886178, 'return top right with angle X'); + assert.deepEqual(coords[2].x, 125.92393802578906, 'return bottom right with angle X'); + assert.deepEqual(coords[3].x, 103.37131512692726, 'return bottom left with angle X'); + assert.deepEqual(coords[0].y, 85, 'return top left with angle Y'); + assert.deepEqual(coords[1].y, 93.20848343981605, 'return top right with angle Y'); + assert.deepEqual(coords[2].y, 125.15803254653693, 'return bottom right with angle Y'); + assert.deepEqual(coords[3].y, 116.94954910672088, 'return bottom left with angle Y'); + }); + + QUnit.test('getCoords absolute with skewX', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, skewX: 45 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(true); + assert.deepEqual(coords[0].x, 40, 'return top left absolute with skewX X'); + assert.deepEqual(coords[1].x, 69, 'return top right absolute with skewX X'); + assert.deepEqual(coords[2].x, 69, 'return bottom absolute right with skewX X'); + assert.deepEqual(coords[3].x, 40, 'return bottom absolute left with skewX X'); + assert.deepEqual(coords[0].y, 30, 'return top left absolute with skewX Y'); + assert.deepEqual(coords[1].y, 30, 'return top right absolute with skewX Y'); + assert.deepEqual(coords[2].y, 47, 'return bottom absolute right with skewX Y'); + assert.deepEqual(coords[3].y, 47, 'return bottom absolute left with skewX Y'); + }); + + QUnit.test('getCoords with skewX', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, skewX: 45 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(); + assert.deepEqual(coords[0].x, 115, 'return top left with skewX X'); + assert.deepEqual(coords[1].x, 173, 'return top right with skewX X'); + assert.deepEqual(coords[2].x, 173, 'return bottom right with skewX X'); + assert.deepEqual(coords[3].x, 115, 'return bottom left with skewX X'); + assert.deepEqual(coords[0].y, 85, 'return top left with skewX Y'); + assert.deepEqual(coords[1].y, 85, 'return top right with skewX Y'); + assert.deepEqual(coords[2].y, 119, 'return bottom right with skewX Y'); + assert.deepEqual(coords[3].y, 119, 'return bottom left with skewX Y'); + }); + + QUnit.test('getCoords absolute with skewY', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, skewY: 45 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(true); + assert.deepEqual(coords[0].x, 40, 'return top left absolute with skewY X'); + assert.deepEqual(coords[1].x, 52, 'return top right absolute with skewY X'); + assert.deepEqual(coords[2].x, 52, 'return bottom absolute right with skewY X'); + assert.deepEqual(coords[3].x, 40, 'return bottom absolute left with skewY X'); + assert.deepEqual(coords[0].y, 30, 'return top left absolute with skewY Y'); + assert.deepEqual(coords[1].y, 30, 'return top right absolute with skewY Y'); + assert.deepEqual(coords[2].y, 59, 'return bottom absolute right with skewY Y'); + assert.deepEqual(coords[3].y, 59, 'return bottom absolute left with skewY Y'); + }); + + QUnit.test('getCoords with skewY', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, skewY: 45 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(); + assert.deepEqual(coords[0].x, 115, 'return top left with skewY X'); + assert.deepEqual(coords[1].x, 139, 'return top right with skewY X'); + assert.deepEqual(coords[2].x, 139, 'return bottom right with skewY X'); + assert.deepEqual(coords[3].x, 115, 'return bottom left with skewY X'); + assert.deepEqual(coords[0].y, 85, 'return top left with skewY Y'); + assert.deepEqual(coords[1].y, 85, 'return top right with skewY Y'); + assert.deepEqual(coords[2].y, 143, 'return bottom right with skewY Y'); + assert.deepEqual(coords[3].y, 143, 'return bottom left with skewY Y'); + }); + + QUnit.test('getCoords absolute with skewY skewX angle', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, skewY: 45, skewX: 30, angle: 90 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(true); + assert.deepEqual(coords[0].x, 40, 'return top left absolute with skewY skewX angle X'); + assert.deepEqual(coords[1].x, 40, 'return top right absolute with skewY skewX angle X'); + assert.deepEqual(coords[2].x, 11, 'return bottom absolute right with skewY skewX angle X'); + assert.deepEqual(coords[3].x, 11, 'return bottom absolute left with skewY skewX angle X'); + assert.deepEqual(coords[0].y, 30, 'return top left absolute with skewY skewX angle Y'); + assert.deepEqual(coords[1].y, 58.74315780649914, 'return top right absolute with skewY skewX angle Y'); + assert.deepEqual(coords[2].y, 58.74315780649914, 'return bottom absolute right with skewY skewX angle Y'); + assert.deepEqual(coords[3].y, 30, 'return bottom absolute left with skewY skewX angle Y'); + }); + + QUnit.test('getCoords with skewY skewX angle', function(assert) { + var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 2, top: 30, left: 40, skewY: 45, skewX: 30, angle: 90 }); + cObj.canvas = { + viewportTransform: [2, 0, 0, 2, 35, 25] + }; + var coords = cObj.getCoords(); + assert.deepEqual(coords[0].x, 115, 'return top left with skewY skewX angle X'); + assert.deepEqual(coords[1].x, 115, 'return top right with skewY skewX angle X'); + assert.deepEqual(coords[2].x, 57, 'return bottom right with skewY skewX angle X'); + assert.deepEqual(coords[3].x, 57, 'return bottom left with skewY skewX angle X'); + assert.deepEqual(coords[0].y, 85, 'return top left with skewY skewX angle Y'); + assert.deepEqual(coords[1].y, 142.48631561299828, 'return top right with skewY skewX angle Y'); + assert.deepEqual(coords[2].y, 142.48631561299828, 'return bottom right with skewY skewX angle Y'); + assert.deepEqual(coords[3].y, 85, 'return bottom left with skewY skewX angle Y'); + }); })(); diff --git a/test/unit/parser.js b/test/unit/parser.js index 0b0df00a5f6..4b8cc705701 100644 --- a/test/unit/parser.js +++ b/test/unit/parser.js @@ -286,7 +286,7 @@ var ANGLE = ANGLE_DEG * Math.PI / 180; element.setAttribute('transform', 'rotate(' + ANGLE_DEG + ')'); parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform')); - assert.deepEqual(parsedValue, [Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0]); + assert.deepEqual(parsedValue, [fabric.util.cos(ANGLE), fabric.util.sin(ANGLE), -fabric.util.sin(ANGLE), fabric.util.cos(ANGLE), 0, 0]); element.setAttribute('transform', 'scale(3.5)'); parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform')); diff --git a/test/unit/path.js b/test/unit/path.js index 3e6728190d9..f574d3cd200 100644 --- a/test/unit/path.js +++ b/test/unit/path.js @@ -221,14 +221,12 @@ })); var ANGLE_DEG = 90; - var ANGLE = ANGLE_DEG * Math.PI / 180; - elPath.setAttribute('transform', 'rotate(' + ANGLE_DEG + ')'); fabric.Path.fromElement(elPath, function(path) { assert.deepEqual( path.get('transformMatrix'), - [Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0] + [0, 1, -1, 0, 0, 0] ); done(); }); diff --git a/test/unit/util.js b/test/unit/util.js index f24b41fce1b..75dce48a21a 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -910,7 +910,7 @@ { x: 0, y: -8.318331151877368 }, { x: 133.33333333333331, y: 19.99999999999999 }, { x: 100.00000000000003, y: 19.99999999999999 }, - { x: 147.19721858646224, y: 100 } + { x: 147.19721858646224, y: 100 }, ]; assert.deepEqual(bounds, expectedBounds, 'bounds are as expected'); }); @@ -951,4 +951,12 @@ var val = fabric.util.capValue(3, 80, 70); assert.equal(val, 70, 'max cap'); }); + + QUnit.test('fabric.util.cos', function(assert) { + assert.ok(typeof fabric.util.cos === 'function'); + assert.equal(fabric.util.cos(0), 1, 'cos 0 correct'); + assert.equal(fabric.util.cos(Math.PI / 2), 0, 'cos 90 correct'); + assert.equal(fabric.util.cos(Math.PI), -1, 'cos 180 correct'); + assert.equal(fabric.util.cos(3 * Math.PI / 2), 0,' cos 270 correct'); + }); })();