当前位置: 首页 > news >正文

计算机图形学07:有效边表法的多边形扫描转换

在这里插入图片描述

作者:非妃是公主
专栏:《计算机图形学》
博客地址:https://blog.csdn.net/myf_666
个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩
在这里插入图片描述

文章目录

  • 专栏推荐
  • 专栏系列文章
  • 一、算法原理
  • 二、OpenGL代码实现
  • 三、效果展示
  • the end……

专栏推荐

专栏名称专栏地址
软件工程专栏——软件工程
计算机图形学 专栏——计算机图形学
操作系统专栏——操作系统
软件测试专栏——软件测试
机器学习专栏——机器学习
数据库专栏——数据库
算法专栏——算法

专栏系列文章

文章名称文章地址
直线生成算法(DDA算法)计算机图形学01——DDA算法
中点BH算法绘制直线计算机图形学02——中点BH算法
改进的中点BH算法计算机图形学03——改进的中点BH算法
中点Bresenham画椭圆计算机图形学04——中点BH绘制椭圆
中点BH算法绘制任意斜率直线计算机图形学05——中点BH算法绘制任意斜率的直线
中点Bresenham画圆计算机图形学06——中点BH算法画圆
有效边表法的多边形扫描转换计算机图形学07——有效边表法绘制填充多边形
中点BH算法绘制抛物线 100x=y2100x = y^2100x=y2计算机图形学08——中点BH绘制抛物线
二维观察之点的裁剪计算机图形学09——二维观察之点裁剪
二维观察之线的裁剪计算机图形学10——二维观察之线裁剪
二维观察之多边形的裁剪计算机图形学11——二维观察之多边形裁剪
二维图形的几何变换计算机图形学12——二维图形几何变换
三维图形的几何变换计算机图形学13——三维图形几何变换
三维图形的投影变换计算机图形学14——三维图形投影变换

计算机图形学(英语:computer graphics,缩写为CG)是研究计算机在硬件和软件的帮助下创建计算机图形的科学学科,是计算机科学的一个分支领域,主要关注数字合成与操作视觉的图形内容。虽然这个词通常被认为是指三维图形,事实上同时包括了二维图形以及影像处理。


一、算法原理

有效边表法是X射线扫描转换的一种改进实现方式,相比于X射线方法,有效边表法由于不需要判断虚实交点,整体效率更高。

通过构造边表,然后随着X射线的移动不断地维护有效边表,通过两两配对边表中的有效边点亮像素,实现多边形的绘制。

具体原理如下:

在这里插入图片描述

在这里插入图片描述

排序方式按照x_ymin(y取到最小值的时候,x值的大小)排,x_ymin相等时按照1k\frac{1}{k}k1大小排,稍加思考会发现,正常情况下,不会出现相等情况。

在这里插入图片描述

在这里插入图片描述

由于配对原则,在顶点相交处,会影响到配对,采用的做法是,在影响配对的情况下进行ymax=ymax−1ymax=ymax-1ymax=ymax1处理,通过此来保证在进行有效边交替的时候不会出现错误(即保证有效边表中的有效边数量为偶数)。

在这里插入图片描述

算法流程(本人在实现的时候,为编码符合自己的逻辑方式,先增加节点、再填充像素、填充后即检查是否需要删除如需要删除、最后进行各个有效边x_ymin属性的+1k+\frac{1}{k}+k1):

在这里插入图片描述


二、OpenGL代码实现

OpenGL代码实现如下:

