diff --git a/docs/03-plugins/convert-path-data.mdx b/docs/03-plugins/convert-path-data.mdx index 04c303de5..66848688f 100644 --- a/docs/03-plugins/convert-path-data.mdx +++ b/docs/03-plugins/convert-path-data.mdx @@ -31,7 +31,7 @@ svgo: description: Number of decimal places to round to, using conventional rounding rules. default: 5 smartArcRounding: - description: Round the radius of circular arcs more when the effective change (measured with the sagitta) is under the error. + description: Round the radius of circular arcs when the effective change is under the error. The effective change is determined using the sagitta of the arc. default: true removeUseless: description: Remove redundant path commands that don't draw anything. diff --git a/plugins/convertPathData.js b/plugins/convertPathData.js index e70e6a31a..2a6c66507 100644 --- a/plugins/convertPathData.js +++ b/plugins/convertPathData.js @@ -407,8 +407,6 @@ function filters( var sdata = data, circle; - const sagitta = command === 'a' ? calculateSagitta(data) : undefined; - if (command === 's') { sdata = [0, 0].concat(data); @@ -645,16 +643,12 @@ function filters( // round arc radius more accurately // eg m 0 0 a 1234.567 1234.567 0 0 1 10 0 -> m 0 0 a 1235 1235 0 0 1 10 0 - if ( - params.smartArcRounding && - command === 'a' && - sagitta !== undefined && - precision - ) { + const sagitta = command === 'a' ? calculateSagitta(data) : undefined; + if (params.smartArcRounding && sagitta !== undefined && precision) { for (let precisionNew = precision; precisionNew >= 0; precisionNew--) { const radius = toFixed(data[0], precisionNew); const sagittaNew = /** @type {number} */ ( - calculateSagitta([radius, radius].concat(data.slice(2))) + calculateSagitta([radius, radius, ...data.slice(2)]) ); if (Math.abs(sagitta - sagittaNew) < error) { data[0] = radius; @@ -1100,15 +1094,16 @@ function isCurveStraightLine(data) { * Calculates the sagitta of an arc if possible. * * @type {(data: number[]) => number | undefined} + * @see https://wikipedia.org/wiki/Sagitta_(geometry)#Formulas */ function calculateSagitta(data) { - const rx = data[0], - ry = data[1], - distance = Math.sqrt(Math.pow(data[5], 2) + Math.pow(data[6], 2)); + if (data[3] === 1) return undefined; + + const [rx, ry] = data; if (Math.abs(rx - ry) > error) return undefined; - if (distance / 2 > rx) return undefined; - if (data[3] == 1) return undefined; - return rx - Math.sqrt(Math.pow(rx, 2) - 0.25 * Math.pow(distance, 2)); + const chord = Math.sqrt(data[5] ** 2 + data[6] ** 2); + if (chord > rx * 2) return undefined; + return rx - Math.sqrt(rx ** 2 - 0.25 * chord ** 2); } /** diff --git a/test/plugins/convertPathData.32.svg b/test/plugins/convertPathData.32.svg index 86d418491..97df96b12 100644 --- a/test/plugins/convertPathData.32.svg +++ b/test/plugins/convertPathData.32.svg @@ -2,12 +2,12 @@ Should convert arc to line === - - + + @@@ - - + + diff --git a/test/plugins/convertPathData.33.svg b/test/plugins/convertPathData.33.svg index 7ca75ecf9..b8125535b 100644 --- a/test/plugins/convertPathData.33.svg +++ b/test/plugins/convertPathData.33.svg @@ -2,12 +2,12 @@ Should round radius considering the sagitta === - - + + @@@ - - + +