椭圆中点算法

news2024/11/27 15:50:06

原理

椭圆的扫描转换与圆的扫描转换有相似之处,但也有不同,主要区别是椭圆弧上存在改变主位移方向的临界点。瞬时针绘制四分椭圆弧的中点算法,根据对称性可以绘制完整的椭圆。

四分椭圆弧

中心在原点,长半轴为 a a a、短半轴为 b b b 的椭圆隐函数方程为

F ( x , y ) = b 2 x 2 + a 2 y 2 − a 2 b 2 = 0 F(x, y) = b^2 x^2 + a^2 y^2 -a^2 b^2 = 0 F(x,y)=b2x2+a2y2a2b2=0

四分法画椭圆算法:已知第一象限内的一点 ( x , y ) (x, y) (x,y), 可以顺时针确定另外 3 个对称点 ( x , − y ) (x, -y) (x,y) ( − x , − y ) (-x, -y) (x,y) ( − x , y ) (-x, y) (x,y)

在这里插入图片描述

临界分析

在临界点处,曲线的斜率为 − 1 -1 1

在这里插入图片描述
N ( x , y ) = N x i + N y j = ∂ F ∂ x i + ∂ F ∂ y j = 2 b 2 x i + 2 a 2 y j N(x, y) = N_{x_i} +N_{y_j} = \frac{\partial F}{\partial x}i + \frac{\partial F}{\partial y}j = 2b^2 x_i + 2 a^2y_j N(x,y)=Nxi+Nyj=xFi+yFj=2b2xi+2a2yj

法矢量的 x x x 方向的分量为 N x = 2 b 2 x N_x = 2b^2x Nx=2b2x, 法矢量的 y y y 方向为 N y Ny Ny = 2a^2y.从曲线上一点的法矢量角度看,在区域 I \bm{I} I 内, N x < N y N_x < N_y Nx<Ny 在临界点处, N x = N y N_x = N_y Nx=Ny 在区域 Ⅱ \bm{Ⅱ} 内, N x > N y N_x > N_y Nx>Ny。显然,在临界点处,法矢量分量的大小发生了变化。

在这里插入图片描述
从曲线上的斜率角度来看,在临界点处,斜率为 − 1 -1 1, 区域内 Ⅰ \bm{Ⅰ} 内, d x > d y dx > dy dx>dy, 所以 x x x 方向为主位移方向,在临界点处,有 d x = d y dx= dy dx=dy, 在区域内 Ⅱ Ⅱ 内, d y > d x dy > dx dy>dx, 所以 y y y 方向为主位移方向。在临界点处,主位移方向发生了改变。

在区域 Ⅰ Ⅰ x x x 方向上每次递增一个单位, y y y 方向上减 1 或 减 0, 取决于中点误差项的值,在区域 Ⅱ Ⅱ y y y 方向上每次递增一个单位, x x x 方向上加 1 或 加 0 取决于中点误差项的值。

在这里插入图片描述

构造区域 I I I 的中点误差项

从当前点 P i P_i Pi 出发选取一个像素点时,需将 P u P_u Pu P d P_d Pd 两个候选像素连线的网格中点 M M M ( x i + 1 , y i − 0.5 ) (x_i + 1, y_i -0.5) (xi+1,yi0.5) 代入隐函数的方程,构造中点误差项 d 1 i d_{1i} d1i

d 1 i = F ( x i + 1 , y i − 0.5 ) = b 2 ( x i + 1 ) 2 + a 2 ( y i − 0.5 ) 2 − a 2 b 2 d_{1i} = F(x_i + 1, y_i-0.5) = b^2 (x_i + 1)^2 + a^2 (y_i -0.5)^2 - a^2b^2 d1i=F(xi+1,yi0.5)=b2(xi+1)2+a2(yi0.5)2a2b2
在这里插入图片描述

