【计算机图形学】图形变换(平移变换、比例变换、旋转变换、对称变换、错切变换、复合变换)

news2024/10/6 8:32:22

一 实验目的

  1. 编写图形各种变换的算法

二 实验内容

1:自行设计基本图案,完成1-5种简单变换

实验结果如下图所示:
图形初始化:

 


第一次点击左键,实现平移变换:

 

 

 
第二次点击左键,实现比例变换(同时伴有平移变换):

 

 
第三次点击左键,实现对称变换(以平行y轴方向的直线为对称轴):

 

 
第四次点击左键,实现对称变换(以平行x轴方向的直线为对称轴):

 


第五次点击左键,实现错切变换(沿x轴方向关于y错切):

 


第六次点击左键,实现错切变换(沿y轴方向关于x错切):

 

 

2:在实验题3-1的基础上实现多步复合变换,设计动画效果

代码来源:https://blog.csdn.net/weixin_42815846/article/details/113099023

实验结果如下图所示:
初始化界面:

 按任意键后出现动画效果:

 

 

三 程序说明

最终的实验代码如下表所示:

1

//

// 程序名称:实验3-1

// 功    能:实现预设图像的平移变换、比例变换等变换

// 编译环境:VS2019,EasyX_20220116

// 最后修改:2022-4-5

#include <graphics.h>

#include <conio.h>

#include <iostream>

#include <math.h>

using namespace std;

#define pi 3.1415926535

int main() {

    POINT t1[] = { {200,200} , {200,20} , {220,80} };

    POINT t2[] = { {200,200} , {200,20} , {180,80} };

    int len = 3;

    float Tx = 50, Ty = 50;//平移

    float Sx = 0.5, Sy = 0.5;//比例

    float angle = 45 * pi / 180;//旋转,没做出来QwQ

    float C = 0.5, B = -0.5;//错切

    //initialize graph

    initgraph(640, 480);

    //勾画初始图案

    setfillcolor(RED);

    fillpolygon(t1, 3);

    polygon(t2, 3);

    //record the times of changing

    int times = 0;

    ExMessage m;

    //全是单步变换。

    while (1) {

         m = getmessage(EX_MOUSE | EX_KEY);

         float cur1x[3], cur1y[3], cur2x[3], cur2y[3];

         //平移

         if (m.message == WM_LBUTTONDOWN && times == 0) {

             for (int i = 0; i < len; i++) {

                  t1[i].x += Tx;

                  t1[i].y += Ty;

                  t2[i].x += Tx;

                  t2[i].y += Ty;

             }

             setfillcolor(RED);

             fillpolygon(t1, 3);

             polygon(t2, 3);

             times++;

         }

         //比例

         else if (m.message == WM_LBUTTONDOWN && times == 1) {

             for (int i = 0; i < len; i++) {

                  t1[i].x += 50;

                  t2[i].x += 50;

             }

             //以一顶点为缩放点

             for (int i = 1; i < len; i++) {

                  t1[i].x = Sx * (t1[i].x - t1[0].x) + t1[0].x;

                  t2[i].x = Sx * (t2[i].x - t2[0].x) + t2[0].x;

                  t1[i].y = Sy * (t1[i].y - t1[0].y) + t1[0].y;

                  t2[i].y = Sy * (t2[i].y - t2[0].y) + t2[0].y;

             }

             setfillcolor(RED);

             fillpolygon(t1, 3);

             polygon(t2, 3);

             times++;

         }

         //对称 about x axis

         else if (m.message == WM_LBUTTONDOWN && times == 2) {

             float mid = t1[0].y;

             for (int i = 0; i < len; i++) {

                  t1[i].y = 2 * mid - t1[i].y;

                  t2[i].y = 2 * mid - t2[i].y;

             }

             setfillcolor(RED);

             fillpolygon(t1, 3);

             polygon(t2, 3);

             times++;

         }

         //对称 about y axis

         else if (m.message == WM_LBUTTONDOWN && times == 3) {

             float midx = t1[2].x;

             for (int i = 0; i < len; i++) {

                  t1[i].x = 2 * midx - t1[i].x;

                  t2[i].x = 2 * midx - t2[i].x;

                  //float cur1x[3], cur1y[3], cur2x[3], cur2y[3];

                  cur1x[i] = t1[i].x;

                  cur1y[i] = t1[i].y;

                  cur2x[i] = t2[i].x;

                  cur2y[i] = t2[i].y;

             }

             setfillcolor(RED);

             fillpolygon(t1, 3);

             polygon(t2, 3);

             times++;

         }

         //错切 沿x轴方向关于y错切(x = x + cy)

         else if (m.message == WM_LBUTTONDOWN && times == 4) {

             for (int i = 0; i < len; i++) {

                  t1[i].x += C * t1[i].y;

                  t2[i].x += C * t2[i].y;

             }

             setfillcolor(RED);

             fillpolygon(t1, 3);

             polygon(t2, 3);

             times++;

         }

         //错切 沿y轴方向关于x错切(y = y + bx)

         else if (m.message == WM_LBUTTONDOWN && times == 5) {

             for (int i = 0; i < len; i++) {

                  /*

                  //float cur1x[3], cur1y[3], cur2x[3], cur2y[3];

                  cur1x[i] = t1[i].x;

                  cur1y[i] = t1[i].y;

                  cur2x[i] = t2[i].x;

                  cur2y[i] = t2[i].y;

                  */

                  //t1[i].y += B * t1[i].x;

                  //t2[i].y += B * t2[i].x;

                  t1[i].y = cur1y[i] + B * cur1x[i];

                  t1[i].x = cur1x[i];

                  t2[i].y = cur2y[i] + B * cur2x[i];

                  t2[i].x = cur2x[i];

             }

             setfillcolor(RED);

             fillpolygon(t1, 3);

             polygon(t2, 3);

             times++;

         }

    }

    _getch();

    closegraph();

    return 0;

}

