From ac8edbaf4163fd7e0934b72175d60e71844d8cf9 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Fri, 27 Aug 2021 01:03:11 +0300 Subject: [PATCH] Fix applying transform to arc with zero radius Ref https://github.com/svg/svgo/issues/1500 --- plugins/_transforms.js | 52 +++++++++++++++-------------- test/plugins/convertPathData.26.svg | 13 ++++++++ 2 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 test/plugins/convertPathData.26.svg diff --git a/plugins/_transforms.js b/plugins/_transforms.js index dcd4db0f..159f1a3b 100644 --- a/plugins/_transforms.js +++ b/plugins/_transforms.js @@ -309,40 +309,42 @@ const transformToMatrix = (transform) => { exports.transformArc = (cursor, arc, transform) => { const x = arc[5] - cursor[0]; const y = arc[6] - cursor[1]; - var a = arc[0], - b = arc[1], - rot = (arc[2] * Math.PI) / 180, - cos = Math.cos(rot), - sin = Math.sin(rot), - h = + let a = arc[0]; + let b = arc[1]; + const rot = (arc[2] * Math.PI) / 180; + const cos = Math.cos(rot); + const sin = Math.sin(rot); + // skip if radius is 0 + if (a > 0 && b > 0) { + let h = Math.pow(x * cos + y * sin, 2) / (4 * a * a) + Math.pow(y * cos - x * sin, 2) / (4 * b * b); - if (h > 1) { - h = Math.sqrt(h); - a *= h; - b *= h; + if (h > 1) { + h = Math.sqrt(h); + a *= h; + b *= h; + } } - var ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0], - m = multiplyTransformMatrices(transform, ellipse), - // Decompose the new ellipse matrix - lastCol = m[2] * m[2] + m[3] * m[3], - squareSum = m[0] * m[0] + m[1] * m[1] + lastCol, - root = - Math.hypot(m[0] - m[3], m[1] + m[2]) * - Math.hypot(m[0] + m[3], m[1] - m[2]); + const ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0]; + const m = multiplyTransformMatrices(transform, ellipse); + // Decompose the new ellipse matrix + const lastCol = m[2] * m[2] + m[3] * m[3]; + const squareSum = m[0] * m[0] + m[1] * m[1] + lastCol; + const root = + Math.hypot(m[0] - m[3], m[1] + m[2]) * Math.hypot(m[0] + m[3], m[1] - m[2]); if (!root) { // circle arc[0] = arc[1] = Math.sqrt(squareSum / 2); arc[2] = 0; } else { - var majorAxisSqr = (squareSum + root) / 2, - minorAxisSqr = (squareSum - root) / 2, - major = Math.abs(majorAxisSqr - lastCol) > 1e-6, - sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol, - rowsSum = m[0] * m[2] + m[1] * m[3], - term1 = m[0] * sub + m[2] * rowsSum, - term2 = m[1] * sub + m[3] * rowsSum; + const majorAxisSqr = (squareSum + root) / 2; + const minorAxisSqr = (squareSum - root) / 2; + const major = Math.abs(majorAxisSqr - lastCol) > 1e-6; + const sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol; + const rowsSum = m[0] * m[2] + m[1] * m[3]; + const term1 = m[0] * sub + m[2] * rowsSum; + const term2 = m[1] * sub + m[3] * rowsSum; arc[0] = Math.sqrt(majorAxisSqr); arc[1] = Math.sqrt(minorAxisSqr); arc[2] = diff --git a/test/plugins/convertPathData.26.svg b/test/plugins/convertPathData.26.svg new file mode 100644 index 00000000..968bab1f --- /dev/null +++ b/test/plugins/convertPathData.26.svg @@ -0,0 +1,13 @@ +Applying transform to arc with zero radius should not produce NaNs + +=== + + + + + +@@@ + + + +