y i + 1 = { y i d 1 i < 0 y i − 1 d 1 i ≥ 0 y_{i+1} = \begin{cases} y_i & d_{1i} < 0\\ yi - 1 & d_1i \geq 0 \end{cases} yi+1={yiyi1d1i<0d1i0

中点误差项 d 1 i d_{1i} d1i 的递推公式

在这里插入图片描述
d 1 i < 0 d_1i < 0 d1i<0 区域内 Ⅰ Ⅰ 内中点的递推

d 1 i + 1 = d 1 i + b 2 ( x i + 3 ) d_{1i+1} = d_{1i} + b^2(x_i + 3) d1i+1=d1i+b2(xi+3)
在这里插入图片描述
d 1 i ≥ 0 d_1i \geq 0 d1i0 区域内 Ⅰ Ⅰ 内中点的递推

d 1 i + 1 = d 1 i + b 2 ( x i + 3 ) + a 2 ( − 2 y i + 2 ) d_{1i+1} = d_{1i} + b^2(x_i + 3) + a^2(-2y_i+ 2) d1i+1=d1i+b2(xi+3)+a2(2yi+2)

中点误差项 d 1 i d_1i d1i 的初值

在区域 Ⅰ Ⅰ 内,椭圆弧的起点扫描转换后的像素点为 P 0 ( a , b ) P_0(a, b) P0(a,b) 沿着主位移 x x x 的方向递增一个单位,第一个参与判断的中点是 M ( 1 , b − 0.5 ) M(1,b-0.5) M(1b0.5), 响应的中点误差项 d 1 i d_{1i} d1i

d 10 = b 2 + a 2 ( − b + 0.25 ) d_{10} = b^2 + a^2(-b + 0.25) d10=b2+a2(b+0.25)

构造区域 Ⅱ Ⅱ 的中点误差项

在区域 Ⅱ Ⅱ 内,主位移方向发生变化,由 x x x 方向转变为 y y y 方向,从区域 Ⅰ Ⅰ 椭圆弧的终点, P i ( x i , y i ) P_i(x_i, y_i) Pi(xi,yi) 出发选取下一像素时,需将 P 1 ( x i , y i − 1 ) P_1(x_i, y_i-1) P1(xiyi1) P r ( x I + 1 , y i + 1 ) P_r(x_I +1, y_i +1) Pr(xI+1,yi+1)
的中点, M ( x i + 0.5 , y i − 1 ) M(x_i + 0.5, y_i-1) M(xi+0.5,yi1) 代入隐函数方程,构造中点误差项 d 2 i d_{2i} d2i

d 2 i = F ( x i + 0.5 , y i − 1 ) = b 2 ( x i + 0.5 ) 2 + a 2 ( y i − 1 ) 2 − a 2 b 2 d_{2i} = F(x_i + 0.5, y_i-1) = b^2(x_i + 0.5)^2 + a ^2(y_i -1)^2 -a^2b^2 d2i=F(xi+0.5,yi1)=b2(xi+0.5)2+a2(yi1)2a2b2

在这里插入图片描述

x i + 1 = { x i + 1 d 2 i < 0 x i d 2 i ≥ 0 x_{i+1} = \begin{cases} x_i + 1& d_{2i} < 0\\ xi & d_{2i} \geq 0 \end{cases} xi+1={xi+1xid2i<0d2i0

中点误差项 d 2 i d_{2i} d2i 的递推公式

在这里插入图片描述

d 2 i < 0 d_{2i} < 0 d2i<0 区域 Ⅰ Ⅰ 内中的递推
d 2 ( i + 1 ) = d 2 i + b 2 ( 2 x i + 2 ) + a 2 ( − 2 y i + 3 ) d_{2(i+1)} = d_{2i} + b^2 (2x_i+2) + a^2(-2y_i +3) d2(i+1)=d2i+b2(2xi+2)+a2(2yi+3)

在这里插入图片描述
d 2 i ≥ 0 d_{2i} \geq 0 d2i0 区域 Ⅰ Ⅰ 内中的递推

d 2 ( i + 1 ) = d 2 i + a 2 ( − 2 y i + 3 ) d_{2(i+1)} = d_{2i} + a^2(-2y_i + 3) d2(i+1)=d2i+a2(2yi+3)

中点误差项 d 2 i d_{2i} d2i 的初始值

假定 P i ( x i , y i ) P_i(x_i, y_i) Pi(xi,yi) 点为区域 Ⅰ Ⅰ 内椭圆弧上的最后一个像素, M I ( x i + 1 , y i − 0.5 ) M_I(xi+1, y_{i-0.5}) MI(xi+1,yi0.5) p u p_u pu p d p_d pd 像素的中点,满足 x x x 方向分量小于 y y y 方向分量

b 2 ( x i + 1 ) < a 2 ( y i − 0.5 ) b^2(x_i +1) < a^2(y_i -0.5) b2(xi+1)<a2(yi0.5)

在这里插入图片描述

而在下一个中点处,不等号改变方向,则说明椭圆弧从区域 Ⅰ Ⅰ 转入了区域 Ⅱ Ⅱ 。 在区域 Ⅱ Ⅱ 内,中点转换为 M Ⅱ ( x i + 0.5 , y i − 1 ) M_Ⅱ (x_i + 0.5, y_i -1) M(xi+0.5,yi1), 用于判断选取 P 1 P1 P1 P r P_r Pr 像素,所以区域 Ⅱ Ⅱ 内椭圆弧中电误差项 d d d 的初始值为

d 2 , 0 = b 2 ( x + 0.5 ) 2 + a 2 ( y − 1 ) 2 − a 2 b 2 d_{2, 0} = b^2(x+0.5)^2 + a^2(y-1)^2 - a^2b^2 d2,0=b2(x+0.5)2+a2(y1)2a2b2

算法

  1. 读入椭圆的长半轴 a a a 和短半轴 b b b
  2. 定义椭圆当前坐标 x x x y y y 定义中点误差项 d 1 d_1 d1 d 2 d_2 d2 定义像素颜色 cColoer
  3. 计算 d 10 = b 2 + a 2 ( − b + 0.25 ) d_{10} = b^2 + a^2(-b+0.25) d10=b2+a2(b+0.25) x = 0 x=0 x=0, y = 0 y=0 y=0cColor=RGB(0, 0, 255)
  4. 绘制点 $(x, y) $及其在四分椭圆中的另外 3个对称点
  5. 判断 d 1 d_1 d1 的符号,若 d 1 < 0 d_1<0 d1<0 ( x , y ) 更新为 (x, y) 更新为 (x,y)更新为 ( x i + 1 , y ) (xi+1, y) (xi+1,y), d 1 d_1 d1 更新为 d 1 + b 2 ( 2 x + 3 ) d_1+b^2(2x+3) d1+b2(2x+3); 否则 ( x , y ) 更新为 (x, y) 更新为 (x,y)更新为 ( x i + 1 , y − 1 ) (xi+1, y-1) (xi+1,y1), d 1 d_1 d1 更新为 d 1 + b 2 ( 2 x + 3 ) + a 2 ( − 2 y + 2 ) d_1+b^2(2x+3) + a^2(-2y+2) d1+b2(2x+3)+a2(2y+2)
  6. b 2 ( x i + 1 ) < a 2 ( y i − 0.5 ) b^2(x_i+1)<a^2(y_i-0.5) b2(xi+1)<a2(yi0.5) 时,重复 (4) 与 (5) 否则转到步骤 (7)
  7. 计算下半部分 d 2 d_2 d2 的初值, d 20 = b 2 ( x + 0.5 ) 2 + a 2 ( y − 1 ) 2 − a 2 b 2 d_{20} = b^2(x+0.5)^2 + a^2(y-1)^2 - a^2 b^2 d20=b2(x+0.5)2+a2(y1)2a2b2
  8. 绘制点 ( x , y ) (x, y) (x,y) 及其在四分椭圆中的另外 3 个对称点
  9. 判断 d 2 d_2 d2 的符号,若 d 2 < 0 d_2 <0 d2<0 ( x , y ) 更新为 (x, y) 更新为 (x,y)更新为 ( x i + 1 , y − 1 ) (xi+1, y-1) (xi+1,y1) d 2 d_2 d2 更新为 d 2 + b 2 2 ( 2 x + 2 ) + a 2 ( − 2 y + 3 ) d_2+b_2^2(2x+2) + a^2(-2y+3) d2+b22(2x+2)+a2(2y+3) 否则 ( x , y ) 更新为 (x, y) 更新为 (x,y)更新为 ( x i + 1 , y ) (xi+1, y) (xi+1,y), d 2 d_2 d2 更新为 d 2 + a 2 ( 2 y + 3 ) d_2+a^2(2y+3) d2+a2(2y+3)
    10.如果 y ≥ 0 y \geq 0 y0 重复步骤 (8) 和 (9)
#include <QApplication>
#include <QPainter>
#include <QWidget>

void EllipsePoint(QPainter * painter, int x, int y) {
    QColor color(255, 0, 0);  // 设置为红色

    // 平移到正确的位置
    int centerX = 400;  // 窗口宽度的一半
    int centerY = 300;  // 窗口高度的一半

    painter->setPen(color);
    painter->drawPoint(centerX+x, centerY+y);
    painter->drawPoint(centerX+x, centerY-y);
    painter->drawPoint(centerX-x, centerY-y);
    painter->drawPoint(centerX-x, centerY+y);


}


void MidPointEllipse(QPainter* painter, int a, int b) {
    int x, y;
    x = 0, y = b;
    double d1 = b * b + a * a * (-b + 0.25);

    EllipsePoint(painter, x, y);

    while (b * b * (x+1) < a * a * (y-0.5)) {

        if (d1 < 0) {
            d1 += b * b * (2*x + 3);
        } else {
            d1 += b*b * (2*x + 3) + a* a*(-2*y +2);
            y--;
        }
        x++;
        EllipsePoint(painter, x, y);
    }
    double d2 = b * b * (x + 0.5) * (x + 0.5) + a * a * (y - 1) * (y -1) - a * a * b *b;
    while (y > 0) {
        if (d2 < 0) {
            d2 += b * b * (2*x + 2) + a * a * (-2*y + 3);
            x++;
        }else {
            d2 += a* a * (-2*y + 3);
        }
        y--;
        EllipsePoint(painter, x, y);
    }

}





class MyWidget : public QWidget {
public:
    MyWidget(QWidget* parent = nullptr) : QWidget(parent) {
        setFixedSize(800, 600);
    }

protected:
    void paintEvent(QPaintEvent* event) override {
        Q_UNUSED(event);

        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing, true);

//        int radius = 50;  // 圆的半径

        int a = 200;
        int b = 100;
//        MidPointCircle(&painter, radius);
        MidPointEllipse(&painter, a, b);

    }
};


int main(int argc, char* argv[]) {
    QApplication app(argc, argv);

    MyWidget widget;
    widget.show();

    return app.exec();
}

在这里插入图片描述

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

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

相关文章

python flask学生成绩管理系统,包含使用文档

python flask学生成绩管理系统。 一.功能介绍 系统交互 登录无需注册功能 学生以学生编号为用户名&#xff0c;密码默认为学生编号&#xff0c;可修改教师以教师编号为用户名&#xff0c;密码默认为教师编号&#xff0c;可修改管理员以admin作为用户名&#xff0c;密码为固定…

关于Unity使用图片字体示例

1.使用TexturePacker打包图集 下载地址 TexturePacker - Create Sprite Sheets for your game! 2.准备好数字图 3. 导入图片 4. 打包图集需要的设置 将重心点设置为左下方 点击回车 > 后点击回 >到精灵列表 选择导出的格式 导出后的内容 >导入unity 导入 >…

AI产品经理 - 方法篇-工作方法

一、AI产品经理-典型的工作方法 二、如何从0做一个AI产品 1. 完整的工作流程 2.项目经理&#xff1a; 3.项目实施&#xff1a;样本测试模型-推荐引擎 4.项目上线 5. 项目实施-产品设计研发

elasticsearch系列九:异地容灾-CCR跨集群复制

概述 起初只在部分业务中采用es存储数据&#xff0c;在主中心搭建了个集群&#xff0c;随着es在我们系统中的地位越来越重要&#xff0c;数据也越来越多&#xff0c;针对它的安全性问题也越发重要&#xff0c;那如何对es做异地容灾呢&#xff1f; 今天咱们就一起看下官方提供的…

NXP实战笔记(三):S32K3xx基于RTD-SDK在S32DS上配置WDT配置

目录 1、WDT概述 2、SWT配置 2.1、超时时间&#xff0c;复位方式的配置 2.2、中断形式 1、WDT概述 SWT 编程模型只允许 32 位&#xff08;字&#xff09;访问。 以下任何尝试访问都是无效的: •非32位访问 •写入只读寄存器 •启用SWT时&#xff0c;将不正确的值写入SR…

SpringBoot 项目中常用的注解

每一层对应每个包&#xff0c;包名中应全为小写。 一、Common 层&#xff08;实体类&#xff09; 前提&#xff1a;导入 Lombok 依赖 Data&#xff1a;生成 get 和 set 方法以及 toString 方法 Getter&#xff1a;只生成 get 方法&#xff0c;避免对类中的成员变量修改。 …

“踩坑”经验分享:Swift语言落地实践

作者 | 路涛、艳红 导读 Swift 是一种适用于iOS/macOS应用开发、服务器端的编程语言。自2014年苹果发布 Swift 语言以来&#xff0c;Swift5 实现了 ABI 稳定性、Module 稳定性和Library Evolution&#xff0c;与Objective-C&#xff08;下文简称“OC”&#xff09;相比&#xf…

数据仓库-数仓优化小厂实践

一、背景 由于公司规模较小&#xff0c;大数据相关没有实现平台化&#xff0c;相关的架构都是原生的Apache组件&#xff0c;所以集群的维护和优化都需要人工的参与。根据自己的实践整理一些数仓相关的优化。 二、优化 1、简易架构图 2、ODS层优化 2.1 分段式解析 随着业务增长…

数据结构与算法教程,数据结构C语言版教程!(第二部分、线性表详解:数据结构线性表10分钟入门)一

第二部分、线性表详解&#xff1a;数据结构线性表10分钟入门 线性表&#xff0c;数据结构中最简单的一种存储结构&#xff0c;专门用于存储逻辑关系为"一对一"的数据。 线性表&#xff0c;基于数据在实际物理空间中的存储状态&#xff0c;又可细分为顺序表&#xff…

助力城市部件[标石/电杆/光交箱/人井]精细化管理,基于YOLOv7【tiny/yolov7】开发构建生活场景下城市部件检测识别系统

井盖、店杆、光交箱、通信箱、标石等为城市中常见部件&#xff0c;在方便居民生活的同时&#xff0c;因为后期维护的不及时往往会出现一些“井盖吃人”、“线杆、电杆、线缆伤人”事件。造成这类问题的原因是客观的多方面的&#xff0c;这也是城市化进程不断发展进步的过程中难…

点亮AI未来的U盘

随着人工智能行业蓬勃发展&#xff0c;如今国内外大模型如雨后春笋般涌现&#xff0c;国内AI赛道更是步入水深火热的发展阶段。上半年的AIGC赛道国内投融资规模以模型层为主&#xff0c;这一现象充分说明了国内人工智能应用场景的丰富多样&#xff0c;投资机会也更加聚焦于应用…

用电脑将图片转为excel表格有几种方法?怎么操作?

将图片转为Excel表格&#xff0c;一般需要借助OCR(光学字符识别)技术。OCR技术可以将图片中的文字提取出来&#xff0c;并转换成Excel表格中的数据。以下是几种常用的方法&#xff1a; 一、.使用在线OCR工具 1、打开金鸣表格文字识别&#xff08;简称金鸣识别&#xff09;网站…

软件测试/测试开发丨Python自动化测试学习笔记

1. 引言 自动化测试是软件开发中的关键环节&#xff0c;它可以提高测试效率、减少重复工作&#xff0c;并提供更快速、稳定的测试结果。Python作为一种易学易用的编程语言&#xff0c;为自动化测试提供了强大的工具和库。本文将介绍如何使用Python进行自动化测试。 2. 安装Py…

如何将弹性公网IP绑定到负载均衡CLB

创建的CLB实例为私网类型&#xff0c;没有公网IP&#xff0c;无法通过公网访问&#xff0c;如果需要让其网站能够通过公网访问&#xff0c;只需要绑定前面创建的EIP即可。 第一步 如果弹性公网IP已经绑定了资源&#xff0c;需要先解绑 第二步 将私网CLB实例绑定到弹性公网IP …

蓝牙物联网智能安防系统设计方案

1概述 安防系统(安全防护)的作用是预防损失&#xff0c;是人们保障人身和财产安全最重要的工具之一。近年来&#xff0c;伴随经济的飞速发展和城市人口的急剧增加&#xff0c;盗窃、入室抢劫等事件的增多给人们的安定生活带来了很大的影响&#xff0c;同时&#xff0c;交通的快…

[OCR]Python 3 下的文字识别CnOCR

目录 1 CnOCR 2 安装 3 实践 1 CnOCR CnOCR 是 Python 3 下的文字识别&#xff08;Optical Character Recognition&#xff0c;简称OCR&#xff09;工具包。 工具包支持简体中文、繁体中文&#xff08;部分模型&#xff09;、英文和数字的常见字符识别&#xff0c;支持竖…

如何实现内部产品权限集成

当前我国各领域正在加速向数字化、移动化、智能化发展&#xff0c;大力投入信息化建设与数字化转型已成为企业的共识&#xff0c;而企业门户系统是企业信息化系统建设是一个重要支撑&#xff0c;以企业业务系统为基础&#xff0c;搭建门户系统作为统一入口和应用中心可以有效支…

通过Python将PDF转为文本,快速提取PDF中的文字

快速高效地从PDF文档中提取信息对于专业人士来说非常重要。处理大量PDF文件时&#xff0c;将PDF转换为可编辑的文本格式可以节省时间和精力。而强大的Python语言正是在这些方面发挥其作用。利用Python中丰富的API&#xff0c;我们可以轻松在Python程序中将PDF转换为文本&#x…

YOLOv5改进 | 2023注意力篇 | BiFormer双层路由注意力机制(Bi-level Routing Attention)

一、本文介绍 BiFormer是一种结合了Bi-level Routing Attention的视觉Transformer模型&#xff0c;BiFormer模型的核心思想是引入了双层路由注意力机制。在BiFormer中&#xff0c;每个图像块都与一个位置路由器相关联。这些位置路由器根据特定的规则将图像块分配给上层和下层路…

重装系统以后无法git跟踪

总结&#xff1a;权限问题 故障定位 解决方案&#xff1a; 复制一份新的文件夹。&#xff08;新建的文件创建和写入权限都变了&#xff09; 修改文件为新的用户 执行提示的命令