最小闭环工程是指新建一个工程,保留能够复现问题的最少的代码,删除其他无关的因素,从而找到问题原因。

这是本次使用的最小工程,它只包括了tgaimage库函数(用于输出图片)、扫描线算法scanline 、两点画直线算法line_rough 和 一个main函数。

#include <vector>
#include "tgaimage.h"
#include <iostream>
using namespace std;

void line_rough(int x0, int y0, int x1, int y1, TGAImage& image, TGAColor& color){
    int d_x = x1 - x0;
    int d_y = y1 - y0;
    float X, Y;

    for (float q = 0.; q < 1; q += 0.01){
        X = x0 + q * d_x;
        Y = y0 + q * d_y;
        image.set(X, Y, color);
    }
}

float k_p0p2, b_p0p2, k_p0p1, b_p0p1, k_p1p2, b_p1p2;
int i, j;
#define UNEXIST -99999
void scanline(int p0[2], int p1[2], int p2[2], TGAImage& image, TGAColor color){
    if (p1[1] > p0[1]) swap(p1, p0);
    if (p2[1] > p0[1]) swap(p2, p0);
    if (p2[1] > p1[1]) swap(p2, p1);

    // 若p0p1在同一条垂直线
    if (p0[0] == p1[0]) 
    {
        cout << "fmxs:p0p1是一条垂直线!" << endl;
        k_p0p1 = UNEXIST;
        b_p0p1 = UNEXIST;
    }
    else
    {
        k_p0p1 = 1.0 * (p0[1] - p1[1]) / (p0[0] - p1[0]);
        b_p0p1 = p0[1] - k_p0p1 * p0[0];
    }

    k_p0p2 = 1.0 * (p0[1] - p2[1]) / (p0[0] - p2[0]);
    b_p0p2 = p2[1] - k_p0p2 * p2[0];
   
    k_p1p2 = 1.0 * (p1[1] - p2[1]) / (p1[0] - p2[0]);
    b_p1p2 = p1[1] - k_p1p2 * p1[0];

    vector<vector<float>> memo1, memo2;

    if (k_p0p1 == UNEXIST) {
        for (int Y = p0[1]; Y >= p1[1]; --Y) {
            memo1.push_back({ 1.0f * p0[0] , 1.0f * Y });
        }
    }
    else
    {
        for (int Y = p0[1]; Y >= p1[1]; --Y) {
            memo1.push_back({ (Y - b_p0p1) / k_p0p1 , (Y - b_p0p2) / k_p0p2 });
        }
    }

    i = 0;
    for (int Y = p0[1]; Y >= p1[1]; --Y){
        line_rough(memo1[i][0], Y, memo1[i][1], Y, image, color);
        i++;
    }

    for (int Y = p1[1]; Y >= p2[1]; --Y){
        memo2.push_back({ (Y - b_p1p2) / k_p1p2 , (Y - b_p0p2) / k_p0p2 });
    }

    j = 0;
    for (int Y = p1[1]; Y >= p2[1]; --Y){
        line_rough(memo2[j][0], Y, memo2[j][1], Y, image, color);
        j++;
    }
}

int main(){
    TGAImage image(800, 800, TGAImage::RGB);
    TGAColor red = TGAColor(255, 0, 0, 1);
    TGAColor green = TGAColor(0, 255, 0, 1);

    // Define a right triangle to determine if the algorithm can draw it
    int p0[2] = { 0,0 }, p1[2] = { 0,300 }, p2[2] = { 300, 0 };
    // Define a common triangle to determine if the algorithm can draw it
    int p3[2] = { 300,90 }, p4[2] = { 400,50 }, p5[2] = { 500,60 };

    scanline(p0, p1, p2, image, red);
    scanline(p3, p4, p5, image, green);

    image.write_tga_file("testRightTriangle.tga");
    return 0;
}

上面代码的main函数中绘制了两个三角形,第一个为直角三角形,其直角边是一条垂直线;第二个为一个普通的三角形。

在输出图片后发现第一个三角形(红色)没有绘制,第二个三角形(绿色)绘制出了。

Untitled

由此可以确定扫描线算法缺少了一个特殊情况的判断:垂直线。我们便可以根据此思路去优化代码。

本最小闭环工程的更多信息请看:

https://stackoverflow.com/questions/75508136/the-scan-line-algorithm-cannot-draw-when-one-side-of-a-triangle-is-vertical

第3个绘制结果[192102232023]