在Processing中实现基于鼠标输入的2D图形独立旋转与拖动

在Processing中实现基于鼠标输入的2D图形独立旋转与拖动

本教程详细介绍了如何在processing中利用2d变换矩阵(translate、rotate、pushmatrix、popmatrix)和鼠标事件(mousedragged)实现多个图形的独立旋转和整体拖动。文章强调了使用相对坐标定义图形的重要性,并提供了示例代码,帮助开发者创建交互式的动态图形效果。

Processing 2D图形变换基础

Processing提供了一套强大的2D变换函数,允许我们对图形进行平移、旋转和缩放,而无需手动修改每个顶点的坐标。这些变换基于一个内部的变换矩阵,它定义了当前绘图环境的坐标系统。理解这些变换的关键在于它们是累积的,并且会影响其之后的所有绘图操作。

translate(x, y): 将坐标系的当前原点移动到新的位置(x, y)。在此之后绘制的所有图形都将相对于这个新原点进行定位。rotate(angle): 围绕当前坐标系的原点旋转绘图环境。angle通常以弧度表示。scale(s) 或 scale(sx, sy): 改变绘图环境的尺寸。

实现图形的静态旋转与拖动

当我们需要让图形在屏幕上保持其“中心”位置旋转,或者通过鼠标拖动来移动它们时,需要巧妙地结合translate()和rotate()。

1. 避免图形“飞出”屏幕

初学者在使用rotate()时常遇到的问题是图形会围绕画布的左上角(默认原点(0,0))旋转,导致图形移出可见区域。要解决这个问题,我们需要:

将坐标系原点移动到图形的中心:在调用rotate()之前,先使用translate(centerX, centerY)将坐标系原点移动到图形的旋转中心。使用相对坐标定义图形:图形的所有顶点坐标都应该相对于其旋转中心来定义。例如,如果图形的中心是(0,0),那么其顶点坐标应是相对于(0,0)的偏移量。

2. 鼠标拖动平移功能

为了实现通过鼠标拖动来移动整个图形组,我们可以利用mouseDragged()事件。这个函数会在鼠标被按下并拖动时持续触发。

float offsetX = 0; // 用于存储整体平移的X偏移量float offsetY = 0; // 用于存储整体平移的Y偏移量void setup() {  size(1800, 1000);}void draw() {  background(0); // 每帧清空背景  // 应用整体平移  translate(offsetX, offsetY);  // ... 在这里绘制所有图形 ...}void mouseDragged() {  // 更新偏移量,使图形跟随鼠标移动  offsetX = mouseX;  offsetY = mouseY;}

在上述代码中,offsetX和offsetY跟踪鼠标的当前位置,并通过translate(offsetX, offsetY)将整个绘图环境的原点移动到鼠标位置。这意味着所有后续绘制的图形都会以鼠标位置为新的(0,0)点进行绘制。

稿定抠图 稿定抠图

AI自动消除图片背景

稿定抠图 76 查看详情 稿定抠图

独立图形的旋转:pushMatrix()与popMatrix()

要让多个图形独立地旋转,例如一个顺时针旋转,另一个逆时针旋转,同时保持它们各自的中心,就需要使用pushMatrix()和popMatrix()。

pushMatrix(): 保存当前的变换矩阵状态。它将当前坐标系的状态(包括平移、旋转、缩放)压入一个中。popMatrix(): 恢复到最近一次pushMatrix()保存的变换矩阵状态。它从栈中弹出上一个状态,并将其设为当前坐标系状态。

通过在每个独立图形的绘制代码块前后分别调用pushMatrix()和popMatrix(),我们可以为每个图形创建独立的变换环境,互不干扰。

示例:两颗星形图形的独立旋转

以下示例展示了如何在Processing中创建两个星形图形,它们围绕各自的中心独立旋转(一个顺时针,一个逆时针),并且整个图形组可以通过鼠标拖动进行平移。图形的顶点坐标已调整为相对于其自身中心(0,0)的相对坐标。

