讲师中心 微信公众号
AI工具推荐 视频效率加速

Processing中实现图形的精确旋转与拖动:基于坐标变换的教程

小丽君_2945

小丽君_2945

发布时间:2025-11-17 13:41:02

|

855人浏览过

|

来源于php中文网

原创

processing中实现图形的精确旋转与拖动:基于坐标变换的教程

本教程旨在解决Processing中图形旋转和拖动时出现偏移的问题。我们将深入探讨Processing的二维坐标变换原理,包括`translate()`、`rotate()`以及`pushMatrix()`和`popMatrix()`的协同应用。通过将图形定义为相对坐标并利用独立的变换上下文,你将学会如何实现复杂场景中多个对象在鼠标输入下进行独立、精确的旋转与平移,确保图形保持在屏幕上的预期位置。

理解Processing中的坐标系统与变换

在Processing中,所有绘图操作都基于一个二维坐标系统。默认情况下,画布的左上角是(0,0)点。当直接使用triangle(1000,600,...)这样的绝对坐标绘制图形时,图形的位置是固定的。直接应用rotate()或translate()函数而不理解其作用机制,很容易导致图形“飞出”屏幕。

1. 绝对坐标的局限性

当你使用triangle(x1, y1, x2, y2, x3, y3)这样的方式定义图形时,这些(x,y)值是相对于画布原点(0,0)的绝对位置。如果你随后调用rotate(),Processing会围绕当前的坐标原点(默认为(0,0))旋转整个坐标系。由于你的图形离(0,0)很远,它会围绕一个遥远的轴心旋转,看起来就像是飞走了。

2. translate() 平移变换

translate(x, y)函数的作用是将整个坐标系统原点从(0,0)移动到新的(x, y)位置。这意味着之后所有的绘图操作都将以这个新的原点为参照。这是实现图形拖动的基础。

我们可以结合mouseDragged()事件来动态更新平移量:

float currentX = 0;
float currentY = 0;

void setup(){
  size (800, 600);
}

void draw() {
  background (0);

  // 将坐标原点移动到 (currentX, currentY)
  translate(currentX, currentY); 

  // 在新的坐标系中绘制一个矩形,它的左上角将位于 (currentX, currentY)
  fill(255, 0, 0);
  rect(0, 0, 100, 100); 
}

// 当鼠标被拖动时调用
void mouseDragged(){
  // 更新平移量,使图形中心跟随鼠标
  // 如果图形的中心是(0,0),直接使用mouseX, mouseY即可
  currentX = mouseX; 
  currentY = mouseY;
}

在上述代码中,rect(0,0,100,100)实际上被绘制在画布的(currentX, currentY)位置。

实现独立对象的旋转

要让图形围绕其自身中心旋转,而不是画布原点,我们需要做两件事:

  1. 将图形的中心点移动到坐标原点(0,0)。
  2. 使用pushMatrix()和popMatrix()隔离变换。

1. rotate() 旋转变换

rotate(angle)函数会围绕当前的坐标原点旋转整个坐标系。angle参数通常以弧度表示。如果想让图形围绕自身中心旋转,就必须先将坐标原点移动到图形的中心。

2. pushMatrix() 和 popMatrix() 的重要性

当你在Processing中应用translate()、rotate()或scale()等变换时,这些变换会影响之后所有的绘图操作。如果想让不同的图形拥有独立的变换,就需要使用pushMatrix()和popMatrix()。

  • pushMatrix():保存当前坐标系统的状态(包括原点位置、旋转角度、缩放比例)。
  • popMatrix():恢复到最近一次pushMatrix()保存的状态。

通过将一组绘图操作封装在pushMatrix()和popMatrix()之间,可以确保这些操作的变换只影响其内部的图形,而不会干扰其他图形或全局坐标系统。

3. 相对坐标的优势

为了让旋转变得简单直观,强烈建议将图形的顶点坐标定义为相对于其自身中心点(0,0)的坐标。例如,一个中心在(0,0)的正方形,其顶点可以是(-50, -50), (50, -50), (50, 50), (-50, 50)。这样,当你translate()到它的目标位置后再rotate(),它就会围绕其自身中心旋转。

综合示例:鼠标拖动与独立旋转的星星

现在,我们将结合上述概念,创建一个可以整体拖动,并包含两个独立旋转的星形图案的Processing草图。一个星形顺时针旋转,另一个逆时针旋转。

float globalTranslateX = 0; // 全局平移的X坐标
float globalTranslateY = 0; // 全局平移的Y坐标

void setup(){
  size (1800, 1000); // 设置画布大小
  // 初始时将全局平移量设置为画布中心,使图形在屏幕中央
  globalTranslateX = width / 2; 
  globalTranslateY = height / 2;
}

