使用C++ Builder VCL消除锯齿行

3okqufwl  于 2022-12-05  发布在  其他
关注(0)|答案(1)|浏览(201)

我需要通过引入反锯齿线来升级一个旧的VCL图形应用程序。为此,我用C编写了https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm页中指出的算法。代码如下。不幸的是,我没有找到任何方法或手段来推导C Builder的“亮度”,不同颜色的亮度如何?

//Antialiased line:
void Observer::aaLine(int x0, int y0, int x1, int y1)
{
    //Draws the pixel point (x,y) with specified brightness, 0 <= br <= 1 :
    auto plot = [&](double X, double Y, double brighness){
        pC->Pixels[X][Y] = brightness; };

    //Fractional part of x:
    auto fpart  = [](double x) { return x - floor(x); };
    auto rfpart = [&](double x) { return 1 - fpart(x); };

    bool steep = abs(y1 - y0) > abs(x1 - x0);

    if(steep) {
        std::swap(x0, y0);
        std::swap(x1, y1);
    }

    if( x0 > x1 ) {
        std::swap(x0, x1);
        std::swap(y0, y1);
    }

    auto dx = x1 - x0;
    auto dy = y1 - y0;
    double gradient;

    if( dx == 0.0 )
        gradient = 1.0;
    else
        gradient = dy / dx;

    //Handle first endpoint
    auto xend = round(x0),
         yend = y0 + gradient * (xend - x0),
         xgap = rfpart(x0 + 0.5),
         xpxl1 = xend, // this will be used in the main loop
         ypxl1 = floor(yend);

    if( steep ) {
        plot(ypxl1,   xpxl1, rfpart(yend) * xgap);
        plot(ypxl1+1, xpxl1,  fpart(yend) * xgap);
    }
    else {
        plot(xpxl1, ypxl1  , rfpart(yend) * xgap);
        plot(xpxl1, ypxl1+1,  fpart(yend) * xgap);
    }
    auto intery = yend + gradient; // first y-intersection for the main loop

    //Handle second endpoint
    xend = round(x1);
    yend = y1 + gradient * (xend - x1);
    xgap = fpart(x1 + 0.5);
    auto xpxl2 = xend, //this will be used in the main loop
         ypxl2 = floor(yend);
    if( steep ){
        plot(ypxl2  , xpxl2, rfpart(yend) * xgap);
        plot(ypxl2+1, xpxl2,  fpart(yend) * xgap);
    }
    else {
        plot(xpxl2, ypxl2,  rfpart(yend) * xgap);
        plot(xpxl2, ypxl2+1, fpart(yend) * xgap);
    }

    //Main loop:
    if( steep )
        for(double x = xpxl1 + 1 ; x <= xpxl2 - 1 ; x += 1)
        {
            plot(floor(intery)  , x, rfpart(intery));
            plot(floor(intery)+1, x,  fpart(intery));
            intery += gradient;
        }
    else
        for(double x = xpxl1 + 1 ; x <= xpxl2 - 1 ; x += 1)
        {
            plot(x, floor(intery),  rfpart(intery));
            plot(x, floor(intery)+1, fpart(intery));
            intery += gradient;
        }
}//Observer::aaLine.

问题位于(我相信)函数的lambda顶部。非常感谢。

kmbjn2e3

kmbjn2e31#

我认为你的问题就在于此:

auto plot = [&](double X, double Y, double brighness){
    pC->Pixels[X][Y] = brightness; };

如果我没理解错的话,pC是某个目标TCanvas ......这有两个主要问题:

  • pC->Pixels[X][Y] = brightness;将根据所选模式(如复制、异或等)将brightness处理为颜色,而不是亮度。

我会使用alpha混合的形式,你采取原始渲染颜色(或背景)和渲染线的想要的颜色,并将其与brightness混合作为参数:

TColor c0=pC->Pixels[X][Y],c0=color of your line;

 // here mix colors c = (c0*(1.0-brightness)) + (c1*brightness)
 // however you need to do this according to selected pixelformat of you graphic object and color channel wise...

 pC->Pixels[X][Y]=c;

注意VCL透明度不使用alpha参数,它只是不透明或不...有关混合的更多信息,请参见类似的:

尤其要注意:

union
         {
         DWORD dd;
         BYTE db[4];
         } c,c0;

因为TColor是32位整数...

  • VCL(或任何基于GDI的API)中的pC->Pixels[X][Y]的速度充其量也是可怜的

如果你要处理很多像素,你应该考虑使用Graphics::TBitmap中的ScanLine[Y] ...并渲染到位图作为后备缓冲区。这通常会将速度提高约1000到约10000倍。有关更多信息,请参阅:

相关问题