// 有效边表法(AET)绘制填充多边形
void AETPolygon(vector<Point> pnts) {vector<Point>::iterator min_iter = min_element(pnts.begin(), pnts.end());vector<Point>::iterator max_iter = max_element(pnts.begin(), pnts.end());int min_y = min_iter->y;int max_y = max_iter->y;int dist = max_y - min_y + 1;vector<ETNode*> ET;		// 边表for (int i = 0; i < dist; i++) {ET.push_back(new ETNode(0, 0, 0));}for (int i = 0; i < pnts.size(); i++) { // 建立边表// 建立边表节点的属性值double x_ymin, y_max, rev_k;if (pnts[i].y > pnts[(i + 1) % pnts.size()].y) {	// 找出y最小值对应的x值x_ymin = pnts[(i + 1) % pnts.size()].x;y_max = pnts[i].y;// 如果为一个顶点的情况,y_max--if ((pnts[(i - 1 + pnts.size()) % pnts.size()].y - pnts[i].y) * (pnts[(i + 1 + pnts.size()) % pnts.size()].y - pnts[i].y) < 0) {y_max--;}}else {x_ymin = pnts[i].x;y_max = pnts[(i + 1) % pnts.size()].y;// 如果为一个顶点的情况,y_max--if ((pnts[(i + pnts.size()) % pnts.size()].y - pnts[i + 1].y) * (pnts[(i + 2 + pnts.size()) % pnts.size()].y - pnts[i + 1].y) < 0) {y_max--;}}// 计算 1/krev_k = (double)(pnts[(i + 1) % pnts.size()].x - pnts[i].x) / (pnts[(i + 1) % pnts.size()].y - pnts[i].y);// 计算 (1/斜率)ETNode* tmp = new ETNode(x_ymin, y_max, rev_k);ETNode* tmpFirstNode = ET[x_ymin - min_y];// 寻找合适的插入位置while (tmpFirstNode->next != nullptr && *(tmpFirstNode->next) < *tmp){tmpFirstNode = tmpFirstNode->next;}// 插入tmp->next = tmpFirstNode->next;tmpFirstNode->next = tmp;}// 建立活动边表ETNode* AET = new ETNode(0, 0, 0); // AET为头节点,不储存边表节点,后续节点才储存// 从下到上进行 x 射线扫描for (int i = min_y; i < max_y; i++) {ETNode* tmp_ETNode = ET[i - min_y];ETNode* tmp_AETNode = AET;while (tmp_ETNode->next != nullptr) {tmp_AETNode = AET;// 寻找AET中的插入位置while (tmp_AETNode->next != nullptr && *(tmp_AETNode->next) < *(tmp_ETNode->next)) {tmp_AETNode = tmp_AETNode->next;}//ET[i - min_y]->next = tmp_ETNode->next->next; 将tmp->next加入到 AET中//tmp_ETNode->next->next = tmp_AETNode->next;//tmp_AETNode->next = tmp_ETNode->next;//tmp_ETNode = ET[i - min_y];// 将tmp加入到 AET 中ETNode* tmp = new ETNode(tmp_ETNode->next->x_ymin, tmp_ETNode->next->y_max, tmp_ETNode->next->rev_k);tmp->next = tmp_AETNode->next;tmp_AETNode->next = tmp;tmp_ETNode = tmp_ETNode->next;}// 添加完以后进行画点tmp_AETNode = AET;while (tmp_AETNode->next != nullptr && tmp_AETNode->next->next != nullptr) {int fillBegin = (int)(tmp_AETNode->next->x_ymin + 0.5);int fillEnd = (int)(tmp_AETNode->next->next->x_ymin + 0.5);glColor3f(0.0f, 1.0f, 0.0f);			// 设置颜色为绿色进行填充glBegin(GL_POINTS);for (int j = fillBegin; j <= fillEnd; j++) {glVertex2i(j, i);}			glEnd();// 填充之后删除y=y_max的边if (i == tmp_AETNode->next->y_max || i == tmp_AETNode->next->next->y_max) {if (i == tmp_AETNode->next->y_max && i == tmp_AETNode->next->next->y_max) { // 删两个ETNode* del = tmp_AETNode->next;tmp_AETNode->next = tmp_AETNode->next->next;delete del;del = tmp_AETNode->next;tmp_AETNode->next = tmp_AETNode->next->next;delete del;}else if(i == tmp_AETNode->next->y_max) { // 删第一个ETNode* del = tmp_AETNode->next;tmp_AETNode->next = tmp_AETNode->next->next;delete del;tmp_AETNode = tmp_AETNode->next;}else {			// 删第二个ETNode* del = tmp_AETNode->next->next;tmp_AETNode->next->next = tmp_AETNode->next->next->next;delete del;tmp_AETNode = tmp_AETNode->next;}continue;}tmp_AETNode = tmp_AETNode->next->next;}// 更新AET表中的x值tmp_AETNode = AET;while (tmp_AETNode->next != nullptr){tmp_AETNode->next->x_ymin += tmp_AETNode->next->rev_k;tmp_AETNode = tmp_AETNode->next;}}// 进行析构// 析构AETETNode* AEThead = AET;while (AEThead != nullptr) {ETNode* del = AEThead;AEThead = AEThead->next;delete del;}// 析构ETfor (int i = 0; i < ET.size(); i++) {ETNode* EThead = ET[i];while (EThead != nullptr) {ETNode* del = EThead;EThead = EThead->next;delete del;}}
}

