JS 线性变换和矩阵乘法失败

2024-03-17

我正在学习线性代数并尝试制作一个具有基本线性变换的小程序(旋转、缩放、平移).

这是完整的工作示例:

我编写了用于为每个变换生成每个矩阵的函数以及用于计算它们的函数(矩阵与点相乘, 矩阵相乘).

export const multiplyMatrixWithPoint = (matrix, point) => {
  return point.map((dimension, index) => {
    let result = 0;

    for (let i = 0; i < 4; i++) {
      const matrixIndex = index * 4 + i;
      result += dimension * matrix[matrixIndex];
    }

    return +result.toFixed(2);
  })
};

// Just creating 2D array to make it easy to calculate the matrix
export const matrixToPoints = matrix => {
  const result = [];

  for (let i = 0; i < 4; i++) {
    const onePoint = [];

    for (let j = 0; j < 4; j++) {
      onePoint.push(matrix[4 * i + j]);
    }
    
    result.push(onePoint);
  }

  return result;
};

// Just making 2D array to 1D
export const pointsToMatrix = points => points.reduce((acc, points) => [...acc, ...points], []);

// Transpose function to make the matrix multiplication correct
export const transposeCSSMatrixToTransform = matrix => matrix[0].map((column, index) => matrix.map(row => row[index]));

export const multiplyMatrices = (matrixA, matrixB) => {
  const separatePoints = transposeCSSMatrixToTransform(matrixToPoints(matrixB));

  return pointsToMatrix(transposeCSSMatrixToTransform(separatePoints.map(point => multiplyMatrixWithPoint(matrixA, point))));
};

export const rotationMatrixGenerator = (matrix, angle) => {
  const radians = degreeToRadian(angle);

  matrix[0] = Math.cos(radians);
  matrix[1] = -Math.sin(radians);
  matrix[4] = Math.sin(radians);
  matrix[5] = Math.cos(radians);

  return matrix; 
};

export const scaleMatrixGenerator = (matrix, { x, y }) => {
  matrix[0] = x;
  matrix[5] = y;

  return matrix;
};

export const translateMatrixGenerator = (matrix, { x, y }) => {
  matrix[12] = x;
  matrix[13] = y;

  return matrix;
};

为了展示我使用 CSS 的转换matrix3d

export const matrixToCSSMatrix = matrix => `matrix3d(${matrix.join(',')})`;

这是代码的执行部分

  ...
  const [matrix, setMatrix] = useState(DEFAULT_MATRIX);
  const [rotationAngle, setRotationAngle] = useState(0);
  const [scale, setScale] = useState(DEFAULT_XY);
  const [translate, setTranslate] = useState(DEFAULT_XY);

  const classes = useStyles();
  const { app } = classes;

  // ---------------------- Rotate --------------------- //
  const rotate = useCallback(e => {
    const { value: angle } = e.target;

    const rotationMatrix = rotationMatrixGenerator(matrix, +angle);
    const updatedMatrix = multiplyMatrices(matrix, rotationMatrix);

    setMatrix(updatedMatrix);
    setRotationAngle(angle);
  }, [matrix]);

  // ---------------------- Scale --------------------- //
  const changeScale = useCallback((e, dimension) => {
    const { value } = e.target;
    const updatedScale = {
      ...scale,
      [dimension]: +value
    };

    const scaleMatrix = scaleMatrixGenerator(matrix, updatedScale);
    const updatedMatrix = multiplyMatrices(matrix, scaleMatrix);

    setMatrix(scaleMatrix);
    setScale(updatedScale);
  }, [matrix, scale]);

  // ------------------ Translate --------------------- //
  const changeTranslation = useCallback((e, position) => {
    const { value } = e.target;
    const updatedTranslation = {
      ...translate,
      [position]: +value
    };

    const translateMatrix = translateMatrixGenerator(matrix, updatedTranslation);
    const updatedMatrix = multiplyMatrices(matrix, translateMatrix);

    setMatrix(translateMatrix);
    setTranslate(updatedTranslation);
  }, [matrix, translate]);
  ...

首先我认为这是因为我没有转置矩阵,我尝试转置它,它有一点帮助,但没有修复所有错误。另外,我尝试收集所有转换并立即应用它们,但这是一个非常糟糕的解决方案并且效果不佳。

我需要单独的旋转、缩放和过渡,但旋转和过渡效果不佳,因为它们使用相同的矩阵段。另外,我无法实现 Z 轴的正常旋转。


在这里,我计算 2D 平移、缩放和旋转的 3D 变换矩阵(4 x 4 矩阵)。我还在样式转换中通过显式串联或通过矩阵预乘来组合它们。

