你能告诉我这个 Cohen-Sutherland 算法的实现有啥问题吗?

Posted

技术标签:

【中文标题】你能告诉我这个 Cohen-Sutherland 算法的实现有啥问题吗?【英文标题】:Can you tell me what's wrong with this implementation of Cohen-Sutherland Algorithm?你能告诉我这个 Cohen-Sutherland 算法的实现有什么问题吗? 【发布时间】:2015-10-01 03:13:47 【问题描述】:

请帮我修复这个 Cohen-Sutherland 算法实现的代码。

The theory is here 在第 91 页。

Here is the entire project.

#include "Line2d.h"
#include "Rectangle2d.h"
#include "Coordinates2d.h"

class ClippingLine2d

private:
    Rectangle2d rectangle;//clipping rectangle
    Line2d line;//line to be clipped
private:
    Bits startPointBits;//bits for start point of line
    Bits endPointsBits;//bits for end point of line
public:
    ClippingLine2d(Rectangle2d rect, Line2d line)
    
        this->rectangle = rect;
        this->line = line;      
           
private:        
    Line2d GetClippedLine(std::vector<Line2d> clippingRegionLines, Line2d ln)
    
        Point2d start = ln.GetStart();
        Point2d end = ln.GetEnd();

        if(startPointBits.bit4 == 1)
        
            start = ln.GetIntersection(clippingRegionLines[3]);//DA
        
        else if(startPointBits.bit3 == 1)
        
            start = ln.GetIntersection(clippingRegionLines[1]);//BC
        
        else if(startPointBits.bit2 == 1)
        
            start = ln.GetIntersection(clippingRegionLines[0]);//AB
        
        else if(startPointBits.bit1 == 1)
        
            start = ln.GetIntersection(clippingRegionLines[2]);//CD
        


        if(endPointsBits.bit4 == 1)
        
            end = ln.GetIntersection(clippingRegionLines[3]);//DA
        
        else if(endPointsBits.bit3 == 1)
        
            end = ln.GetIntersection(clippingRegionLines[1]);//BC
        
        else if(endPointsBits.bit2 == 1)
        
            end = ln.GetIntersection(clippingRegionLines[0]);//AB
        
        else if(endPointsBits.bit1 == 1)
        
            end = ln.GetIntersection(clippingRegionLines[2]);//CD
        

        return Line2d(start.Round(), end.Round());
    
public:
    Line2d GetClippedLine()
    
        Point2d min = rectangle.GetStart();
        Point2d max = rectangle.GetEnd();

        startPointBits.PointToBits(max, min, line.GetStart());
        endPointsBits.PointToBits(max, min, line.GetEnd());

        std::vector<Line2d> clippingRegionLines = rectangle.GetLines();

        Line2d tempLine = this->line;
        Bits start = startPointBits;
        Bits end = endPointsBits;

        while(start.IsClippingCandidate(end))
        
            tempLine = GetClippedLine(clippingRegionLines, tempLine);

            Point2d startP = tempLine.GetStart();
            Point2d endP = tempLine.GetEnd();

            start.PointToBits(max, min, startP);
            end.PointToBits(max, min, endP);

            Coordinates2d::Draw(tempLine);
        

        return tempLine;
    
;

#define LINENUM 3

int main()

    Line2d ln(Point2d(-120, -40), Point2d(270, 160)); 
    Rectangle2d rect(Point2d(0, 0), Point2d(170, 120)); 

    Coordinates2d::ShowWindow("Cohen-Sutherland Line Clipping");
    Coordinates2d::Draw(ln);
    Coordinates2d::Draw(rect);  

    ClippingLine2d clip(rect, ln);

    Line2d clippedLine = clip.GetClippedLine();

    Coordinates2d::Draw(clippedLine);

    Coordinates2d::Wait();

    return 0;

GetClippedLine() 陷入无限循环。因为,线端点的Bit3始终保持为1..


反对者和接近者,请留下评论。

【问题讨论】:

【参考方案1】:

Bits 类中的== 运算符包含一个错误:

bool operator == (Bits & b)

    bool b1 = bit1 == b.bit1;
    bool b2 = bit2 == b.bit2; // <-- change bit1 to bit2
    bool b3 = bit3 == b.bit3; // <-- change bit1 to bit3
    bool b4 = bit4 == b.bit4; // <-- change bit1 to bit4

    if(b1==true && b2==true && b3==true && b4==true) return true;
    else return false;

IsClippingCandidate()内部GetClippedLine()调用操作符函数

此外,您的剪裁测试与零进行比较,如果线的端点大于或等于剪裁线,则返回 1(需要剪裁),这意味着如果它被精确剪裁到行它将始终为 1。因此,将比较更改为大于而不是大于或等于。

int Sign(int a)

    if(a>0) return 1;
    else return 0;

此外,如果您得到不准确的结果,您可以尝试以浮点而不是整数进行剪辑,在这种情况下,您应该将 a 的类型更改为浮点或双精度,并为比较添加一个小的容差,例如if(a &gt; 0.0001f)

只要在 start 或 end 中设置了位,剪裁函数就应该执行,因此将 IsClippingCandidate 更改为 OR 两者一起,并在结果为零时返回 false(两者都没有设置位),否则返回 true:

bool IsClippingCandidate(Bits & bits)

    Bits zeroBits;
    Bits orredBits = *this | bits;

    if(orredBits == zeroBits) return false;
    else return true;

你也可以测试这条线是否完全在剪切区域之外,可以这样丢弃:

bool IsInvisible(Bits & bits)

    Bits zeroBits;
    Bits andedBits = *this & bits;

    if(andedBits == zeroBits) return false;
    else return true;

如果两个点都在给定的剪切线之外,那么这条线是不可见的。

【讨论】:

它有效,但问题是,算法是否正确实施?我怀疑实际上根本不需要while循环来实现算法。你怎么看? 在通过循环后可能会设置一些剪辑位,但我认为您还需要进行测试才能完全丢弃该行。如果你和它们并且结果不为零,那么这条线完全在剪切区域之外。

以上是关于你能告诉我这个 Cohen-Sutherland 算法的实现有啥问题吗?的主要内容,如果未能解决你的问题,请参考以下文章

裁剪算法——Cohen-Sutherland算法

为啥在 Cohen-Sutherland 裁剪算法中计算水平线的 x 截距时需要舍入?

麻烦用中文告诉我这些单词怎么读 谢谢

你能告诉我一亿以内有多少对孪生素数吗?

你能告诉我这段代码在做啥吗?

[计算机图形学 with OpenGL] Chapter8 习题8.6 线段旋转后使用Cohen-Sutherland算法裁剪