Можете ли вы сказать мне, что не так с этой реализацией алгоритма Коэна-Сазерленда?

Пожалуйста, помогите мне исправить код этой реализации алгоритма Коэна-Сазерленда.

Теория здесь на странице 91.

Вот весь проект.

#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() застрял в бесконечном цикле. Coz, Бит3 конечной точки линии всегда остается 1 ..


Пожалуйста, будьте осторожны, чтобы оставить комментарий.

-1

Решение

== Оператор в вашем классе битов содержит ошибку:

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 > 0.0001f)

Функция отсечения должна выполняться до тех пор, пока в начале или конце установлены биты, поэтому измените IsClippingCandidate ИЛИ два вместе и возвращают 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;
}

Если обе точки находятся за пределами заданной линии отсечения, то эта линия невидима.

1

Другие решения