const resultEl = document.getElementById('result')
const angleEl = document.getElementById('angle')
const xEl = document.getElementById('x')
const yEl = document.getElementById('y')
const sxEl = document.getElementById('sx')
const syEl = document.getElementById('sy')
const premulEl = document.getElementById('premul')
/** Counter clock-wise rotation */
function getXRotation(angle){
  const c = Math.cos(angle)
  const s = Math.sin(angle)
  return [
  +c, -s,  0,  0,
  +s, +c,  0,  0,
   0,  0,  1,  0,
   0,  0,  0,  1];
}

function getTranslation(x, y){
return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 x, y, 0, 1]
}
function getScale(sx, sy){
return [
 sx, 0, 0, 0,
  0,sy, 0, 0,
  0, 0, 1, 0,
  0, 0, 0, 1]
}

function mat4mul(B, A){
  const C = [];
  for(let i = 0; i < 4; ++i){
    for(let j = 0; j < 4; ++j){
      let c = 0;
      for(let k = 0; k < 4; ++k){
        c += A[4*i+k] * B[4*k+j]
      }
      C.push(c);
    }
  }
  return C
}

const update = (e) => {
  const T1 = getTranslation(xEl.value, yEl.value)
  const T2 = getXRotation(angleEl.value * Math.PI / 180)
  const T3 = getScale(sxEl.value, syEl.value)
  let T = '';
  if(premul.checked){
    T = `matrix3d(${
      mat4mul(mat4mul(T1,T2),T3)
    })`
    resultEl.style.backgroundColor = 'yellow';
  }else{
    T = `
    matrix3d(${T1})
    matrix3d(${T2})
    matrix3d(${T3})
    `
    resultEl.style.backgroundColor = 'gray'
  }
  resultEl.style.transform = T;
}

angleEl.addEventListener('input', update)
xEl.addEventListener('input', update)
yEl.addEventListener('input', update)
sxEl.addEventListener('input', update)
syEl.addEventListener('input', update)
premulEl.addEventListener('input', update)
div#result {
 background-color: gray;
 border: 2px solid black;
 color: black;
 width: 3cm; 
 height: 2cm;
}
<label>Rotation angle <input type=range id=angle min=0 max=360 value=0>
</label><br>
<label>Translation X <input type=range id=x min=0 max=360 value=0></label><br>
<label>Translation Y <input type=range id=y min=0 max=360 value=0></label><br>
<label>Scale X <input type=range id=sx min=0.5 max=2 value=1 step=0.01></label><br>
<label>Scale Y <input type=range id=sy min=0.5 max=2 value=1 step=0.01></label><br>
<label><input type=checkbox id=premul> Multiply matrices