float offsetX = 0; // 整体平移Xfloat offsetY = 0; // 整体平移Yvoid setup() {  size(1800, 1000);  // 初始时将整体平移中心设置在画布中央  offsetX = width / 2;  offsetY = height / 2;}void draw() {  background(0); // 每帧清空背景  // 1. 应用整体平移,将所有图形的逻辑中心移动到鼠标拖动的位置  translate(offsetX, offsetY);  // --- 第一个星形 (顺时针旋转) ---  pushMatrix(); // 保存当前变换状态 (包括整体平移)    // 2. 围绕当前原点 (即星形的中心) 旋转    rotate(frameCount * 0.01); // frameCount是一个内置变量,提供连续的动画值    // 3. 绘制第一个星形 (使用相对于其中心的坐标)    fill(139, 19, 191);    triangle( 100,  100,    0,  350, -100,  100);    fill(20, 134, 245);    triangle( 200, -100,  350,  100,  100,  100);    fill(191, 8, 8);    triangle(-100,  100, -350,  100, -200, -100);    fill(86, 165, 3);    triangle(-200, -100, -350, -400,    0, -150);    fill(167, 167, 166);    triangle(   0, -150,  350, -400,  200, -100);  popMatrix(); // 恢复到pushMatrix()时的变换状态 (取消了第一个星形的旋转)  // --- 第二个星形 (逆时针旋转) ---  pushMatrix(); // 再次保存当前变换状态 (包括整体平移)    // 2. 围绕当前原点 (即星形的中心) 逆时针旋转    rotate(frameCount * -0.01);    // 3. 绘制第二个星形 (使用相对于其中心的坐标)    fill(139, 19, 191);    triangle(-100, -150,    0, -400,  100, -150);    fill(86, 165, 3);    triangle( 100, -150,  350, -150,  200,   50);    fill(167, 167, 166);    triangle(-200,   50, -350, -150, -100, -150);    fill(20, 134, 245);    triangle(-200,   50, -350,  350,    0,  150);    fill(191, 8, 8);    triangle( 200,  50, 350, 350,   0, 150);  popMatrix(); // 恢复到pushMatrix()时的变换状态 (取消了第二个星形的旋转)  // 绘制中心圆 (相对于当前原点,即整体平移后的中心)  fill(0, 0, 0);  // 注意:Processing内置的圆形绘制函数是ellipse,这里为了兼容原代码,使用自定义的circle函数  circle(0, 0, 425);}// 鼠标拖动时更新整体平移偏移量void mouseDragged() {  offsetX = mouseX;  offsetY = mouseY;}// 自定义circle函数,实际调用ellipsevoid circle(float x, float y, float r) {  ellipse(

以上就是在Processing中实现基于鼠标输入的2D图形独立旋转与拖动的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1026140.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Golang如何使用compress/gzip实现文件压缩
上一篇 2025年12月2日 01:49:27
win11系统麦克风没声音怎么办
下一篇 2025年12月2日 01:49:31

