椭圆中点算法

原理

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

四分椭圆弧

中心在原点,长半轴为 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.mzph.cn/news/593570.shtml

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

相关文章

01-03

利用模板类完成顺序表

简易电子琴

#include<reg51.h> //包含51单片机寄存器定义的头文件 sbit P14P1^4; //将P14位定义为P1.4引脚 sbit P15P1^5; //将P15位定义为P1.5引脚 sbit P16P1^6; //将P16位定义为P1.6引脚 sbit P17P1^7; //将P17位定义为P1.7引脚 unsigned char keyval; …

高端大气的在线文档

背景 产品介绍&#xff0c;帮助手册&#xff0c;操作手册&#xff0c;开发说明&#xff0c;个人的简单网站等等&#xff0c;都需要一个在线的文档&#xff0c;特别是开源社区的在线文档也非常需要&#xff0c;开源社区也为此提供了大量的工具。如何找到一款高端大气的&#xf…

解决Golang WriteHeader设置后,Content-Type失效的问题

场景 最近笔者在研究web框架过程中&#xff0c;发现了一个响应类型的问题&#xff0c;困扰许久&#xff0c;原因就是设置了响应状态码后&#xff0c;然后设置响应类型为application/json。在实际请求后&#xff0c;响应类型变成了text/plain; charsetutf-8格式。 问题解决&…

学习Go语言Web框架Gee总结--前缀树路由Router(三)

学习Go语言Web框架Gee总结--前缀树路由Router router/gee/trie.gorouter/gee/router.gorouter/gee/context.gorouter/main.go 学习网站来源&#xff1a;Gee 项目目录结构&#xff1a; router/gee/trie.go 实现动态路由最常用的数据结构&#xff0c;被称为前缀树(Trie树) 关…

【AI】目标检测算法DETR源码解析及推理测试

说到目标检测&#xff0c;自然而然我们会想到YOLO这个框架&#xff0c;YOLO框架已经发展到V8版本了&#xff0c;各种应用也比较成熟&#xff0c;不过我最近在研究Transformer&#xff0c;今天的主角是Transformer在目标检测的开山之作&#xff1a;DETR&#xff1a;End-to-End O…

FairGuard游戏加固产品常见问题解答

针对日常对接中&#xff0c;各位用户对FairGuard游戏加固方案在安全性、稳定性、易用性、接入流程等方面的关注&#xff0c;我们梳理了相关问题与解答&#xff0c;希望可以让您对产品有一个初步的认知与认可。 Q1:FairGuard游戏加固产品都有哪些功能? A&#xff1a;FairGuar…

OpenFeign

OpenFeign 一、基本使用 1、引入依赖 <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId><groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-start…

k8s的网络

k8s的网络 k8s中的通信模式&#xff1a; 1、pod内部之间容器与容器之间的通信 在同一个pod中的容器共享资源和网络&#xff0c;使用同一个网络命名空间&#xff0c;可以直接通信的 2、同一个node节点之内&#xff0c;不同pod之间的通信 每个pod都有一个全局的真实的ip地址…

BMS均衡技术

一、电池的不一致性&#xff1f; 每个电池都有自己的“个性”&#xff0c;要说均衡&#xff0c;得先从电池谈起。即使是同一厂家同一批次生产的电池&#xff0c;也都有自己的生命周期、自己的“个性”——每个电池的容量不可能完全一致。例如以下的两个原因都会造成电池不一致…

docker部署mysql

1.查找mysql镜像 [rootVM-4-5-centos ~]# docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-sourc…

AnyText:多语言视觉文字生成与编辑——最详细傻瓜式安装教程

先看图,下面都是AnyText生成的,可以说效果效果确实是很震撼了。 附上地址: GitHub - tyxsspa/AnyTextContribute to tyxsspa/AnyText development by creating an account on GitHub.https://github.com/tyxsspa/AnyText接下来开始详细讲解安装过程: 1. 下载项目 (1)下…

探讨JVM垃圾回收机制与内存泄漏

目录 1. 垃圾回收机制的基本原理 2. 内存泄漏的定义与表现 3. 垃圾回收机制的局限性 4. Finalizer导致的延迟 5. 不当使用静态集合 6. JNI资源未释放 7. 解决内存泄漏的方法 8. 结语 在Java虚拟机&#xff08;JVM&#xff09;的世界中&#xff0c;垃圾回收机制被设计用…

电磁波的信号加载说明

电磁波的信号加载电磁波(Electromagnetic wave)是由同相振荡 且互相垂直的电场与磁场在空间中衍生发射的振荡粒子波&#xff0c;是以波动的形式传播的电磁场&#xff0c;具有波粒二象性&#xff0c;其粒子形态称为光子&#xff0c;电磁波与光子不是非黑即白的关系&#xff0c;而…

外显和呼叫系统的关系

经常接到推销电销&#xff0c;对于不同号码显示&#xff0c;我们选择接听电话和挂断电话的概率也是不一样的。 我们接到号码有显示运营商和归属地名称。 例如&#xff1a;北京 移动&#xff0c;广东深圳 电信&#xff0c;广电&#xff0c;广东广州 虚拟运营商等&#xff1b; 有…

快速打通 Vue 3(二):响应式对象基础

很激动进入了 Vue 3 的学习&#xff0c;作为一个已经上线了三年多的框架&#xff0c;很多项目都开始使用 Vue 3 来编写了 这一组文章主要聚焦于 Vue 3 的新技术和新特性 如果想要学习基础的 Vue 语法可以看我专栏中的其他博客 Vue&#xff08;一&#xff09;&#xff1a;Vue 入…

Flink-【时间语义、窗口、水位线】

1. 时间语义 1.1 事件时间&#xff1a;数据产生的事件&#xff08;机器时间&#xff09;&#xff1b; 1.2 处理时间&#xff1a;数据处理的时间&#xff08;系统时间&#xff09;。 &#x1f330;&#xff1a;可乐 可乐的生产日期 事件时间&#xff08;可乐产生的时间&…

算法导论复习——CHP24 单源最短路

单源最短路径问题&#xff1a; 给定一个图G (V,E)&#xff0c;找出从给定的源点s∈V到其它每个结点v∈V的最短路径。 这样最短路径具有最优子结构性&#xff1a;两个结点之间的最短路径的任何子路径都是最短的。 基本概念 负权边&#xff1a;权重为负值的边称为负权重的边。 如…

Vue3+TS+ElementPlus的安装和使用教程【详细讲解】

前言 本文简单的介绍一下vue3框架的搭建和有关vue3技术栈的使用。通过本文学习我们可以自己独立搭建一个简单项目和vue3的实战。 随着前端的日月更新&#xff0c;技术的不断迭代提高&#xff0c;如今新vue项目首选用vue3 typescript vite pinia……模式。以前我们通常使用…

webpack知识点总结(高级应用篇)

除开公共基础配置之外&#xff0c;我们意识到两点: 1. 开发环境(modedevelopment),追求强大的开发功能和效率&#xff0c;配置各种方便开 发的功能;2. 生产环境(modeproduction),追求更小更轻量的bundle(即打包产物); 而所谓高级应用&#xff0c;实际上就是进行 Webpack 优化…