三次贝塞尔曲线,二次贝塞尔曲线有什么区别
https://blog.csdn.net/xiaoyao961/article/details/148678265

SVG 贝塞尔曲线可视化设计器
下面是一个简单的贝塞尔曲线可视化设计器,使用 HTML5 和 JavaScript 实现。这个设计器允许你通过拖动控制点来实时调整贝塞尔曲线的形状。
这个贝塞尔曲线设计器具有以下特点:
直观的交互:可以直接拖动起点、终点和控制点来调整曲线形状
曲线类型切换:支持二次贝塞尔曲线和三次贝塞尔曲线
辅助线显示:可以显示或隐藏控制点之间的连接线,帮助理解曲线形成原理
颜色自定义:可以更改曲线的颜色
导出功能:可以将当前曲线导出为 SVG 文件
坐标显示:实时显示鼠标位置和控制点坐标
响应式设计:适配不同屏幕尺寸
您可以通过拖动各个点来观察曲线的变化,直观地理解贝塞尔曲线的形成原理。这对于网页设计、动画制作和游戏开发等领域都非常有用。

  <script src="https://cdn.tailwindcss.com"></script>3.4.16.js
 <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>贝塞尔曲线可视化设计器</title><script src="3.4.16.js"></script><link href="font-awesome.min.css" rel="stylesheet"><script>tailwind.config = {theme: {extend: {colors: {primary: '#3B82F6',secondary: '#10B981',accent: '#F59E0B',dark: '#1F2937',},fontFamily: {inter: ['Inter', 'sans-serif'],},}}}</script><style type="text/tailwindcss">@layer utilities {.content-auto {content-visibility: auto;}.bezier-control {cursor: move;transition: r 0.2s, fill 0.2s;}.bezier-control:hover {r: 8;fill: #F59E0B;}.bezier-handle {cursor: move;opacity: 0.5;transition: r 0.2s, fill 0.2s;}.bezier-handle:hover {r: 6;fill: #F59E0B;}.bezier-path {fill: none;stroke-width: 3;stroke-linecap: round;stroke-linejoin: round;}.bezier-guide {stroke-dasharray: 5,5;stroke-width: 1;stroke-opacity: 0.5;}}</style>
</head>
<body class="bg-gray-100 font-inter min-h-screen flex flex-col"><header class="bg-white shadow-md py-4 px-6"><div class="container mx-auto"><h1 class="text-2xl font-bold text-dark flex items-center"><i class="fa fa-curve mr-2 text-primary"></i>贝塞尔曲线可视化设计器</h1></div></header><main class="flex-1 container mx-auto p-4 flex flex-col md:flex-row gap-6"><!-- 控制面板 --><div class="md:w-1/4 bg-white rounded-lg shadow p-4"><h2 class="text-lg font-semibold mb-4 flex items-center"><i class="fa fa-sliders text-primary mr-2"></i>曲线控制</h2><div class="mb-4"><label class="block text-sm font-medium text-gray-700 mb-1">曲线类型</label><select id="curveType" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary/50"><option value="cubic">三次贝塞尔曲线</option><option value="quadratic">二次贝塞尔曲线</option></select></div><div id="cubicControls" class="mb-4"><label class="block text-sm font-medium text-gray-700 mb-1">显示辅助线</label><div class="flex items-center space-x-4"><label class="inline-flex items-center"><input type="checkbox" id="showGuides" class="form-checkbox h-5 w-5 text-primary rounded" checked><span class="ml-2 text-sm text-gray-700">显示控制线</span></label></div></div><div class="mb-4"><label class="block text-sm font-medium text-gray-700 mb-1">曲线颜色</label><input type="color" id="curveColor" class="w-full h-10 border border-gray-300 rounded-md" value="#3B82F6"></div><div class="mt-6"><button id="resetBtn" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-md transition duration-200 flex items-center justify-center"><i class="fa fa-refresh mr-2"></i>重置曲线</button></div><div class="mt-4"><button id="exportBtn" class="w-full bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-4 rounded-md transition duration-200 flex items-center justify-center"><i class="fa fa-download mr-2"></i>导出SVG</button></div></div><!-- 绘图区域 --><div class="md:w-3/4 flex-1 bg-white rounded-lg shadow overflow-hidden"><div class="p-4 border-b border-gray-200 flex justify-between items-center"><h2 class="text-lg font-semibold flex items-center"><i class="fa fa-paint-brush text-primary mr-2"></i>绘图区域</h2><div class="text-sm text-gray-500"><span id="coordinateDisplay">坐标: -</span></div></div><div class="relative"><!-- SVG 绘图区域 --><svg id="bezierCanvas" class="w-full h-[600px] bg-gray-50" viewBox="0 0 800 600"><!-- 网格背景 --><pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse"><path d="M 20 0 L 0 0 0 20" fill="none" stroke="#eee" stroke-width="0.5"/></pattern><rect width="100%" height="100%" fill="url(#grid)"/><!-- 贝塞尔曲线 --><path id="bezierPath" class="bezier-path" stroke="#3B82F6" d=""/><!-- 控制线(辅助线) --><line id="controlLine1" class="bezier-guide" stroke="#9CA3AF" x1="0" y1="0" x2="0" y2="0" /><line id="controlLine2" class="bezier-guide" stroke="#9CA3AF" x1="0" y1="0" x2="0" y2="0" /><!-- 控制点 --><circle id="startPoint" class="bezier-control" cx="100" cy="300" r="6" fill="#3B82F6" /><circle id="endPoint" class="bezier-control" cx="700" cy="300" r="6" fill="#3B82F6" /><!-- 二次贝塞尔曲线控制点 --><circle id="controlPoint1" class="bezier-handle" cx="400" cy="150" r="5" fill="#10B981" /><!-- 三次贝塞尔曲线控制点(默认隐藏) --><circle id="controlPoint2" class="bezier-handle" cx="400" cy="450" r="5" fill="#10B981"></circle></svg></div></div></main><footer class="bg-dark text-white py-4 mt-6"><div class="container mx-auto px-4 text-center text-sm"><p>贝塞尔曲线可视化设计器 &copy; 2025</p></div></footer><script>// 初始化变量let isDragging = false;let selectedElement = null;let offset = { x: 0, y: 0 };let curveType = 'cubic';let showGuides = true;// 获取DOM元素const svg = document.getElementById('bezierCanvas');const bezierPath = document.getElementById('bezierPath');const startPoint = document.getElementById('startPoint');const endPoint = document.getElementById('endPoint');const controlPoint1 = document.getElementById('controlPoint1');const controlPoint2 = document.getElementById('controlPoint2');const controlLine1 = document.getElementById('controlLine1');const controlLine2 = document.getElementById('controlLine2');const curveTypeSelect = document.getElementById('curveType');const showGuidesCheckbox = document.getElementById('showGuides');const curveColorInput = document.getElementById('curveColor');const resetBtn = document.getElementById('resetBtn');const exportBtn = document.getElementById('exportBtn');const coordinateDisplay = document.getElementById('coordinateDisplay');// 更新贝塞尔曲线function updateBezierCurve() {const startX = parseFloat(startPoint.getAttribute('cx'));const startY = parseFloat(startPoint.getAttribute('cy'));const endX = parseFloat(endPoint.getAttribute('cx'));const endY = parseFloat(endPoint.getAttribute('cy'));const cp1X = parseFloat(controlPoint1.getAttribute('cx'));const cp1Y = parseFloat(controlPoint1.getAttribute('cy'));const cp2X = parseFloat(controlPoint2.getAttribute('cx'));const cp2Y = parseFloat(controlPoint2.getAttribute('cy'));// 更新控制线if (showGuides) {controlLine1.setAttribute('x1', startX);controlLine1.setAttribute('y1', startY);controlLine1.setAttribute('x2', cp1X);controlLine1.setAttribute('y2', cp1Y);if (curveType === 'cubic') {controlLine2.setAttribute('x1', cp2X);controlLine2.setAttribute('y1', cp2Y);controlLine2.setAttribute('x2', endX);controlLine2.setAttribute('y2', endY);}}// 更新曲线let pathData = '';if (curveType === 'quadratic') {pathData = `M ${startX},${startY} Q ${cp1X},${cp1Y} ${endX},${endY}`;} else {pathData = `M ${startX},${startY} C ${cp1X},${cp1Y} ${cp2X},${cp2Y} ${endX},${endY}`;}bezierPath.setAttribute('d', pathData);}// 处理SVG坐标function getSVGPoint(event) {const pt = svg.createSVGPoint();pt.x = event.clientX;pt.y = event.clientY;return pt.matrixTransform(svg.getScreenCTM().inverse());}// 事件处理:开始拖动function startDrag(event) {if (event.target.classList.contains('bezier-control') || event.target.classList.contains('bezier-handle')) {isDragging = true;selectedElement = event.target;const svgPoint = getSVGPoint(event);const cx = parseFloat(selectedElement.getAttribute('cx'));const cy = parseFloat(selectedElement.getAttribute('cy'));offset.x = svgPoint.x - cx;offset.y = svgPoint.y - cy;svg.style.cursor = 'grabbing';event.preventDefault();}}// 事件处理:拖动中function drag(event) {if (isDragging) {const svgPoint = getSVGPoint(event);const cx = svgPoint.x - offset.x;const cy = svgPoint.y - offset.y;// 限制在SVG画布内const svgRect = svg.getBoundingClientRect();const newX = Math.max(0, Math.min(cx, svgRect.width));const newY = Math.max(0, Math.min(cy, svgRect.height));selectedElement.setAttribute('cx', newX);selectedElement.setAttribute('cy', newY);// 更新坐标显示coordinateDisplay.textContent = `坐标: (${Math.round(newX)}, ${Math.round(newY)})`;// 更新曲线updateBezierCurve();}}// 事件处理:结束拖动function endDrag() {isDragging = false;selectedElement = null;svg.style.cursor = 'default';}// 事件处理:曲线类型变更function handleCurveTypeChange() {curveType = curveTypeSelect.value;if (curveType === 'quadratic') {controlPoint2.style.display = 'none';controlLine2.style.display = 'none';} else {controlPoint2.style.display = 'block';controlLine2.style.display = 'block';}updateBezierCurve();}// 事件处理:显示辅助线变更function handleShowGuidesChange() {showGuides = showGuidesCheckbox.checked;controlLine1.style.display = showGuides ? 'block' : 'none';controlLine2.style.display = showGuides && curveType === 'cubic' ? 'block' : 'none';}// 事件处理:曲线颜色变更function handleCurveColorChange() {bezierPath.setAttribute('stroke', curveColorInput.value);startPoint.setAttribute('fill', curveColorInput.value);endPoint.setAttribute('fill', curveColorInput.value);}// 事件处理:重置按钮function handleReset() {// 重置点位置startPoint.setAttribute('cx', 100);startPoint.setAttribute('cy', 300);endPoint.setAttribute('cx', 700);endPoint.setAttribute('cy', 300);controlPoint1.setAttribute('cx', 400);controlPoint1.setAttribute('cy', 150);controlPoint2.setAttribute('cx', 400);controlPoint2.setAttribute('cy', 450);// 重置曲线类型和颜色curveTypeSelect.value = 'quadratic';curveType = 'quadratic';curveColorInput.value = '#3B82F6';bezierPath.setAttribute('stroke', '#3B82F6');startPoint.setAttribute('fill', '#3B82F6');endPoint.setAttribute('fill', '#3B82F6');// 更新显示controlPoint2.style.display = 'none';controlLine2.style.display = 'none';showGuidesCheckbox.checked = true;showGuides = true;// 更新曲线updateBezierCurve();}// 事件处理:导出SVGfunction handleExport() {// 创建新的SVG元素const exportSvg = svg.cloneNode(true);// 移除事件监听器和不必要的元素exportSvg.removeAttribute('style');exportSvg.removeAttribute('onmousedown');exportSvg.removeAttribute('onmousemove');exportSvg.removeAttribute('onmouseup');// 移除网格背景的pattern引用const rect = exportSvg.querySelector('rect');if (rect) {rect.setAttribute('fill', 'white');}// 移除坐标显示相关元素const coordinateDisplay = exportSvg.querySelector('#coordinateDisplay');if (coordinateDisplay) {coordinateDisplay.parentNode.removeChild(coordinateDisplay);}// 创建SVG字符串const svgData = new XMLSerializer().serializeToString(exportSvg);// 创建下载链接const blob = new Blob([svgData], {type: 'image/svg+xml'});const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'bezier-curve.svg';document.body.appendChild(a);a.click();setTimeout(() => {document.body.removeChild(a);URL.revokeObjectURL(url);}, 0);}// 添加事件监听器svg.addEventListener('mousedown', startDrag);document.addEventListener('mousemove', drag);document.addEventListener('mouseup', endDrag);curveTypeSelect.addEventListener('change', handleCurveTypeChange);showGuidesCheckbox.addEventListener('change', handleShowGuidesChange);curveColorInput.addEventListener('input', handleCurveColorChange);resetBtn.addEventListener('click', handleReset);exportBtn.addEventListener('click', handleExport);// 初始化updateBezierCurve();handleShowGuidesChange();</script>
</body>
</html>    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/909518.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/909518.shtml
英文地址,请注明出处:http://en.pswp.cn/news/909518.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pytorch框架——自动微分和反向传播

一、自动微分概念 自动微分&#xff08;Automatic Differentiation&#xff0c;AD&#xff09;是一种利用计算机程序自动计算函数导数的技术&#xff0c;它是机器学习和优化算法中的核心工具&#xff08;如神经网络的梯度下降&#xff09;&#xff0c;通过反向传播计算并更新梯…

【Linux手册】进程的状态:从创建到消亡的“生命百态”

目录 前言 操作系统进程状态 运行状态 阻塞状态 挂起状态 Linux中具体的进程状态 R(running)运行状态 S(sleeping)阻塞状态 D(disk sleep)磁盘休眠状态 T(stopped)和t(tracing stop) X(dead)终止状态 Z(zombie)僵尸状态 僵尸进程的危害 前言 我们在运行可执行程序…

李沐--动手学深度学习 LSTM

1.从零开始实现LSTM #从零开始实现长短期记忆网络 import torch from torch import nn from d2l import torch as d2l#加载时光机器数据集 batch_size,num_steps 32,35 train_iter,vocab d2l.load_data_time_machine(batch_size,num_steps)#1.定义和初始化模型参数&#xff…

面经的疑难杂症

1.介绍一下虚拟地址&#xff0c;虚拟地址是怎么映射到物理地址的&#xff1f; 虚拟地址是指在采用虚拟存储管理的操作系统中&#xff0c;进程访问内存时所使用的地址。每个进程都有独立的虚拟地址空间&#xff0c;虚拟地址通过操作系统和硬件&#xff08;如MMU&#xff0c;内存…

去噪扩散概率模型(DDPM)全解:从数学基础到实现细节

一、 概述 在这篇博客文章中&#xff0c;我们将深入探讨去噪扩散概率模型&#xff08;也被称为 DDPMs&#xff0c;扩散模型&#xff0c;基于得分的生成模型&#xff0c;或简称为自动编码器&#xff09;&#xff0c;这可以说是AIGC最近几年飞速发展的基石&#xff0c;如果你想做…

【系统分析师】2011年真题:案例分析-答案及详解

文章目录 试题1【问题 1】【问题 2】【问题 3】 试题2【问题 1】【问题 2】【问题 3】 试题3【问题 1】【问题 2】【问题 3】 试题4【问题 1】【问题 2】【问题 3】 试题5【问题 1】【问题 2】【问题 3】 试题1 随着宽带应用快速发展&#xff0c;用户要求系统服务提供商提供基…

【unitrix】 1.7 规范化常量类型结构(standardization.rs)

一、源码 这段代码实现了一个二进制数字标准化系统&#xff0c;用于将二进制数字类型&#xff08;B0/B1&#xff09;转换为更简洁的表示形式。 //! 二进制数字标准化模块 / Binary Number Normalization Module //! //! 提供将二进制数字(B0/B1)标准化为更简洁表示形式的功能…

NJet Portal 应用门户管理介绍

nginx向云原生演进&#xff0c;All in OpenNJet&#xff01; 1. 应用门户简介 NJet 应用引擎是基于 Nginx 的面向互联网和云原生应用提供的运行时组态服务程序&#xff0c;作为底层引擎&#xff0c;NJet 实现了NGINX 云原生功能增强、安全加固和代码重构&#xff0c;利用动态加…

uni-app学习笔记三十六--分段式选项卡组件的使用

先来看效果&#xff1a; 上图有3个选项卡&#xff08;PS:uniapp官方称之为分段器&#xff0c;我还是习惯叫选项卡&#xff09;&#xff0c;需要实现点击不同的选项卡时下方切换显示对应的数据。 下面介绍下实现的过程。 1.在uniapp官方文档下载并安装该扩展组件&#xff1a;u…

Qt:Qt桌面程序正常退出注意事项

一般情况下&#xff0c;Qt窗体的创建和显示命令如下&#xff1a; Main_window main_window; main_window.show(); 主窗体中设置属性Qt::WA_DeleteOnClose setAttribute(Qt::WA_DeleteOnClose); 则在main.cpp中可以将窗体创建为指针&#xff0c;这样在退出时可以正确释放指针…

【arXiv2024】时间序列|TimesFM-ICF:即插即用!时间序列预测新王者!吊打微调!

论文地址&#xff1a;https://arxiv.org/pdf/2410.24087 代码地址&#xff1a;https://github.com/uctb/TSFM 为了更好地理解时间序列模型的理论与实现&#xff0c;推荐参考UP “ThePPP时间序列” 的教学视频。该系列内容系统介绍了时间序列相关知识&#xff0c;并提供配套的论…

从0开始学习语言模型--Day02-如何最大化利用硬件

如何利用硬件 这个单元分为内核、并行处理和推理。 内核&#xff08;Kernels&#xff09; 我们说的内核一般指的就是GPU&#xff0c;这是我们用于计算的地方&#xff0c;一般说的计算资源就指的是GPU的大小。我们模型所用的数据和参数一般存储在内存里&#xff0c;假设把内存…

ElasticSearch配置详解:设置内存锁定的好处

什么是内存锁定 "bootstrap": {"memory_lock": "true" }内存锁定是指将Elasticsearch的JVM堆内存锁定在物理内存中&#xff0c;防止操作系统将其交换&#xff08;swap&#xff09;到磁盘。 内存交换是操作系统的虚拟内存管理机制&#xff0c;当…

成功解决 ValueError: Unable to find resource t64.exe in package pip._vendor.distlib

解决问题 我们在本地的命令行中运行指令"python -m pip install --upgrade pip"的时候&#xff0c;报了如下的错误&#xff1a; 解决思路 我们需要重新安装一下pip。 解决方法 步骤1&#xff1a; 通过执行下面的指令删除本地的pip: python -m pip uninstall pip…

仓库物资出入库管理系统源码+uniapp小程序

一款基于ThinkPHPuniapp开发的仓库物资出入库管理系统&#xff0c;适用于单位内部物资采购、发放管理的库存管理系统。提供全部无加密源码&#xff0c;支持私有化部署。 更新日志&#xff1a; 新增 基于UNIAPP开发的手机端&#xff0c;适配微信小程序 新增 字典管理 新增页面…

基于机器学习的逐巷充填开采岩层运动地表沉降预测

基于机器学习的逐巷充填开采岩层运动地表沉降预测 1. 项目概述 本报告详细介绍了使用Python和机器学习技术预测逐巷充填开采过程中地表沉降的方法。通过分析地质参数、开采参数和充填参数,构建预测模型评估地表沉降风险。 # 导入必要的库 import numpy as np import pandas…

MotleyCrew ——抛弃dify、coze,手动搭建多agent工作流

1. MotleyCrew 核心组件 &#xff0d; 协调器&#xff1a; Crew MotleyCrew 的核心是一个 “Crew” 对象&#xff0c;即多代理系统的指挥者。Crew 持有一个全局的知识图谱&#xff08;使用 Kuzu 图数据库&#xff09;&#xff0c;用于记录所有任务、任务单元和其执行状态。 Cr…

掌握这些 Python 函数,让你的代码更简洁优雅

在 Python 编程世界里&#xff0c;代码的简洁性与可读性至关重要。简洁优雅的代码不仅便于自己后期维护&#xff0c;也能让其他开发者快速理解逻辑。而 Python 丰富的内置函数和一些实用的第三方库函数&#xff0c;就是实现这一目标的有力武器。接下来&#xff0c;就为大家介绍…

简说ping、telnet、netcat

简说 ping 和 telnet 命令的作用、用法和区别&#xff0c;方便理解它们在网络诊断中的用途。 &#x1f310; ping 命令 ✅ 作用&#xff1a; ping 用于检测网络连通性。它通过向目标主机发送 ICMP Echo 请求 并等待回应&#xff0c;从而判断目标主机是否可达&#xff0c;并测…

基于STM32的超声波模拟雷达设计

一、雷达概述 雷达&#xff08;Radio Detection and Ranging&#xff0c;无线电探测与测距&#xff09;是一种利用电磁波探测目标位置、速度等信息的主动式传感器系统。其基本原理是发射电磁波并接收目标反射的回波&#xff0c;通过分析回波的时间差、频率变化等参数&#xff0…