<br>
<br>
<br>
<br>
<div id=result>Result</div>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JS 线性变换和矩阵乘法失败 的相关文章

  • Chart.js 渲染垂直堆积条形图太慢

    我正在使用 Chart js API 渲染多个堆叠的垂直条形图 但性能很慢 我什至做了一些改变 这样所有的content对象已经由服务器而不是浏览器处理 但我意识到大部分时间来自最终函数new Chart overallStatsChart
  • 当 img.crossOrigin="Anonymous" 时,Chrome MJPEG CORS“响应无效”

    Image from origin http 192 168 1 67 5555 has been blocked from loading by Cross Origin Resource Sharing policy Invalid r
  • 在多个 angular.js 应用程序之间共享单个服务

    我正在构建一个电子商务网站 基于 shopify 并且使用多个小型 angularjs 应用程序来处理诸如快速购物车 愿望清单 过滤产品和其他一些较小项目之类的事情 我最初使用了一个大型应用程序 具有路由和所有内容 但当我没有完整的 RES
  • 检测 JavaScript 版本

    如何检测浏览器支持的 JavaScript 版本 如果有 我想检查 ECMAScript 3 ECMAScript 5 和 ECMAScript 6 注意 我想避免已弃用的language tag 这里有一个很好的参考给你 http www
  • React.js 和 Ajax 之间的区别

    当我在 google 上搜索 React js 时 我得到的是 React js 是一个用于创建用户界面的框架 如果网站的某个特定部分经常更新 则意味着我们可以使用 React 但我很困惑 Ajax 仅用于此目的 我们可以使用 Ajax 更
  • 在 angularJS 中覆盖模块值/常量的最佳方法

    我用 angularJS 编写了一个模块 封装了所有后端通信 为了获得更大的灵活性 我将 api 前缀作为模块上的常量值 可能是值 因为我没有在配置阶段使用它 所以像 angular module myapp data constant a
  • 内容丰富的 api markdown 转换为 HTML

    有没有什么简单的方法可以将 Markdown 文本从 Contentful api 转换为 html 代码以显示在 html 页面上 我尝试过使用 pagedown 和一些类似的技术 但似乎没有一个对我有用 我是 Contentful 的客
  • React:未捕获的引用错误:未定义需求

    我正在阅读 React 教程 http facebook github io react docs animation html http facebook github io react docs animation html 并且我无法
  • 如何为多个元素添加Class?

    我正在使用这段 javascript 向多个元素添加一个类 我试图引用多个 div 并向它们添加类 它只适用于第一个 JavaScript
  • 无法将中间件与 Firebase 和 NuxtJS 3 一起使用

    我正在尝试在示例项目中使用 Firebase 身份验证 身份验证按预期工作 但是一旦我想使用中间件来阻止用户访问管理页面或在已经登录的情况下访问登录页面 这是不可能的 我已经尝试了几个小时 但没有任何效果 这是我的package json
  • setTimeout() 的问题

    这是我的代码 我想要它做的是写 0 等待一秒 写 1 等待一秒 写 2 等待一秒 等等 而是写 5 5 5 5 5 for i 0 i lt 5 i setTimeout document write i 1000 http jsfiddl
  • Immutable.js 推入嵌套对象中的数组

    假设有一个对象 const object foo bar 1 2 3 我需要推动4 to object foo bar array 现在我正在这样做 const initialState Immutable fromJS object co
  • React Context - Context.Consumer 与 Class.contextType

    我正在学习新引入的 React Context API 但我注意到它在示例中的消耗存在一些不一致 有的还是用原来的上下文 消费者HOC 方法 而有些 包括 React 文档 使用静态类 contextType method 有什么区别以及为
  • 如何设置第三方 cookie

    我如何设置第三方 cookie 我有要求设置cookie 并且cookie将在访问的网站中启用 就像我在访问cde com或def com或ghi com时在abc com中设置cookie一样 所以设置的cookie将在所有网站上获取 我
  • Ajax调用完成后执行函数

    我是 Ajax 新手 我尝试在使用 for 循环时使用 Ajax Ajax 调用之后 我正在运行一个使用 Ajax 调用中创建的变量的函数 该函数只执行两次 我认为 Ajax 调用可能没有足够的时间在循环开始之前进行调用 有没有办法在运行
  • js中将div旋转到一定高度

    How to rotate a div to certain height suppose 10px I can rotate a div otherwise around 360 degrees I need the angle by w
  • 在 Javascript 中使用 fetch API 接收和处理 JSON

    在我的项目中 当条件不足时 我的 Django 应用程序会发送带有消息的 JSON 响应 我使用这个 JsonResponse 指令 Code data is taken email email return JsonResponse da
  • 对于调用另一个异步函数的异步函数,玩笑测试失败

    我正在尝试测试一个使用另一个异步函数返回的数据的异步函数 这是解释我的问题的代码 StudentInfo js export async function getData studentData imported from another
  • 为什么转换 new.Date() .toISOString() 会改变时间?

    我正在以两种不同的格式在数据库中插入日期 这是作为日期时间插入 var mydate mydate new Date document getElementById clockinhour value mydate toISOString
  • 使用 document.getElementsByName() 不起作用?

    第二个警报命令的代码按预期工作 显示元素 to 的值 但第一个警报命令不起作用 它应该做同样的事情 这是为什么