三、效果展示

有效边表法的多边形扫描转换效果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


the end……

有效边表法的多边形扫描转换算法到这里就要结束啦~~到此既是缘分,欢迎您的点赞评论收藏关注我,不迷路,我们下期再见!!

😘😘😘 我是Cherries,一位计算机科班在校大学生,写博客用来记录自己平时的所思所想!
💞💞💞 内容繁杂,又才疏学浅,难免存在错误,欢迎各位大佬的批评指正!
👋👋👋 我们相互交流,共同进步!

:本文由非妃是公主发布于https://blog.csdn.net/myf_666,转载请务必标明原文链接:https://blog.csdn.net/myf_666/article/details/128226399

相关文章:

计算机图形学07:有效边表法的多边形扫描转换

作者&#xff1a;非妃是公主 专栏&#xff1a;《计算机图形学》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、算法原理二、…...

UNIX编程--Makefile入门

Makefile 文件命名和规则 文件命名 makefile 或者 Makefile Makefile 规则 一个 Makefile 文件中可以有一个或者多个规则目标 ... &#xff1a; 依赖 ...命令 (shell 命令)...目标&#xff1a;最终要生成的文件&#xff0c;伪目标除外依赖&#xff1a;生成目标所需的文件或是目…...

【数据结构初阶】手撕单链表

目录一.链表概念和结构二.单链表功能的实现1.打印单链表内容2.申请单链表节点3.头插和尾插4.头删和尾删5.单链表查找6.pos位置前后插入7.pos位置删除三.链表面试题剖析一.链表概念和结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素…...

angular中http请求和传值

有关angular传值的相关内容 <number-info[subTitle]"customTitle"[total]"item.ENERGY_RATE %"[subTotal]"item.ENERGY_RATE_DIFF %"[status]"item.ENERGY_RATE_DIFF > 0 ? up : down">在number-info上面,会是一个delon/c…...

VSCode问题记录

20230304 - 0. 引言 这几年的编程方式还真是各种变化&#xff0c;从一开始直接VIM&#xff0c;到后面使用jupyter进行机器学习相关&#xff0c;然后再过渡到vim的形式并加以tmux批量化&#xff0c;最后去年使用了vscode作为IDE。随着工具的变化&#xff0c;那么很多习惯也都随…...

html基础学习

初识HTML HTML: 超文本标记语言 一.HTML的基本结构 根控制标记(头) ​ 头控制标记(头) ​ 标题 标题标记 ​ 头控制标记(尾) ​ 网页显示区域(一般要实现的代码都在这里写) </body> 根控制标记(尾) 二.网页的基本标签 标题标签 <h1> 一级标题</h1> <…...

leetcode_贪心算法

贪心算法相关题简单题目455.分发饼干1005.K次取反后最大化的数组和860.柠檬水找零序列问题376.摆动序列法一&#xff1a;贪心法法二&#xff1a;动态规划单调递增的数字简化版本有点难度53.最大子序和贪心算法动态规划134.加油站968.监控二叉树两个维度权衡问题分发糖果406.根据…...

C语言每日一题】——杨氏矩阵

【C语言每日一题】——倒置字符串&#x1f60e;前言&#x1f64c;杨氏矩阵&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者简介…...

最佳iOS设备管理器imazing 2.16.9官网Mac/Windows下载电脑版怎么下载安装

imazing 2.16.9官网Mac/Windows下载电脑版是款针对苹果设备所打造的管理工具。iMazing为用户提供多种设备管理功能&#xff0c;每一位用户都能以自己的形式管理苹果设备。iMazing与苹果设备连接后&#xff0c;用户就可以轻松传输文件&#xff0c;浏览保存信息等。 应用介绍 iM…...

八大排序算法之堆排序的实现+经典TopK问题

