- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在整个 Internet 上进行了搜索,发现了数百个 Bresenham 线图算法的实现。但是,我发现奇怪的一件事是,只有两个或三个可以覆盖所有八个八位字节。尽管如此,它们仍在许多应用中使用。
例如,this lady已实现 this version (line 415) Bresenham 的算法。但是,它并没有涵盖整个 360 度。 This guy here似乎正在开发一个图书馆。但它仍然无法正常工作。
你能告诉我为什么吗?
This guy's implementation工作良好。但是,我想这不是 Bresenham 的算法。它与 the theory 几乎没有相似之处。 .
最后,我找到了the following version正确运行的 Bresenham 画线算法。
#include "utils.h"
void Bresenham(int x1, int y1, int const x2, int const y2, int color)
{
int dx = x2 - x1;
// if x1 == x2, then it does not matter what we set here
int ix((dx > 0) - (dx < 0));
dx = abs(dx) << 1;
int dy = y2 - y1;
// if y1 == y2, then it does not matter what we set here
int iy((dy > 0) - (dy < 0));
dy = abs(dy) << 1;
PlotPixel(x1, y1, color);
if (dx >= dy)
{
// error may go below zero
int error(dy - (dx >> 1));
while (x1 != x2)
{
if ((error >= 0) && (error || (ix > 0)))
{
error -= dx;
y1 += iy;
}
// else do nothing
error += dy;
x1 += ix;
PlotPixel(x1, y1, color);
}
}
else
{
// error may go below zero
int error(dx - (dy >> 1));
while (y1 != y2)
{
if ((error >= 0) && (error || (iy > 0)))
{
error -= dy;
x1 += ix;
}
// else do nothing
error += dx;
y1 += iy;
PlotPixel(x1, y1, color);
}
}
}
int main()
{
int gm = DETECT;
int gd = DETECT;
initgraph(&gm, &gd, "");
double x1 = 0;
double y1 = 0;
double r = 50;
double x2 = 0;
double y2 = 0;
double signx = 0;
double signy = 0;
for(int theta=0 ; theta<=360 ; theta++)
{
x2 = r * cos(DegreeToRad((double) theta));
y2 = r * sin(DegreeToRad((double) theta));
x1 = 5 * cos(DegreeToRad((double) theta));
y1 = 5 * sin(DegreeToRad((double) theta));
Bresenham(x1, y1, x2, y2, YELLOW);
//delay(10);
}
getch();
closegraph();
return 0;
}
原始代码很奇怪。所以,我需要你的帮助来理解这一点。
为什么他要左移 dx 和 dy,然后在计算之前再次右移它们?
the theory 的 dt 和 ds 在哪里?谈论?
根据理论,dt和ds应该在while循环的每一步都被测试过。但是,这段代码并没有这样做。为什么?
理论似乎没有任何错误值处理的迹象。代码正在计算的 error
有什么用?他如何计算错误
?他如何使用 error
值?
测试 if(dx >= dy)
背后的逻辑是什么?
最佳答案
这是对我自己的 Bresenham 版本的解释。
我们从直线的参数方程开始,(X + t.Dx, Y + t.Dy)
, 其中t
是 [0, 1]
范围内的参数.端点显然是 (X, Y)
和 (X + Dx, Y + Dy)
.
要将其转换为数字线,我们需要每行或每列恰好有一个像素,以确保连续线为准。所以定义 D = Max(|Dx|, |Dy|)
, 我们将绘制 D+1
分数对应的点 t
: (X + I.Dx/D, Y + I.Dy/D)
, 与 I
在 [0, D]
.
让我们暂时假设0 <= Dy < Dx = D
, 等式简化为 (X + I, Y + I.Dy/Dx)
.由于最后一项可能不是整数,我们将其四舍五入为round(I.Dy/Dx) = floor(I.Dy/Dx + 1/2) = floor((I.Dy + Dx/2) / Dx)
。 .
后一个表达式是等差数列对大于公差的分母的商。因此,当您增加 I
时, 该比率要么保持固定,要么增加 1
.对于无除法的实现,我们使用了一个技巧:保留商和除法的余数,让 Q
和 R
,每次增加I
, 更新这些。
让N = I.Dy + Dx/2
, 和 Q = N / Dx
, R = N % Dx
.然后增加I
, I' = I + 1
, N' = N + Dy
, Q' = (N + Dy) / Dx
, R' = (N + Dy) % Dx
.如您所见,以下规则成立:
if R + Dy >= Dx
Q' = Q + 1; R' = R + Dy - Dx
else
Q' = Q; R' = R + Dy
我们现在将所有元素放在一起,调整符号并区分更水平和更垂直的情况(正如您会注意到的那样,无需显式表示 Q
):
# Increments
Sx= Sign(Dx); Sy= Sign(Dy)
# Segment length
Dx= |Dx|; Dy= |Dy|; D= Max(Dx, Dy)
# Initial remainder
R= D / 2
if Dx > Dy:
# Main loop
for I= 0..D:
Set(X, Y)
# Update (X, Y) and R
X+= Sx; R+= Dy # Lateral move
if R >= Dx
Y+= Sy; R-= Dx # Diagonal move
else:
# Main loop
for I= 0..D:
Set(X, Y)
# Update (X, Y) and R
Y+= Sy; R+= Dx # Lateral move
if R >= Dy
X+= Sx; R-= Dy # Diagonal move
C/C++ 实现(来自@anonymous)
void Set(int x, int y, int color)
{
PlotPixel(x, y, color);
}
int Sign(int dxy)
{
if(dxy<0) return -1;
else if(dxy>0) return 1;
else return 0;
}
void Bresenham(int x1, int y1, int x2, int y2, int color)
{
int Dx = x2 - x1;
int Dy = y2 - y1;
//# Increments
int Sx = Sign(Dx);
int Sy = Sign(Dy);
//# Segment length
Dx = abs(Dx);
Dy = abs(Dy);
int D = max(Dx, Dy);
//# Initial remainder
double R = D / 2;
int X = x1;
int Y = y1;
if(Dx > Dy)
{
//# Main loop
for(int I=0; I<D; I++)
{
Set(X, Y, color);
//# Update (X, Y) and R
X+= Sx; R+= Dy; //# Lateral move
if (R >= Dx)
{
Y+= Sy;
R-= Dx; //# Diagonal move
}
}
}
else
{
//# Main loop
for(int I=0; I<D; I++)
{
Set(X, Y, color);
//# Update (X, Y) and R
Y+= Sy;
R+= Dx; //# Lateral move
if(R >= Dy)
{
X+= Sx;
R-= Dy; //# Diagonal move
}
}
}
}
关于c++ - 请为我解释这个 Bresenham Line 绘图代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32251437/
我在一个项目中工作,该项目需要 SQL 结果的最佳性能,并且希望优化查询,但经过反复试验后,我在 IN 方面遇到了一些问题。 -- THIS RETURNS NO RESULTS AT ALL. SE
在尝试创建一个实际上非常简单的 SQL 语句时,我发现自己迷失了方向。 我有一个包含 3 个表的数据库: 食谱 - 存储一些用于 cooking 的食谱名称 配料食谱 - 将配料与食谱链接 成分 -
我正在尝试理解 PHP 中的 Hebrev 函数。 https://php.net/manual/en/function.hebrevc.php 它说:“将逻辑希伯来语文本转换为视觉文本”。但我不明白
嗨,我在 Grid view 的 android 文档中发现了一段代码对于以下代码。 gridview.setOnItemClickListener(new OnItemClickListener()
谁能解释一下 InfiniBand 是什么?与以太网相比的主要区别是什么,这些差异如何使其比以太网更快? 在官方description从 mellanox 写到 Introduce InfiniBan
这个问题已经有答案了: How are java increment statements evaluated in complex expressions (1 个回答) 已关闭 8 年前。 我知道
我正在阅读 MySQL 教程,我遇到了这个: SELECT /*! SQL_NO_CACHE */ user FROM users; 为什么优化提示 SQL_NO_CACHE 包含在: /*!
我无法理解$(this),我做了一个剪刀石头布的版本,并应用了 jQuery 让用户在计算机上选择按钮选项。我希望有人能解释一下 $(this) 指的是什么,它是 btn-primary 吗?该函数在
我不是很确定 while(choice == 1 || choice ==2);谁能解释一下。我明白这一点 if(choice ==1) displayMonthly(rainfall); e
let flyRight = CABasicAnimation(keyPath: "position.x") flyRight.toValue = view.bounds.size.width/2 f
目录 解释:int型默认值为0 但我们尝试发现并不能通过: 原因: int的默认值为0,而Integer的默认值为null
我正在处理一个查询,自从一个 SSRS 服务器传输到另一个服务器后,它似乎没有按预期执行,并且 where 语句的一部分中出现了以下行 找出不同之处,或者至少从我能找到的地方来看。 where COA
我正在制作一个退回检测程序,读取退回邮件。我们的设置是发送电子邮件,在发送的邮件中添加一个 noreply@domain.tl。一些收件人不再存在,因此我们想要读取退回邮件,并检测它发送给谁。我已经崩
我有一个关于公式通过控制点弯曲的问题。 如您所知,HTML Canvas 有 quadraticCurveTo(x1, y1, x2, y2)与 x1 and x2作为控制点。 但是,当您尝试使用它绘
我有一个 Emakefile看起来像: %% -- %% %% -- {'/Users/user/projects/custom_test/trunk/*', [debug_info, {out
我有一个非常简单的问题。这不仅适用于 spray-json,而且我已经阅读了 argonaut 和 circe 的类似声明。所以请赐教。 在 spray-json 中,我遇到了 There is no
我正在为视频添加水印。我试图让水印与视频尺寸成比例。我已经使用 scale2ref 看到了十几个不同的答案,但没有解释实际发生了什么,所以我发现很难知道如何实现/更改配置以适应我的情况。 当前覆盖命令
因为我正在学习语言,所以我在玩 Haskell,我只是发现了一些我不理解的东西,我找不到解释。如果我尝试运行此代码: map (`div` 0) [1,2,3,4] 我得到一个除以 0 的异常,这是预
我正在寻找解决错误对象引用未设置到对象实例的步骤/指南。以及问题发生原因的解释。 我正在寻找更一般的解释,所以如果我收到错误,我应该采取什么步骤来查找问题。我经常看到有人提供特定代码段的帖子,而其他人
我最近想升级我的知识React ,所以我从组件生命周期方法开始。让我好奇的第一件事是这个componentWillReceiveProps .所以,文档说当组件接收新的(不一定是更新的) Prop 时
我是一名优秀的程序员,十分优秀!