随机推荐

  • SQL Server 触发器隔离/范围文档

    我一直在寻找确定的有关 SQL Server 中触发器的隔离级别 或并发性或范围 我不确定确切的称呼它 的文档 我发现以下来源表明我认为是正确的 也就是说 两个用户对同一个表 甚至是相同的行 执行更新 然后将执行独立且隔离的触发器 http
  • Thymeleaf 中 th:each 语句中的 If-Else

    我想要的是 Thymeleaf 中 th each 语句中的 if else If currentSkill null 然后显示包含内容的表格 否则 您没有任何技能 这是没有 if else 的代码 div table tr td td t
  • 递归函数 vs setInterval vs setTimeout javascript

    我正在使用 NodeJs 并需要调用无限函数 但我不知道什么是最佳性能 递归函数 function test my code test 设置时间间隔 setInterval function my code 60 设置超时时间 functi
  • 如何在 Android 中从网络浏览器 (Chrome) 打开任何应用程序?我与 A Href 链接有什么关系?

    我想从我的网络浏览器打开第三方应用程序 所以 我没有任何清单文件或任何东西 我有一个网页 我想要一个可以打开第三方应用程序的链接 例如 Twitter 或 Opera 如何构建锚链接来打开该应用程序 谢谢 基于意图的 URI 的基本语法如下
  • 如何在 PHP 中设置自定义标头

    JAVA 开发人员在标头中向我发送数据 我这样认为 SESSION HTTP COUNTRYNAME 如何使用标头返回响应 它尝试过header countryname USA 但是PHPfunction headers list没有显示它
  • mysql根据之前的记录增加值

    我有一张桌子 Id Parent Counter 1 A NULL 2 A NULL 3 A NULL 4 B NULL 5 B NULL 6 C NULL 7 D NULL 8 D NULL 我想更新表 使计数器列更新 1 与之前的一样长
  • 如何避免在具有许多实例变量的类中使用 getter/setter

    我会尽量保持简短 我的类有很多实例变量 30 因此有很多 getter setter 这些类本身很简单 但由于 getter setter LOC 爆炸了 而且还有太多的代码重复 所以我删除了属性并将它们存储在地图中 如下所示 public
  • 定期轮询 Go 中的 REST 端点

    我正在尝试编写一个 Go 应用程序 定期轮询 PHP 应用程序公开的 REST 端点 Go 轮询应用程序将有效负载读取到结构中并进行进一步处理 我正在寻找一些关于开始实施的建议 最简单的方法是使用 Ticker ticker time Ne
  • d3js 在饼图周围重新分布标签

    我正在使用 d3 js 创建一个外部带有标签的圆环图 我使用基于饼图每片质心的三角函数来定位标签 g append g attr class percentage append text attr transform function d
  • 持久 Akka 邮箱和无损

    在 Akka 中 当一个 actor 在处理消息时死亡 内部onReceive 该消息丢失 有没有办法保证无损 有没有办法配置 Akka 始终保留消息before将他们发送到onReceive 以便在演员死亡时可以恢复并重播 也许像持久邮箱
  • 我应该如何在 Angular 模块中包含模型类?

    我有几个类 我想成为一个普通的 bean DTO 类 它们不显示 component 类 它们不是 Pipe 类 也不应该是 Directive 至少我认为不应该 是 我希望能够将它们捆绑到一个模块中 它们将在其他模块中使用 但尽管有几个咒
  • scala string.split 不起作用

    以下是我的 REPL 输出 我不确定为什么 string split 在这里不起作用 val s Pedro groceries apple 1 42 s java lang String Pedro groceries apple 1 4
  • 根据用户输入更改 AppID 和 AppName

    我想在同一系统上多次安装同一应用程序 例如两个用户使用两个不同的 Web 服务 每个都有自己的 在我的设置脚本中我想更改AppID and AppName基于用户的输入 例如我的默认值AppName Service App 应该改为AppN
  • 如何使用Vault在Ansible v2中运行playbook api

    这是我所拥有的 我知道这无需加密即可运行 并且我可以运行 ansible vault 编辑 common yml with ANSIBLE VAULT PASSWORD FILE vault pass txt 在环境中设置 from col
  • Gerrit 可以在 Gitlab 之前工作吗?还是打算取代它

    我认为我并没有真正理解 Gerrit 如何融入我团队现有的工作流程 Gerrit 是否打算成为代码的中心 枢纽 我一直把它想象成类似于 Atlassian 的 Crucible 它适合 Atlassian 的 Stash 或 Bitbuck
  • C# 反应式扩展 当 OnNext 花费很长时间并且可观察到产生新事件时会发生什么

    我是 Rx 新手 我在想当 IObservable 非常快地产生大量事件而 OnNext 需要很长时间时会发生什么 我猜想新事件会在内部以某种方式排队 这样我就可以运行我们的内存 我对吗 考虑下面的小例子 Subject
  • 如何对 json 数组值进行排序?

    我想将此 json 转换为按日期排序的 html 表 基本上我的 JSON 数据看起来像这样 这里我要recurrence列出日期 var frequencyList project abc recurrenceList 2021 09 1
  • IBrokers reqMktData,如何在回调函数中添加超时?

    我一直在使用来自 IBrokers 软件包的修改后的快照功能来从 IB 获取 最后 价格 并且它对于流动性股票非常有效 我打的电话是例如 reqMktData tws twsSTK AAPL eventWrapper eWrapper da
  • Ansible/Jinja2 - 映射列表中的嵌套键

    当映射嵌套变量列表中的属性时 我无法检索其键 我想从下面检索 tls cert file 的密钥强调文字变量 vault config listener tcp address 0 0 0 0 8200 tls cert file etc
  • JS 线性变换和矩阵乘法失败

    我正在学习线性代数并尝试制作一个具有基本线性变换的小程序 旋转 缩放 平移 这是完整的工作示例 我编写了用于为每个变换生成每个矩阵的函数以及用于计算它们的函数 矩阵与点相乘 矩阵相乘 export const multiplyMatrixW