相关推荐

  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 深入理解 Express.js 中 next() 参数的作用与中间件机制

    本文深入探讨 express.js 中间件函数中的 `next()` 参数。它负责将控制权传递给请求-响应周期中的下一个中间件或路由处理程序。文章将详细解释 `next()` 的工作原理、中间件的注册与执行顺序,以及不正确使用 `next()` 可能导致请求挂起的风险,并通过代码示例和实际应用场景,…

    2026年5月10日
    000
  • Golang空接口如何应用在项目中

    空接口可用于接收任意类型值,常见于日志函数、通用数据结构、JSON动态解析及配置驱动逻辑,提升代码灵活性,但需配合类型断言确保安全,避免滥用以降低维护成本。 空接口 interface{} 在 Go 语言中是一个非常灵活的类型,它可以存储任何类型的值。虽然它牺牲了一部分类型安全,但在实际项目中合理使…

    2026年5月10日
    100
  • Go语言Cgo代码GDB调试失效:Go 1.1版本下的挑战与官方进展

    本文探讨了go语言程序中cgo代码在使用gdb进行调试时遇到的挑战,特别指出go 1.1版本中存在的变量值显示异常问题。该问题是一个已知的官方缺陷(go issue 5221),导致在cgo交互部分gdb调试功能失效,而go 1.0版本则无此问题。文章将通过示例代码重现该现象,并阐述其根源及官方的解…

    2026年5月10日
    000
  • PHP动态网页数据库备份恢复_PHP动态网页MySQL数据库备份教程

    答案:PHP动态网页的MySQL数据库备份与恢复需通过定期导出SQL文件并安全存储来保障数据安全,核心方法包括使用mysqldump命令行工具实现高效灵活的自动化备份,利用phpMyAdmin图形化工具进行手动导出导入以降低操作门槛,以及通过PHP脚本调用系统命令将备份过程集成到应用中;恢复时可采用…

    2026年5月10日
    000
  • C#如何处理异常?C# try-catch-finally最佳实践与常见错误规避

    正确使用 try-catch-finally 应捕获具体异常、用 finally 或 using 释放资源、避免空 catch 和裸抛异常,确保异常日志记录并保留堆栈跟踪,提升代码健壮性与可维护性。 在C#中,异常处理是保障程序稳定运行的重要机制。正确使用 try-catch-finally 结构不…

    2026年5月10日
    000
  • JavaScript解释器_javascript代码执行

    JavaScript通过引擎解析执行,先语法分析生成AST,再编译为字节码或机器码,最后执行;执行时创建上下文并入栈,同步代码直接运行,异步任务由API处理后回调入队,事件循环在调用栈空时将回调推入执行;此机制解释了变量提升、暂时性死区及宏任务与微任务执行顺序差异。 JavaScript代码的执行依…

    2026年5月10日
    000
  • Flet应用中正确显示AlertDialog对话框的指南

    本文旨在指导flet开发者如何正确显示`alertdialog`对话框。针对在`usercontrol`中直接设置`dlg_modal.open = true`和调用`self.update()`无法显示对话框的常见问题,文章详细阐述了其原因,并提供了使用`e.page.show_dialog_as…

    2026年5月10日
    000
  • JavaScript数据结构实现_javascript算法基础

    JavaScript中常用数据结构包括栈、链表和字典:1. 栈利用数组的push和pop实现LIFO,适用于括号匹配;2. 链表由节点组成,插入删除高效,适合频繁修改场景;3. 字典用对象实现键值对存储,常用于频率统计;4. 二分查找在有序数组中以O(log n)效率查找目标值,需数组已排序。掌握这…

    2026年5月10日
    000
  • C++的atomic是什么_C++11使用std::atomic实现无锁编程的基础

    std::atomic是C++11提供的模板类,用于封装变量并保证其操作的原子性,如int、bool、指针等类型;通过load、store、fetch_add等操作实现线程安全的共享变量访问,避免数据竞争和锁带来的性能开销;常用于无锁编程场景,如计数器累加,提升并发效率。 在C++11中,std::…

    2026年5月10日
    000
  • PHP递归实现图遍历_PHP通过递归算法遍历图形结构的实现思路

    深度优先遍历通过递归探索节点,需标记已访问节点防环;可扩展路径记录用于搜索,或多次递归检测连通分量,适用于复杂图结构处理。 在处理图形结构时,若需要访问每个节点且图中存在复杂的连接关系,递归是一种自然且高效的解决方案。由于图可能存在环路,必须通过标记已访问节点的方式来避免无限循环。以下是几种使用PH…

    2026年5月10日
    000
  • 使用 CSS 实现图片悬停文字提示

    使用 CSS 实现图片悬停文字提示使用 CSS 实现图片悬停文字提示使用 CSS 实现图片悬停文字提示使用 CSS 实现图片悬停文字提示

    本教程详细介绍了如何使用 html 的 ` ` 和 “ 元素结合 css 实现图片悬停显示文本的交互效果。通过巧妙运用 css 动画和变换属性,当用户鼠标悬停在图片上时,图片会缩小、模糊,同时预设的文本内容平滑地淡入显示,从而提升用户界面的动态性和信息提示的友好性。 引言:图片悬停效果的重要性 在…

    2026年5月10日 用户投稿
    200
  • 解决cuDF与Numba在Docker环境中的NVVM缺失错误

    本文旨在解决在docker容器中使用cudf时,由于numba依赖cuda工具包中的nvvm组件缺失而导致的`filenotfounderror`。核心问题在于选择了精简的cuda `runtime`镜像,该镜像不包含numba进行jit编译所需的开发工具。解决方案是切换到包含完整开发工具的cuda…

    2026年5月10日
    000
  • PHP递归和迭代哪个快_PHP递归与迭代执行效率对比评测

    递归因函数调用开销大、内存消耗高,在PHP中执行效率通常低于迭代;以斐波那契数列为例,朴素递归时间复杂度达O(2^n),迭代为O(n),带缓存的递归可优化至O(n)但仍慢于迭代;通过microtime和memory_get_usage对比测试可验证该结论;启用OPcache等环境优化可提升整体性能,…

    2026年5月10日
    000
  • webstorm怎么运行调试html_webstorm调试运行html方法【教程】

    WebStorm通过内置服务器和浏览器配合实现HTML预览与调试。1. 右键HTML文件选择Open in Browser,自动启动本地服务器并预览;2. 启用Live Edit功能需安装JetBrains插件,点击Debug图标实现实时编辑更新;3. 在JS代码行设断点,通过Debug模式运行可暂…

    2026年5月10日
    000
  • 如何利用JavaScript的垃圾回收机制优化应用的内存使用?

    JavaScript垃圾回收基于可达性判断,通过根对象追踪引用链,不可达对象被自动清理。开发者应避免内存泄漏:及时解绑事件监听器、清除定时器、减少全局变量使用,并合理使用WeakMap和WeakSet等弱引用结构,以降低内存负担,提升性能。 JavaScript 的垃圾回收机制基于自动内存管理,开发…

    2026年5月10日
    100
  • Go与.NET互操作:在Go应用中调用.NET库的策略

    本文探讨了在go应用中集成.net库或ui的策略。核心方法是通过在go进程中宿主.net clr,利用c-callable dll作为桥梁。文章将介绍这种技术的可行性,并讨论实现过程中可能遇到的技术细节和注意事项,帮助开发者实现go与.net之间的互操作性。 引言 在现代软件开发中,跨语言互操作性是…

    2026年5月10日
    000
  • 解决Python 3.11环境下Motor库异步协程导入错误的指南

    本文旨在解决在Python 3.11环境中使用Motor库时遇到的`ImportError: cannot import name ‘coroutine’ from ‘asyncio’`错误。该问题通常源于Motor库版本过旧,未能适配Python 3…

    2026年5月10日
    000
  • c++中的RAII是什么意思_c++ RAII使用方法

    RAII的核心是将资源生命周期绑定到对象生命周期上,通过构造函数获取资源、析构函数释放资源,确保异常安全和自动管理。例如,使用std::make_unique避免内存泄漏,std::ifstream自动关闭文件,std::lock_guard防止死锁,还可自定义RAII类如FileHandle封装C…

    2026年5月10日
    000
  • c++中new和delete怎么用_c++动态内存分配方法

    new用于动态分配内存,delete用于释放;可分配单变量、数组并初始化,需手动管理避免泄漏。 在C++中,new 和 delete 是用于动态内存分配和释放的关键字。它们允许程序在运行时从堆(heap)上申请和释放内存,相比栈上的静态或自动变量,提供了更大的灵活性。 1. new 的基本用法 使用…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信