|
4109 | 4109 | function identity() { |
4110 | 4110 | return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; |
4111 | 4111 | } |
4112 | | - function pLength(point) { |
4113 | | - return Math.sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]); |
4114 | | - } |
4115 | 4112 | function normalize(point) { |
4116 | 4113 | const [x, y, z] = point; |
4117 | 4114 | const norm = Math.sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]); |
|
4232 | 4229 | const row0 = [matrix[0], matrix[1], matrix[2]]; |
4233 | 4230 | const row1 = [matrix[4], matrix[5], matrix[6]]; |
4234 | 4231 | const row2 = [matrix[8], matrix[9], matrix[10]]; |
| 4232 | + const cross = [ |
| 4233 | + row1[1] * row2[2] - row1[2] * row2[1], |
| 4234 | + row1[2] * row2[0] - row1[0] * row2[2], |
| 4235 | + row1[0] * row2[1] - row1[1] * row2[0], |
| 4236 | + ]; |
4235 | 4237 | // Compute scale |
4236 | | - const scaleX = pLength(row0); |
| 4238 | + const scaleX = Math.hypot(...row0); |
4237 | 4239 | const row0Norm = normalize(row0); |
4238 | 4240 | const skewXY = dot(row0Norm, row1); |
4239 | 4241 | const row1Proj = [ |
4240 | 4242 | row1[0] - skewXY * row0Norm[0], |
4241 | 4243 | row1[1] - skewXY * row0Norm[1], |
4242 | 4244 | row1[2] - skewXY * row0Norm[2] |
4243 | 4245 | ]; |
4244 | | - const scaleY = pLength(row1Proj); |
| 4246 | + const scaleY = Math.hypot(...row1Proj); |
4245 | 4247 | const row1Norm = normalize(row1Proj); |
4246 | 4248 | const skewXZ = dot(row0Norm, row2); |
4247 | 4249 | const skewYZ = dot(row1Norm, row2); |
|
4250 | 4252 | row2[1] - skewXZ * row0Norm[1] - skewYZ * row1Norm[1], |
4251 | 4253 | row2[2] - skewXZ * row0Norm[2] - skewYZ * row1Norm[2] |
4252 | 4254 | ]; |
4253 | | - const scaleZ = pLength(row2Proj); |
4254 | 4255 | const row2Norm = normalize(row2Proj); |
| 4256 | + const determinant = row0[0] * cross[0] + row0[1] * cross[1] + row0[2] * cross[2]; |
| 4257 | + const scaleZ = Math.hypot(...row2Proj) * (determinant < 0 ? -1 : 1); |
4255 | 4258 | // Build rotation matrix from orthonormalized vectors |
4256 | 4259 | const r00 = row0Norm[0], r01 = row1Norm[0], r02 = row2Norm[0]; |
4257 | 4260 | const r10 = row0Norm[1], r11 = row1Norm[1], r12 = row2Norm[1]; |
|
4288 | 4291 | qz = 0.25 * s; |
4289 | 4292 | } |
4290 | 4293 | [qx, qy, qz] = toZero([qx, qy, qz]); |
4291 | | - // const q = gcd(qx, gcd(qy, qz)); |
4292 | 4294 | let q = [Math.abs(qx), Math.abs(qy), Math.abs(qz)].reduce((acc, curr) => { |
4293 | 4295 | if (acc == 0 || (curr > 0 && curr < acc)) { |
4294 | 4296 | acc = curr; |
|
21354 | 21356 | scales.delete('x'); |
21355 | 21357 | } |
21356 | 21358 | if (scales.size == 1) { |
21357 | | - let prefix = scales.has('x') ? '' : scales.has('y') ? 'Y' : 'Z'; |
| 21359 | + let prefix = scales.has('x') ? 'X' : scales.has('y') ? 'Y' : 'Z'; |
21358 | 21360 | result.push({ |
21359 | 21361 | typ: exports.EnumToken.FunctionTokenType, |
21360 | 21362 | val: 'scale' + prefix, |
@@ -21419,6 +21421,109 @@ |
21419 | 21421 | } |
21420 | 21422 | return true; |
21421 | 21423 | } |
| 21424 | + function minifyTransformFunctions(transform) { |
| 21425 | + const name = transform.val.toLowerCase(); |
| 21426 | + if ('skewx' == name) { |
| 21427 | + transform.val = 'skew'; |
| 21428 | + return transform; |
| 21429 | + } |
| 21430 | + if (!['translate', 'translate3d', 'scale', 'scale3d'].includes(name)) { |
| 21431 | + return transform; |
| 21432 | + } |
| 21433 | + const values = []; |
| 21434 | + for (const token of transform.chi) { |
| 21435 | + if (token.typ == exports.EnumToken.CommentTokenType || token.typ == exports.EnumToken.WhitespaceTokenType || token.typ == exports.EnumToken.CommaTokenType) { |
| 21436 | + continue; |
| 21437 | + } |
| 21438 | + if (![exports.EnumToken.NumberTokenType, exports.EnumToken.LengthTokenType, exports.EnumToken.AngleTokenType, exports.EnumToken.PercentageTokenType].includes(token.typ)) { |
| 21439 | + return transform; |
| 21440 | + } |
| 21441 | + if (token.typ == exports.EnumToken.PercentageTokenType && typeof token.val == 'number' && name.startsWith('scale')) { |
| 21442 | + Object.assign(token, { typ: exports.EnumToken.NumberTokenType, val: token.val / 100 }); |
| 21443 | + } |
| 21444 | + values.push(token); |
| 21445 | + } |
| 21446 | + if ((name == 'translate' || name == 'scale') && values.length > 2) { |
| 21447 | + return transform; |
| 21448 | + } |
| 21449 | + const ignoredValue = name.startsWith('scale') ? 1 : 0; |
| 21450 | + const t = new Set(['x', 'y', 'z']); |
| 21451 | + let i = 3; |
| 21452 | + while (i--) { |
| 21453 | + if (values.length <= i || values[i].val == ignoredValue) { |
| 21454 | + t.delete(i == 0 ? 'x' : i == 1 ? 'y' : 'z'); |
| 21455 | + } |
| 21456 | + } |
| 21457 | + if (name == 'translate3d' || name == 'translate') { |
| 21458 | + if (t.size == 0) { |
| 21459 | + return { |
| 21460 | + typ: exports.EnumToken.FunctionTokenType, |
| 21461 | + val: 'translate', |
| 21462 | + chi: [ |
| 21463 | + { typ: exports.EnumToken.NumberTokenType, val: 0 } |
| 21464 | + ] |
| 21465 | + }; |
| 21466 | + } |
| 21467 | + if (t.size == 1) { |
| 21468 | + return { |
| 21469 | + typ: exports.EnumToken.FunctionTokenType, |
| 21470 | + val: 'translate' + (t.has('x') ? '' : t.has('y') ? 'Y' : 'Z'), |
| 21471 | + chi: [ |
| 21472 | + values[t.has('x') ? 0 : t.has('y') ? 1 : 2] |
| 21473 | + ] |
| 21474 | + }; |
| 21475 | + } |
| 21476 | + if (t.size == 2) { |
| 21477 | + if (t.has('z')) { |
| 21478 | + return transform; |
| 21479 | + } |
| 21480 | + return { |
| 21481 | + typ: exports.EnumToken.FunctionTokenType, |
| 21482 | + val: 'translate', |
| 21483 | + chi: [ |
| 21484 | + values[0], |
| 21485 | + { typ: exports.EnumToken.CommaTokenType }, |
| 21486 | + values[1] |
| 21487 | + ] |
| 21488 | + }; |
| 21489 | + } |
| 21490 | + } |
| 21491 | + if (name == 'scale3d' || name == 'scale') { |
| 21492 | + if (t.size == 0) { |
| 21493 | + return { |
| 21494 | + typ: exports.EnumToken.FunctionTokenType, |
| 21495 | + val: 'scale', |
| 21496 | + chi: [ |
| 21497 | + { typ: exports.EnumToken.NumberTokenType, val: 1 } |
| 21498 | + ] |
| 21499 | + }; |
| 21500 | + } |
| 21501 | + if (t.size == 1) { |
| 21502 | + return { |
| 21503 | + typ: exports.EnumToken.FunctionTokenType, |
| 21504 | + val: 'scale' + (t.has('x') ? 'X' : t.has('y') ? 'Y' : 'Z'), |
| 21505 | + chi: [ |
| 21506 | + values[t.has('x') ? 0 : t.has('y') ? 1 : 2] |
| 21507 | + ] |
| 21508 | + }; |
| 21509 | + } |
| 21510 | + if (t.size == 2) { |
| 21511 | + if (t.has('z')) { |
| 21512 | + return transform; |
| 21513 | + } |
| 21514 | + return { |
| 21515 | + typ: exports.EnumToken.FunctionTokenType, |
| 21516 | + val: 'scale', |
| 21517 | + chi: [ |
| 21518 | + values[0], |
| 21519 | + { typ: exports.EnumToken.CommaTokenType }, |
| 21520 | + values[1] |
| 21521 | + ] |
| 21522 | + }; |
| 21523 | + } |
| 21524 | + } |
| 21525 | + return transform; |
| 21526 | + } |
21422 | 21527 |
|
21423 | 21528 | function skewX(x, from) { |
21424 | 21529 | const matrix = identity(); |
|
21474 | 21579 | }); |
21475 | 21580 | } |
21476 | 21581 | } |
21477 | | - // console.error({matrix}); |
21478 | | - // matrix = toZero(matrix) as Matrix; |
21479 | 21582 | return { |
21480 | 21583 | matrix: serialize(toZero(matrix)), |
21481 | 21584 | cumulative, |
|
21499 | 21602 | { |
21500 | 21603 | values.length = 0; |
21501 | 21604 | const children = stripCommaToken(transformList[i].chi.slice()); |
21502 | | - const valCount = transformList[i].val == 'translate3d' || transformList[i].val == 'translate' ? 3 : 1; |
| 21605 | + const valCount = transformList[i].val == 'translate3d' ? 3 : transformList[i].val == 'translate' ? 2 : 1; |
21503 | 21606 | for (let j = 0; j < children.length; j++) { |
21504 | 21607 | if (children[j].typ == exports.EnumToken.WhitespaceTokenType) { |
21505 | 21608 | continue; |
|
21586 | 21689 | const children = stripCommaToken(transformList[i].chi.slice()); |
21587 | 21690 | for (let k = 0; k < children.length; k++) { |
21588 | 21691 | child = children[k]; |
21589 | | - if (child.typ != exports.EnumToken.NumberTokenType) { |
| 21692 | + if (child.typ != exports.EnumToken.NumberTokenType && child.typ != exports.EnumToken.PercentageTokenType) { |
21590 | 21693 | return null; |
21591 | 21694 | } |
21592 | 21695 | values.push(getNumber(child)); |
@@ -21767,28 +21870,21 @@ |
21767 | 21870 | if (node.typ != exports.EnumToken.DeclarationNodeType || !node.nam.match(/^(-[a-z]+-)?transform$/)) { |
21768 | 21871 | continue; |
21769 | 21872 | } |
21770 | | - const children = node.val.reduce((acc, curr) => { |
21771 | | - if (curr.typ == exports.EnumToken.FunctionTokenType && 'skew' == curr.val.toLowerCase()) { |
21772 | | - if (curr.chi.length == 3) { |
21773 | | - if (curr.chi[2].val == 0) { |
21774 | | - curr.chi.length = 1; |
21775 | | - curr.val = 'skew'; |
21776 | | - } |
21777 | | - else if (curr.chi[0].val == 0) { |
21778 | | - curr.chi = [curr.chi[2]]; |
21779 | | - curr.val = 'skewY'; |
21780 | | - } |
21781 | | - } |
21782 | | - } |
21783 | | - acc.push(curr); |
21784 | | - return acc; |
21785 | | - }, []); |
| 21873 | + const children = []; |
| 21874 | + for (const child of node.val) { |
| 21875 | + children.push(child.typ == exports.EnumToken.FunctionTokenType ? minifyTransformFunctions(child) : child); |
| 21876 | + } |
21786 | 21877 | consumeWhitespace(children); |
21787 | | - let { matrix, cumulative, minified } = compute(children) ?? {}; |
| 21878 | + let { matrix, cumulative, minified } = compute(children) ?? { |
| 21879 | + matrix: null, |
| 21880 | + cumulative: null, |
| 21881 | + minified: null |
| 21882 | + }; |
21788 | 21883 | if (matrix == null || cumulative == null || minified == null) { |
| 21884 | + node.val = children; |
21789 | 21885 | continue; |
21790 | 21886 | } |
21791 | | - let r = [filterValues(node.val.slice())]; |
| 21887 | + let r = [filterValues(children)]; |
21792 | 21888 | if (eqMatrix(matrix, cumulative)) { |
21793 | 21889 | r.push(cumulative); |
21794 | 21890 | } |
|
0 commit comments