目录
已知两点P1 P2,来推导直线算法
如:y=kx+b
但其中会产生浮点数,我们知道在像素级别的绘制中是不能出现浮点数的,因此我们需要想办法消灭浮点数。
先说结论:Brensenham直线算法就是不断判断下图中d1和d2的距离,取其中的最小值来判断要绘制哪一个像素。
下面进行一些数学的推导:
由图中:
又(其中产生了浮点数)
其中为了方便设
则
考察第一个点:
带入
得:,
由此可以判断它的正负,若为负,说明d1-d2<0,即d1
通过可以迭代:
整体的思路,就是说通过P1这个点,来消除浮点数的出现,然后判断P1的正负,来选择下一个像素是上面的还是下面的像素(看上面的图)
总结:
初始:
当
否则(也就是d1<d2,选择下面的像素点):
--------------------------------------------以上是在斜率k<1的情况下-------------------------------------------------
如果k>1,则将dx与dy进行交换,用y进行”步进“
- namespace GT {
- void GT::Canvas::drawLine(intV2 pt1, intV2 pt2, RGBA _color){
- int disX = abs(pt2.x - pt1.x);
- int disY = abs(pt2.y - pt1.y);
-
- int xNow = pt1.x;
- int yNow = pt2.y;
-
- int stepX = 0;
- int stepY = 0;
-
- //判断两个方向步进的正负
- stepX = pt1.x < pt2.x ? 1 : -1;
- stepY = pt1.y < pt2.y ? 1 : -1;
-
- //对比xy偏移量,决定步进方向选取x or y
- int sumStep = disX;
- bool useXStep = true;
- if (disX < disY) {
- sumStep = disY;
- useXStep = false;
- SWAP_INT(disX, disY);
- }
-
- //初始化P
- int p = 2 * disY - disX;
- for (int i = 0; i < sumStep; i++) {
- drawPoint(xNow, yNow, _color);
- if (p >= 0) {
- if (useXStep) {
- yNow += stepY;
- }
- else {
- xNow += stepX;
- }
- p = p - 2 * disX;
- }
- //步进主坐标
- if (useXStep) {
- xNow += stepX;
- }
- else {
- yNow += stepY;
- }
- p = p + 2 * disY;
- }
- }
- }
测试:
- void Render() {
- _canvas->clear();
-
- 逐像素绘制
- //for (int i = 0; i < wWidth; i++) {
- // for (int j = 0; j < wHeight; j++) {
- // GT::RGBA _color(rand() % 255, rand() % 255, rand() % 255);
- // _canvas->drawPoint(i, j, _color);
- // }
- //}
- _canvas->drawLine(GT::intV2(100, 100), GT::intV2(150, 150),GT::RGBA(255,0,0));
-
- //在这里画到设备上,hMem相当于缓冲区
- BitBlt(hDC, 0, 0, wWidth, wHeight, hMem, 0, 0, SRCCOPY);
- }
- void Render() {
- _canvas->clear();
-
- GT::RGBA _color(rand() % 255, rand() % 255, 0);
- GT::intV2 pt1(100, 100);
- float r = 50;
- for (int i = 0; i < 360; i += 20) {
- float radian = DEG2RAD(i);
- int x = r * sin(radian) + pt1.x;
- int y = r * cos(radian) + pt1.y;
- GT::intV2 pt2(x, y);
-
- _canvas->drawLine(pt1, pt2, _color);
- }
-
- //在这里画到设备上,hMem相当于缓冲区
- BitBlt(hDC, 0, 0, wWidth, wHeight, hMem, 0, 0, SRCCOPY);
- }
- //=========画线算法Brensenhem===
- void drawLine(Point pt1,Point pt2);
-
- //=========线性插值Lerp=========
- inline RGBA colorLerp(RGBA _color1, RGBA _color2, float _scale) {
- RGBA _color;
- _color.m_r = _color.m_r + (float)(_color2.m_r - _color1.m_r) * _scale;
- _color.m_g = _color.m_g + (float)(_color2.m_g - _color1.m_g) * _scale;
- _color.m_b = _color.m_b + (float)(_color2.m_b - _color1.m_b) * _scale;
- _color.m_a = _color.m_a + (float)(_color2.m_a - _color1.m_a) * _scale;
- return _color;
- }
- #include "Canvas.h"
- #include
- #include "GTMATH.hpp"
-
- namespace GT {
- void GT::Canvas::drawLine(Point pt1, Point pt2) {
- int disX = abs(pt2.m_x - pt1.m_x);
- int disY = abs(pt2.m_y - pt1.m_y);
-
- int xNow = pt1.m_x;
- int yNow = pt1.m_y;
-
- int stepX = 0;
- int stepY = 0;
-
- //判断两个方向步进的正负
- stepX = pt1.m_x < pt2.m_x ? 1 : -1;
- stepY = pt1.m_y < pt2.m_y ? 1 : -1;
-
- //对比xy偏移量,决定步进方向选取x or y
- int sumStep = disX;
- bool useXStep = true;
- if (disX < disY) {
- sumStep = disY;
- useXStep = false;
- SWAP_INT(disX, disY);
- }
-
- //初始化P
- int p = 2 * disY - disX;
- for (int i = 0; i < sumStep; i++) {
- RGBA _color;
- float _scale = 0;
- if (useXStep) {
- _scale = (float)(xNow - pt1.m_x) / (float)(pt2.m_x - pt1.m_x);
- }
- else {
- _scale = (float)(yNow - pt1.m_y) / (float)(pt2.m_y - pt1.m_y);
- }
- _color = colorLerp(pt1.m_color, pt2.m_color, _scale);
- drawPoint(xNow, yNow, _color);
-
- if (p >= 0) {
- if (useXStep) {
- yNow += stepY;
- }
- else {
- xNow += stepX;
- }
- p = p - 2 * disX;
- }
- //步进主坐标
- if (useXStep) {
- xNow += stepX;
- }
- else {
- yNow += stepY;
- }
- p = p + 2 * disY;
- }
- }
- }
-
-
- void Render() {
- _canvas->clear();
-
- GT::Point pt1(100, 100, GT::RGBA(255, 0, 0));
- float r = 100;
- for (int i = 0; i < 360; i += 20) {
- float radian = DEG2RAD(i);
- int x = r * sin(radian) + pt1.m_x;
- int y = r * cos(radian) + pt1.m_y;
- GT::Point pt2(x, y, GT::RGBA(0, 255, 0));
-
- _canvas->drawLine(pt1, pt2);
- }
-
- //在这里画到设备上,hMem相当于缓冲区
- BitBlt(hDC, 0, 0, wWidth, wHeight, hMem, 0, 0, SRCCOPY);
- }