2

//

// 程序名称:实验3-2

// 功    能:实现预设图像的复合变换

// 编译环境:VS2019,EasyX_20220116

// 最后修改:2022-4-5

#include <graphics.h>

#include <conio.h>

#include <iostream>

#include <math.h>

#include <malloc.h>

#include <stdio.h>

using namespace std;

#define PI 3.1415926535

int dimension = 3, num = 4;

double points[50][2] = { {150,150},{150,200},{200,200},{200,150} };

//初始化

void initialize() {

    initgraph(800, 640);

    setbkcolor(WHITE);

    setcolor(WHITE);

    fillrectangle(0, 0, 800, 640);

    setcolor(BLACK);

    line(0, 80, 800, 80);

    setcolor(BLACK);

    line(0, 80, 800, 80);

    //说明框矩形

    RECT r = { 0,0,800,80 };

    drawtext(_T("\n\n依次展示旋转,放大,平移,关于直线对称,关于x错切"), &r, DT_CENTER | DT_VCENTER);

    HRGN rgn = CreateRectRgn(1, 81, 799, 639);

    setcliprgn(rgn);

   

    setcolor(BLACK);

    rectangle(0, 0, 800, 640);

    setcolor(RED);

}

//矩阵乘法

void multiply(double a[5][5], int ar, int ac, double b[5][5], int br, int bc) {

    if (ac != br) {

         cout << "matrix invalid";

         return;

    }

    double c[5][5];

    for (int i = 0; i < ar; i++) {

         for (int j = 0; j < bc; j++) {

             c[i][j] = 0;

         }

    }

    for (int i = 0; i < ar; i++) {

         for (int j = 0; j < bc; j++) {

             for (int k = 0; k < ac; k++) {

                  c[i][j] += a[i][k] * b[k][j];

             }

         }

    }

    for (int i = 0; i < ar; i++) {

         for (int j = 0; j < bc; j++) {

             b[i][j] = c[i][j];

         }

    }

}

//平移变换

void trans(double tx, double ty) {

    double T[5][5] = { {1,0,tx},{0,1,ty},{0,0,1} };

    double point[5][5];

    for (int i = 0; i < num; i++) {

         point[0][0] = points[i][0];

         point[1][0] = points[i][1];

         point[2][0] = 1;

         multiply(T, dimension, dimension, point, dimension, 1);

         points[i][0] = point[0][0];

         points[i][1] = point[1][0];

    }

}

//旋转变换

void rotate(double degree) {

    double theta = degree / 180 * PI;

    double R[5][5] = { {cos(theta),-sin(theta),0},{sin(theta),cos(theta),0},{0,0,1} };

    double point[5][5];

    for (int i = 0; i < num; i++) {

         point[0][0] = points[i][0];

         point[1][0] = points[i][1];

         point[2][0] = 1;

         multiply(R, dimension, dimension, point, dimension, 1);

         points[i][0] = point[0][0];

         points[i][1] = point[1][0];

    }

}

//缩放变换

void scale(double sx, double sy) {

    double S[5][5] = { {sx,0,0},{0,sy,0},{0,0,1} };

    double point[5][5];

    for (int i = 0; i < num; i++) {

         point[0][0] = points[i][0];

         point[1][0] = points[i][1];

         point[2][0] = 1;

         multiply(S, dimension, dimension, point, dimension, 1);

         points[i][0] = point[0][0];

         points[i][1] = point[1][0];

    }

}

//对称变换

void symmetry(int flag) {

    if (flag == 0) {

         for (int i = 0; i < num; i++) {

             points[i][1] = -points[i][1];

         }

    }

    else if (flag == 1) {

         for (int i = 0; i < num; i++) {

             points[i][0] = -points[i][0];

         }

    }

    else {

         return;

    }

}

void anysymmetry(int x1, int y1, int x2, int y2) {

    double k = 0, b = 0;

    if (x1 == x2) {

         trans(-x1, 0);

         symmetry(1);

         trans(x1, 0);

    }

    else if (y1 == y2) {

         trans(0, -y1);

         symmetry(0);

         trans(0, y1);

    }

    else {

         k = double((y1 - y2) / (x1 - x2));

         b = y1 - k * x1;

         trans(0, -b);

         rotate(-atan(k) * 180 * 1.0 / PI);

         symmetry(0);

         rotate(atan(k) * 180 * 1.0 / PI);

         trans(0, b);

    }

}

//输出图形

void paint() {

    for (int i = 0; i < num; i++) {

         if (i == num - 1) {

             line(points[i][0], points[i][1], points[0][0], points[0][1]);

             break;

         }

         line(points[i][0], points[i][1], points[i + 1][0], points[i + 1][1]);

    }

}

//错切变换

void cut(int flag, int degree) {

    double point[5][5];

    if (flag == 0) {

         double C[5][5] = { {1,0,0},{tan(double(degree) / 180 * PI),1,0},{0,0,1} };

         for (int i = 0; i < num; i++) {

             point[0][0] = points[i][0];

             point[1][0] = points[i][1];

             point[2][0] = 1;

             multiply(C, dimension, dimension, point, dimension, 1);

             points[i][0] = point[0][0];

             points[i][1] = point[1][0];

         }

    }

    else if (flag == 1) {

         double C[5][5] = { {1,tan(double(degree) / 180 * PI),0},{0,1,0},{0,0,1} };

         for (int i = 0; i < num; i++) {

             point[0][0] = points[i][0];

             point[1][0] = points[i][1];

             point[2][0] = 1;

             multiply(C, dimension, dimension, point, dimension, 1);

             points[i][0] = point[0][0];

             points[i][1] = point[1][0];

         }

    }

    else if (flag == 2) {

         double C[5][5] = { {1,tan(double(degree) / 180 * PI),0},{tan(double(degree) / 180 * PI),1,0},{0,0,1} };

         for (int i = 0; i < num; i++) {

             point[0][0] = points[i][0];

             point[1][0] = points[i][1];

             point[2][0] = 1;

             multiply(C, dimension, dimension, point, dimension, 1);

             points[i][0] = point[0][0];

             points[i][1] = point[1][0];

         }

    }

    else {

         return;

    }

}

//复合变换

