js实现两个轴直线插补圆弧插补

news/2024/9/29 18:13:51 标签: javascript, 前端, 开发语言

效果图

插补

源代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Multi-Axis Motion with Canvas</title>
  <style>
    body {
      margin: 0;
    }
    #controls {
      position: absolute;
      top: 10px;
      right: 10px;
      z-index: 1;
      background: rgba(255, 255, 255, 0.8);
      padding: 10px;
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <div id="controls">
    <h4>直线插补</h4>
    <label>起始点 X: <input type="number" id="startX" value="10"></label><br>
    <label>起始点 Y: <input type="number" id="startY" value="1"></label><br>
    <label>结束点 X: <input type="number" id="endX" value="20"></label><br>
    <label>结束点 Y: <input type="number" id="endY" value="10"></label><br>
    <label>进给速率: <input type="number" id="feedRateLine" value="15"></label><br>
    <button id="lineButton">执行直线插补</button><br><br>

    <h4>圆弧插补</h4>
    <label>圆心 X: <input type="number" id="centerX" value="250"></label><br>
    <label>圆心 Y: <input type="number" id="centerY" value="250"></label><br>
    <label>半径: <input type="number" id="radius" value="100"></label><br>
    <label>起始角度: <input type="number" id="startAngle" value="0" step="0.01"></label><br>
    <label>结束角度: <input type="number" id="endAngle" value="1.57" step="0.01"></label><br>
    <label>进给速率: <input type="number" id="feedRateArc" value="10"></label><br>
    <button id="arcButton">执行圆弧插补</button><br><br>

    <button id="clearButton">清空画布</button>
  </div>

  <canvas id="myCanvas" width="500" height="500"></canvas>

  <script>
    class Axis {
      constructor() {
        this.position = 0;
        this.velocity = 0;
        this.acceleration = 0;
        this.targetPosition = 0;
      }

      update(dt) {
        const distance = this.targetPosition - this.position;
        const absDistance = Math.abs(distance);
        const decelDistance = Math.pow(this.velocity, 2) / (2 * this.acceleration);

        if (absDistance <= decelDistance) {
          if (Math.abs(this.velocity) < 0.001) {
            this.velocity = 0;
            this.position = this.targetPosition;
          } else {
            const sign = distance > 0 ? 1 : -1;
            this.velocity -= sign * this.acceleration * dt;
            this.position += this.velocity * dt;
          }
        } else {
          if (Math.abs(this.velocity) < this.targetVelocity) {
            this.velocity += this.acceleration * dt;
          }
          this.position += this.velocity * dt;
        }
      }
    }

    class MultiAxisSystem {
      constructor(numAxes) {
        this.axes = new Array(numAxes).fill().map(() => new Axis());
        this.canvas = document.getElementById('myCanvas');
        this.ctx = this.canvas.getContext('2d');
        this.ctx2 = this.canvas.getContext('2d');
        this.historyPoint=[];
      }

      setTargetPositions(targetPositions) {
        if (targetPositions.length !== this.axes.length) {
          console.error("Invalid target positions.");
          return;
        }
        for (let i = 0; i < this.axes.length; ++i) {
          this.axes[i].targetPosition = targetPositions[i];
        }
      }

      update(dt) {
        this.axes.forEach(axis => axis.update(dt));
      }

      linearInterpolation(startX, startY, endX, endY, feedRate, dt) {
        const distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
        const totalTime = distance / feedRate;
        const numSteps = Math.floor(totalTime / dt);
        const xStep = (endX - startX) / numSteps;
        const yStep = (endY - startY) / numSteps;

        let currentStep = 0;

        const animate = () => {
          if (currentStep < numSteps) {
            const x = startX + currentStep * xStep;
            const y = startY + currentStep * yStep;

            this.setTargetPositions([x, y]);
            this.update(dt);
            this.draw(x, y);

            currentStep++;
            setTimeout(animate, dt * 1000);
          }
        };
        animate();
      }

      circularInterpolation(centerX, centerY, radius, startAngle, endAngle, feedRate, dt) {
        const arcLength = Math.abs(endAngle - startAngle) * radius;
        const totalTime = arcLength / feedRate;
        const numSteps = Math.floor(totalTime / dt);
        const angleStep = (endAngle - startAngle) / numSteps;

        let currentStep = 0;

        const animate = () => {
          if (currentStep < numSteps) {
            const currentAngle = startAngle + currentStep * angleStep;
            const x = centerX + radius * Math.cos(currentAngle);
            const y = centerY + radius * Math.sin(currentAngle);

            this.setTargetPositions([x, y]);
            this.update(dt);
            this.draw(x, y);
            
            currentStep++;
            setTimeout(animate, dt * 1000);
          }
        };
        animate();
      }

      draw(x, y) {
        
        let ctx=this.ctx
        let canvas=this.canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);


        // 绘制网格
        const gridSize = 20;
        ctx.strokeStyle = '#e0e0e0';
        ctx.beginPath();
        for (let i = 0; i <= canvas.width; i += gridSize) {
          ctx.moveTo(i, 0);
          ctx.lineTo(i, canvas.height);
        }
        for (let j = 0; j <= canvas.height; j += gridSize) {
          ctx.moveTo(0, j);
          ctx.lineTo(canvas.width, j);
        }
        ctx.stroke();

        // 绘制坐标轴
        ctx.strokeStyle = 'black';
        ctx.beginPath();
        ctx.moveTo(canvas.width / 2, 0);
        ctx.lineTo(canvas.width / 2, canvas.height);
        ctx.moveTo(0, canvas.height / 2);
        ctx.lineTo(canvas.width, canvas.height / 2);
        ctx.stroke();

        let ctx2=this.ctx2
        if(this.historyPoint.length>0){
            for (let i = 0; i < this.historyPoint.length; i++) {
                ctx2.beginPath();
                ctx2.arc(this.historyPoint[i].x, this.historyPoint[i].y, 5, 0, 2 * Math.PI);
                ctx2.fillStyle = 'green';
                ctx2.fill();
            }
        }
        this.historyPoint.push({x,y})

      
        // 绘制运动点
        ctx2.beginPath();
        ctx2.arc(x, y, 5, 0, 2 * Math.PI);
        ctx2.fillStyle = 'blue';
        ctx2.fill();

        // 在左上角绘制坐标
        ctx.fillStyle = 'red';
        ctx.font = '12px Arial';
        ctx.fillText(`(${x.toFixed(2)}, ${y.toFixed(2)})`, 10, 20);
      }

      clearCanvas() {
        this.historyPoint=[]
        const ctx = this.canvas.getContext('2d');
        ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
      }
    }

    const multiAxisSystem = new MultiAxisSystem(2);
    const timeStep = 0.01;

    document.getElementById('lineButton').addEventListener('click', () => {
      const startX = parseFloat(document.getElementById('startX').value);
      const startY = parseFloat(document.getElementById('startY').value);
      const endX = parseFloat(document.getElementById('endX').value);
      const endY = parseFloat(document.getElementById('endY').value);
      const feedRate = parseFloat(document.getElementById('feedRateLine').value);
      multiAxisSystem.historyPoint=[];
      multiAxisSystem.linearInterpolation(startX, startY, endX, endY, feedRate, timeStep);
    });

    document.getElementById('arcButton').addEventListener('click', () => {
      const centerX = parseFloat(document.getElementById('centerX').value);
      const centerY = parseFloat(document.getElementById('centerY').value);
      const radius = parseFloat(document.getElementById('radius').value);
      const startAngle = parseFloat(document.getElementById('startAngle').value);
      const endAngle = parseFloat(document.getElementById('endAngle').value);
      const feedRate = parseFloat(document.getElementById('feedRateArc').value);
      multiAxisSystem.historyPoint=[];
      multiAxisSystem.circularInterpolation(centerX, centerY, radius, startAngle, endAngle, feedRate, timeStep);
    });

    document.getElementById('clearButton').addEventListener('click', () => {
      multiAxisSystem.clearCanvas();
    });
  </script>
</body>
</html>

http://www.niftyadmin.cn/n/5683505.html

相关文章

不同领域的常见 OOD(Out-of-Distribution)数据集例子

以下是几个来自不同领域的常见 OOD&#xff08;Out-of-Distribution&#xff09;数据集例子&#xff0c;这些数据集常用于测试和研究模型在分布变化或分布外数据上的泛化能力&#xff1a; 1. 计算机视觉领域 CIFAR-10 vs. CIFAR-10-C / CIFAR-100-C: 描述&#xff1a;CIFAR-10…

滚雪球学MySQL[6.1讲]:数据备份与恢复

全文目录&#xff1a; 前言6. 数据备份与恢复6.1 备份的基础知识6.1.1 备份的重要性6.1.2 备份的类型 6.2 备份策略6.2.1 完全备份与增量备份结合6.2.2 定期检查备份有效性6.2.3 异地备份 6.3 MySQL备份工具6.3.1 mysqldump6.3.2 mysqlhotcopy6.3.3 Percona XtraBackup 6.4 数据…

LSTM预测未来30天销售额

加入深度实战社区:www.zzgcz.com&#xff0c;免费学习所有深度学习实战项目。 1. 项目简介 本项目旨在利用深度学习中的长短期记忆网络&#xff08;LSTM&#xff09;来预测未来30天的销售额。LSTM模型能够处理时序数据中的长期依赖问题&#xff0c;因此在销售额预测这类涉及时…

latex作者介绍添加,以及作者介绍段落间距调整(看这篇就够了)

文章目录 1.latex语句如何添加作者的介绍和照片2.作者介绍段落和段落之间的距离太大如何调整 1.latex语句如何添加作者的介绍和照片 \begin{IEEEbiography}[{\includegraphics[width1in,height1.25in,clip,keepaspectratio]{图像存放地址}}]{作者姓名} 这里写作者介绍 \end{IE…

rpm方式安装jdk1.8

1、查询系统中是否已经安装jdk rpm -qa |grep java 或 rpm -qa |grep jdk 2、卸载已有的openjdk rpm -e --nodeps java-1.7.0-openjdk rpm -e --nodeps java-1.7.0-openjdk-headless rpm -e --nodeps java-1.8.0-openjdk rpm -e --nodeps java-1.8.0-openjdk-headless3、安装j…

低代码单点登录:提升用户体验与安全性的新方案

什么是低代码单点登录&#xff1f; 低代码单点登录是一种通过低代码开发平台构建的用户身份验证方案。用户在登录一次后&#xff0c;可以无缝访问多个应用程序和服务&#xff0c;无需再次输入凭证。这一系统不仅简化了用户的登录流程&#xff0c;还能提高安全性&#xff0c;通…

VMware下Ubuntu找不到共享文件夹

在VMware的设置中已经设置了共享文件夹&#xff0c;在Ubuntu系统中找不到&#xff0c;参考了网上其他的文章&#xff0c;发现还是不能解决问题&#xff0c;无意中尝试了一小步&#xff0c;没想到成功解决了&#xff0c;在这里记录一下。 1&#xff09;首先查询本机的gid 2&…

创建数据/采集数据+从PI数据到PC+实时UI+To PLC

Get_Data ---------- import csv import os import random from datetime import datetime import logging import time # 配置日志记录 logging.basicConfig(filename=D:/_Study/Case/Great_Data/log.txt, level=logging.INFO, format=%(asctime)s - %(l…