目录 一.堆元素的上下调整接口 1.前言 2.堆元素向上调整算法接口 3.堆元素向下调整算法接口 二.堆排序的实现 1.空间复杂度为O(N)的堆排序(以排升序为例) 思路分析: 代码实现: 排序测试: ​时空复杂度分析: 2. 空间复杂度为O(1)的堆排序(以排降序为例) 将数组arr调…...

使用AppSmith(PagePlug )低代码平台快速构建小程序应用实践

文章目录一、入门&#xff08;一&#xff09;介绍&#xff08;二&#xff09;功能特性&#xff08;三&#xff09;体验一下&#xff08;四&#xff09;参考教程二、使用Appsmith构建商城微信小程序&#xff08;一&#xff09;说明&#xff08;二&#xff09;应用配置&#xff0…...

第52章 短信验证服务和登录的后端定义实现

1 Services.Messages.SmsValidate using Core.Domain.Messages; using Data; using Microsoft.EntityFrameworkCore; namespace Services.Messages { /// <summary> /// 【短信验证服务--类】 /// <remarks> /// 摘要&#xff1a; /// 通过类中的方法成员实…...

谷歌验证码的使用

1. 表单重复提交之验证码 1.1 表单重复提交三种常见情况 提交完表单。服务器使用请求转来进行页面跳转。这个时候&#xff0c;用户按下功能键 F5&#xff0c;就会发起最后一次的请求。造成表单重复提交问题。解决方法&#xff1a;使用重定向来进行跳转用户正常提交服务器&…...

Git学习入门(1)- git的安装与配置

title: git学习&#xff08;1&#xff09; - git的安装与配置CSDN: https://blog.csdn.net/jj6666djdbbd?typeblogBlog: https://helloylh.comGithub: https://github.com/luumodtags: gitabbrlink: 12001description: 本文主要讲解了git的安装&#xff0c;配置基本工作date: …...

【Python】使用Playwright断言方法验证网页和Web应用程序状态

作为测试框架&#xff0c;Playwright 提供了一系列断言方法&#xff0c;您可以使用它们来验证网页和 Web 应用程序的状态。在这篇博客中&#xff0c;田辛老师将介绍 Playwright 中可用的各种断言方法&#xff0c;并为每种方法提供示例。 assert page.url() expected_url &…...

libgdx导入blender模型

具体就是参考 官网 https://libgdx.com/wiki/graphics/3d/importing-blender-models-in-libgdx blender 教程可以看八个案例教程带你从0到1入门blender【已完结】 这里贴一下过程图。 1.初始环境搭建略过。 2.打开blender 选中摄像机和灯光&#xff0c;右键进行删除。 3.选中…...

【20230227】回溯算法小结

回溯法又叫回溯搜索法&#xff0c;是搜索的一种方式。回溯法本质是穷举所有可能。如果想让回溯法高效一些&#xff0c;可以加一些剪枝操作。回溯算法解决的经典问题&#xff1a;组合问题切割问题子集问题排列问题棋盘问题如何去理解回溯法&#xff1f;回溯法解决的问题都可以抽…...

centos安装rocketmq

centos安装rocketmq1 下载rocketmq二进制包2 解压二进制包3 修改broker.conf4 修改runbroker.sh和runserver.sh的JVM参数5 启动NameServer和Broker6 安装rockermq dashboard(可视化控制台)1 下载rocketmq二进制包 点击rocketmq二进制包下载地址&#xff0c;下载完成之后通过ft…...

汇编语言程序设计(二)之寄存器

系列文章 汇编语言程序设计&#xff08;一&#xff09; 寄存器 在学习汇编的过程中&#xff0c;我们经常需要操作寄存器&#xff0c;那么寄存器又是什么呢&#xff1f;它是用来干什么的&#xff1f; 它有什么分类&#xff1f;又该如何操作&#xff1f;… 你可能会有许多的…...

华为OD机试Golang解题 - 单词接龙 | 独家

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典文章目录 华为Od必看系列使用说明本期题目…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

简单介绍C++中 string与wstring

在C中&#xff0c;string和wstring是两种用于处理不同字符编码的字符串类型&#xff0c;分别基于char和wchar_t字符类型。以下是它们的详细说明和对比&#xff1a; 1. 基础定义 string 类型&#xff1a;std::string 字符类型&#xff1a;char&#xff08;通常为8位&#xff09…...