void multitrans() {

    paint();

    int i = 50;

    while (i > 0) {

         i--;

         Sleep(50);

         clearcliprgn();

         trans(-150, -150);

         rotate(-20);

         trans(150, 150);

         paint();

    }

    i = 8;

    while (i > 0) {

         i--;

         Sleep(250);

         scale(1.1, 1.1);

         clearcliprgn();

         paint();

    }

    i = 40;

    while (i > 0) {

         i--;

         Sleep(50);

         trans(-1, -1);

         clearcliprgn();

         paint();

    }

    i = 4;

    while (i > 0) {

         i--;

         Sleep(250);

         anysymmetry(250, 100, 300, 560);

         clearcliprgn();

         setcolor(BLACK);

         line(250, 100, 300, 560);

         setcolor(RED);

         paint();

    }

    i = 20;

    while (i > 0) {

         i--;

         Sleep(150);

         cut(0, 1);

         clearcliprgn();

         paint();

    }

}

//主函数

int main() {

    initialize();

    _getch();

    multitrans();

    _getch();

    closegraph();

    return 0;

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 性能优化——APP启动优化详解

1.1 为什么要启动优化&#xff1f; 用户希望应用能够及时响应并快速加载&#xff0c;启动时间过长的应用不能满足这个期望&#xff0c;并且可能使用户失望。 启动太慢的结果&#xff1a; 体验效果差用户放弃使用你的应用时间越长用户流失越高产品死掉 1.2 启动优化流程及分…

HDLBits-Modules 题解【Verilog模块例化】(中文翻译+英文原文,可顺带学习英文)

Moudule 概念介绍 到目前为止&#xff0c;你已经熟悉了一个模块&#xff0c;它是一个通过输入和输出端口与其外部交互的电路。更大、更复杂的电路是通过将较小的模块和其他连接在一起的部分&#xff08;例如赋值语句和always块&#xff09;组合而成的更大模块来构建的。因为模…

从零开始学OpenCV——图像灰度变换详解(线性与非线性变换)

文章目录图像灰度变化灰度变换介绍灰度线性变换灰度分段线性变换图像点运算灰度非线性变换线性点运算灰度的非线性变换&#xff1a;对数变换灰度的非线性变换&#xff1a;伽马变换灰度的非线性变换&#xff1a;对比拉伸灰度的非线性变换&#xff1a; S形灰度变换灰度的非线性变…

tomcat中出现RFC7230和RFC3986问题解析

问题截图 问题分析 出现上述问题&#xff0c;是因为各版本tomcat中对特殊字符和请求路径中携带中文参数而产生的错误提示。 解决办法 1、调整tomcat版本 tomcat 7.0.76之前的版本不会出现类似问题 2、tomcat9之前&#xff0c;修改tomcat目录底下的/conf/catalina.properti…

233:vue+openlayers绘制渐变填充色的圆形、多边形

第233个 点击查看专栏目录 本示例的目的是介绍如何在vue+openlayer中绘制带有渐变填充色的圆形、多边形。这里用canvas的方式去渲染,用到了DEVICE_PIXEL_RATIO,设备上的物理像素与设备无关像素 (dips) 之间的比率 (window.devicePixelRatio)。 直接复制下面的 vue+openlayer…

用ChatGPT创建一个REST API

ChatGPT是OpenAI公司开发的大型语言模型。在本文中&#xff0c;主要探讨如何使用ChatGPT在C#中创建REST API。 一、简介 ChatGPT是由人工智能研究中心OpenAI创建的尖端自然语言处理模型&#xff0c;OpenAI公司是由埃隆马斯克、萨姆奥特曼和格雷格布罗克曼共同创办的。该模型于…

360浏览器+Adobe Acrobat DC实现在线预览PDF大样校对

甲方&#xff1a;实现方正PDF文字大样校对&#xff0c;校对后在360浏览器中新开一个页面在线预览PDF文字大样校对结果。 我方实现过程&#xff1a; 1.方案选择 方案零&#xff1a;使用浏览器自带的PDF阅览器&#xff0c;经测试360极速模型,谷歌等软件能预览但是标记的PDF内容…

【笔记】大模型,大资料

大模型&#xff0c;大资料&#xff0c;loss会降低&#xff0c;准确率会增加 1大模型 1.1模型的顿悟时刻 举了一个一知半解的例子 1.2 模型 chain of thought 模型足够大时才会有比较好的作用 calibration 检测模型对于答案的confidence 会出现 “u-shape” 2.大资料 文法…

系统复杂度之【高可用】

接着&#xff0c;我们聊聊复杂度的第二个要求高可用。 参考维基百科&#xff0c;先来看看高可用的定义。 系统无中断地执行其功能的能力&#xff0c;代表系统的可用性程度&#xff0c;是进行系统设计时的准则之一。 这个定义的关键在于“ 无中断”&#xff0c;但恰好难点也在“…

Java 并发编程面试题——Future

目录1.什么是 Future 模式&#xff1f;Java 中是如何实现的&#xff1f;2.Callable、Future 与 FutureTask 分别是什么&#xff1f;2.1.Callable 接口2.2.Future 接口2.3.FutureTask 类3.CompletableFuture 类有什么用&#xff1f;1.什么是 Future 模式&#xff1f;Java 中是如…

windows系统管理_Windows server 2016 组管理与授权

组账户的概述 在 windows 服务器中&#xff0c;当我们需要为多个用户设置相同的权限时&#xff0c;一个一个的逐一设置会比较 麻烦&#xff0c;这个时候我们就需要用到另一种模式&#xff0c;组账户&#xff0c;使用此账户来进行简化操作。 在以后的职场中&#xff0c;每家公司…

Flink 优化 (五) --------- Job 优化

目录一、使用 DataGen 造数据1. DataStream 的 DataGenerator2. SQL 的 DataGenerator二、算子指定 UUID三、链路延迟测量四、开启对象重用五、细粒度滑动窗口优化一、使用 DataGen 造数据 开发完 Flink 作业&#xff0c;压测的方式很简单&#xff0c;先在 kafka 中积压数据&a…

全景图像畸变校正

1.简介 理想的相机基本上是小孔成像的&#xff0c;在小孔成像模型中&#xff0c;如果焦距一定&#xff0c;那么图像传感器像素平面的面积直接决定了相机视场角的大小&#xff0c;超过这个视场角范围的物体不会被镜头获取到。因此基于透镜成像原理的相机&#xff0c;视场角无法…

JAVA解析XML时的内存消耗问题

问题出现 最近一个项目中&#xff0c;有个需求功能是从外部传入的XML读取数据&#xff0c;然后写入到数据库中。 写完之后&#xff0c;有在本地电脑上的Tomcat跑了一下&#xff0c;正常读取到XML中的数据&#xff0c;并整理好后&#xff0c;插入了数据库保存了。但是线上运行的…

C语言文件操作复习回顾(2)

TIPS 文件的顺序读写&#xff1a;fgetc, fputc, fputs&#xff08;一行字符串的输出\n注意一下&#xff09;, fgets&#xff08;一行字符串的输入\n三特性&#xff09;&#xff0c;fprintf&#xff08;格式化字符串的输出联想printf很简单&#xff09;&#xff0c;fscanf&…

pyspark 实验二,rdd编程

1.环境准备 start-all.sh启动Hadoop ./bin start-all.sh 启动spark 上传数据集 1.求该系总共多少学生 linessc.textFile("file:///home/data.txt") res lines.map(lambda x:x.split(",")).map(lambda x:x[0]) sumres.distinct() sum.cont() 2.求该系设置…

【MybatisPlus快速入门】—— 进阶入门

进阶篇 1.1 映射专题 Mybatis 框架之所以能够简化数据库操作&#xff0c;是因为他内部的映射机制&#xff0c;通过自动映射&#xff0c;进行数据的封装&#xff0c;我们只要符合映射规则&#xff0c;就可以快速高效的完成SQL操作的实现既然 MybatisPlus 是基于Mybatis 的增强…

程序员如何能提高自己的编程水平?

这些实用的小建议&#xff0c;能帮你迅速地提高编程水平&#xff1a; 不要做无意义的奋斗 拒绝喊口号和无意义的奋斗&#xff0c;包括但不限于&#xff1a; ①做了计划表却从未有执行的一天&#xff1b; ②每天都是最早来、最晚走&#xff0c;但是工作进度趋近于0&#xff1b…

ASP.NET Core MVC 从入门到精通之接化发(一)

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…

PathCore:IAD文献解读

论文链接&#xff1a;[Towards Total Recall in Industrial Anomaly Detection]Towards Total Recall in Industrial Anomaly Detection &#xff1a;数据集&#xff0c; &#xff1a;标签 : 在ImageNet上预训练后的网络 第 张图 网络中第 层 1. Locall…