这是Cohen-Sutherland代码:
public static Tuple<PointF, PointF> ClipSegment(RectangleF r, PointF p1, PointF p2)
{
//classify the endpoints of the line
var outCodeP1 = ComputeOutCode(p1, r);
var outCodeP2 = ComputeOutCode(p2, r);
var accept = false;
while (true)
{
// Case 1!
if ((outCodeP1 | outCodeP2) == OutCode.Inside)
{
accept = true;
break;
}
// Case 2!
if ((outCodeP1 & outCodeP2) != 0)
{
break;
}
//Case 3!
var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
// calculate the intersection of the line with the clipping rectangle using parametric line equations
var p = CalculateIntersection(r, p1, p2, outCode);
// update the point after clipping and recalculate outcode
if (outCode==outCodeP1)
{
p1 = p;
outCodeP1 = ComputeOutCode(p1, r);
}
else
{
p2 = p;
outCodeP2 = ComputeOutCode(p2, r);
}
}
// if clipping area contained a portion of the line
if (accept)
{
return new Tuple<PointF, PointF>(p1, p2);
}
// the line did not intersect the clipping area
return null;
}
案例1:两个端点都在裁剪区域内。
案例2:两个端点共享一个被排除的区域,它们之间的一条线不可能在裁剪区域内。
案例3:端点位于不同的区域,并且该段部分位于剪切矩形内,选择剪切矩形外的一个端点。
我尝试将所有片段都放在剪切窗口之外而不是内部。 有人能帮助我吗?
答案 0 :(得分:0)
在意识到找到剪切区域之外的段可能产生多个元组并更新方法的返回类型之后,只需要遍历逻辑并反转每个决策:
public static IEnumerable<Tuple<PointF, PointF>> ClipSegment(RectangleF r, PointF p1, PointF p2)
{
// classify the endpoints of the line
var outCodeP1 = ComputeOutCode(p1, r);
var outCodeP2 = ComputeOutCode(p2, r);
var results = new List<Tuple<PointF,PointF>>();
while (true)
{
// Case 1:
// both endpoints are within the clipping region
if ((outCodeP1 | outCodeP2) == OutCode.Inside)
{
//Completely clipped
break;
}
// Case 2:
// both endpoints share an excluded region, impossible for a line between them to be within the clipping region
if ((outCodeP1 & outCodeP2) != 0)
{
//Not clipped at all
results.Add(Tuple.Create(p1,p2));
break;
}
//Case 3: The endpoints are in different regions, and the segment is partially within
//the clipping rectangle Select one of the endpoints outside the clipping rectangle
var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
// calculate the intersection of the line with the clipping rectangle using parametric line equations
var p = CalculateIntersection(r, p1, p2, outCode);
// update the point after clipping and recalculate outcode
if (outCode==outCodeP1)
{
//Keep "discarded" segment
results.Add(Tuple.Create(p1,p));
p1 = p;
outCodeP1 = ComputeOutCode(p1, r);
}
else
{
//ditto
results.Add(Tuple.Create(p,p2));
p2 = p;
outCodeP2 = ComputeOutCode(p2, r);
}
}
return results;
}
您可以将调用代码更改为:
var clipped = CohenSutherland.ClipSegment(_rect, p1, p2);
newLines.AddRange(clipped);
(因为我们现在保证始终返回一个列表,即使是空的,也不再需要null
检查。)
我们可能希望考虑的一个改进是将函数更改为迭代器并使用yield return
而不是在内部维护单独的列表。