void draw() {
  background (0); // 清空背景

  // 1. 应用全局平移:根据鼠标拖动来移动整个场景
  translate(globalTranslateX, globalTranslateY);

  // 2. 绘制第一个星形图案 (顺时针旋转)
  pushMatrix(); // 保存当前坐标系统状态
    // 应用旋转:frameCount是一个内置变量,每帧递增,用于实现连续动画
    // 0.01是旋转速度,正值表示顺时针
    rotate(frameCount * 0.01); 

    // 绘制第一个星形(由多个三角形组成),所有坐标都相对于(0,0)
    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()之前的坐标系统状态

  // 3. 绘制第二个星形图案 (逆时针旋转)
  pushMatrix(); // 再次保存当前坐标系统状态
    // 应用旋转:负值表示逆时针
    rotate(frameCount * -0.01); 

    // 绘制第二个星形,所有坐标同样相对于(0,0)
    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()之前的坐标系统状态

  // 4. 绘制中心圆,它会随着全局平移而移动,但不会旋转
  fill(0,0,0);
  // 注意这里circle的坐标是(0,0),因为它将在当前的坐标原点绘制
  circle(0, 0, 425); 
}

// 鼠标拖动事件处理函数
void mouseDragged(){
  // 更新全局平移量,使画布的(0,0)点跟随鼠标位置
  // 因为我们的星形图案都是围绕(0,0)绘制的,所以这样可以拖动星形的中心
  globalTranslateX = mouseX;
  globalTranslateY = mouseY;
}

// Processing中没有内置的circle函数,这里提供一个辅助函数
// 它使用ellipse来绘制一个正圆
void circle(float x, float y, float r){
  ellipse(x, y, r, r);
}

代码解释:

  • globalTranslateX, globalTranslateY: 这两个变量存储了整个场景的平移量。在draw()函数开始时,translate(globalTranslateX, globalTranslateY)将画布的逻辑原点移动到这个位置,使得所有后续绘制的图形都相对于这个新原点。
  • setup(): 初始化globalTranslateX和globalTranslateY为画布中心,这样程序启动时星星会显示在屏幕中央。
  • pushMatrix() / popMatrix(): 每一组星形图案的绘制都被封装在这两个函数之间。这意味着rotate()函数只影响当前pushMatrix()和popMatrix()之间的代码,实现了星形的独立旋转。
  • *`rotate(frameCount 0.01)**:frameCount`是Processing内置的变量,表示程序运行至今的帧数。通过乘以一个小数,可以使星形每帧旋转一个微小角度,从而产生连续动画效果。正负号控制旋转方向。
  • 相对坐标: 所有的triangle()顶点坐标都经过了调整,使其中心位于(0,0)。这样,当rotate()函数被调用时,星形会围绕其自身的中心点旋转,而不是画布的某个固定点。
  • mouseDragged(): 当鼠标被拖动时,globalTranslateX和globalTranslateY会更新为当前的鼠标位置。由于星形是围绕(0,0)绘制的,并且translate(globalTranslateX, globalTranslateY)将(0,0)移动到鼠标位置,所以星形会跟随鼠标移动。

注意事项与最佳实践

  • 变换的顺序至关重要: 通常的变换顺序是:translate() -> rotate() -> scale()。改变这个顺序会得到不同的结果。例如,先旋转再平移,与先平移再旋转,效果是不同的。
  • 始终使用pushMatrix()/popMatrix(): 这是管理复杂场景中多个独立对象变换的关键。如果没有它们,所有的变换会累积,导致难以预测的结果。
  • 以(0,0)为中心设计图形: 在构建可旋转或可缩放的图形时,最好将它们的几何中心设计在(0,0)点。这样,rotate()和scale()操作会非常直观。如果图形的中心不在(0,0),你需要先translate()到它的中心,再进行旋转/缩放,最后再translate()回原来的位置,或者直接使用rotate(angle, centerX, centerY)(某些库或高级功能可能支持)。
  • 弧度与角度: Processing的rotate()函数默认接受弧度值。如果你习惯使用角度,可以使用radians()函数将角度转换为弧度,例如rotate(radians(45))。

总结

通过本教程,你已经掌握了Processing中二维坐标变换的核心概念。理解translate()、rotate()以及pushMatrix()和popMatrix()的协同作用,并结合相对坐标的绘图策略,你现在能够创建出在鼠标控制下进行精确平移和独立旋转的动态图形。这些技能是构建更复杂交互式Processing应用的基础。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

80

2026.10.22

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

40

2026.10.22

Golangci-lint检查器使用教程
Golangci-lint检查器使用教程

本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。

40

2026.10.22

Gradle怎么构建Java项目
Gradle怎么构建Java项目

本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。

20

2026.10.22

PHP时间戳漏洞修复教程
PHP时间戳漏洞修复教程

本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。

40

2026.10.22

Golangci-lint配置文件与规则设置
Golangci-lint配置文件与规则设置

本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。

20

2026.10.22

Golangci-lint安装与入门教程
Golangci-lint安装与入门教程

本专题讲解Golangci-lint的安装、初始化、基础命令和首次代码检查,覆盖本地环境、Docker及多平台用法,帮助Go开发者快速上手。

40

2026.10.22

PHP2Shell高危漏洞修复教程
PHP2Shell高危漏洞修复教程

PHP2Shell漏洞是什么,哪些PHP版本和运行环境会受到影响,服务器应该如何检测与修复?本专题提供版本自查脚本、Linux与Docker升级命令、PHP-FPM和Apache排查步骤,以及修复验证、临时缓解和应急响应方案。

240

2026.10.22

剧云人物设定与关系管理教程
剧云人物设定与关系管理教程

本专题介绍剧云人物设定与关系管理,讲解角色小传、性格职业、人物目标、背景资料和关系网络的创建及维护方法。

20

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn