Line clipping: Difference between revisions

Content deleted Content added
No edit summary
Line 289:
{
return "Liang-Barsky algorithm";
}
}
</nowiki></pre>
 
== Fast-Clipping ==
C# implementation for Fast-Clipping algorithm
<pre><nowiki>
internal sealed class FastClipping : IClippingAlgorithm
{
private Vector2 _clipMin, _clipMax;
 
public IEnumerable<Vector2> GetBoundingPolygon()
{
yield return _clipMin;
yield return new Vector2(_clipMax.X, _clipMin.Y);
yield return _clipMax;
yield return new Vector2(_clipMin.X, _clipMax.Y);
}
 
public void SetBoundingRectangle(Vector2 start, Vector2 end)
{
_clipMin = start;
_clipMax = end;
}
 
public void SetBoundingPolygon(IEnumerable<Vector2> points)
{
throw new NotSupportedException("see Capabilities =)");
}
 
#region отсечения концов отрезка
 
private void clipStartTop(ref Line line)
{
line.Start.X += line.Dx * (_clipMin.Y - line.Start.Y) / line.Dy;
line.Start.Y = _clipMin.Y;
}
 
private void clipStartBottom(ref Line line)
{
line.Start.X += line.Dx * (_clipMax.Y - line.Start.Y) / line.Dy;
line.Start.Y = _clipMax.Y;
}
 
private void clipStartRight(ref Line line)
{
line.Start.Y += line.Dy * (_clipMax.X - line.Start.X) / line.Dx;
line.Start.X = _clipMax.X;
}
 
private void clipStartLeft(ref Line line)
{
line.Start.Y += line.Dy * (_clipMin.X - line.Start.X) / line.Dx;
line.Start.X = _clipMin.X;
}
 
private void clipEndTop(ref Line line)
{
line.End.X += line.Dx * (_clipMin.Y - line.End.Y) / line.Dy;
line.End.Y = _clipMin.Y;
}
 
private void clipEndBottom(ref Line line)
{
line.End.X += line.Dx * (_clipMax.Y - line.End.Y) / line.Dy;
line.End.Y = _clipMax.Y;
}
 
private void clipEndRight(ref Line line)
{
line.End.Y += line.Dy * (_clipMax.X - line.End.X) / line.Dx;
line.End.X = _clipMax.X;
}
 
private void clipEndLeft(ref Line line)
{
line.End.Y += line.Dy * (_clipMin.X - line.End.X) / line.Dx;
line.End.X = _clipMin.X;
}
 
#endregion
 
public bool ClipLine(ref Line line)
{
int lineCode = 0;
 
if (line.End.Y < _clipMin.Y) lineCode |= 8;
else if (line.End.Y > _clipMax.Y) lineCode |= 4;
 
if (line.End.X > _clipMax.X) lineCode |= 2;
else if (line.End.X < _clipMin.X) lineCode |= 1;
 
if (line.Start.Y < _clipMin.Y) lineCode |= 128;
else if (line.Start.Y > _clipMax.Y) lineCode |= 64;
 
if (line.Start.X > _clipMax.X) lineCode |= 32;
else if (line.Start.X < _clipMin.X) lineCode |= 16;
 
// 9 - 8 - A
// | | |
// 1 - 0 - 2
// | | |
// 5 - 4 - 6
switch (lineCode)
{
// Из центра
case 0x00: return true;
 
case 0x01: clipEndLeft(ref line); return true;
 
case 0x02: clipEndRight(ref line); return true;
 
case 0x04: clipEndBottom(ref line); return true;
 
case 0x05:
clipEndLeft(ref line);
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
return true;
 
case 0x06:
clipEndRight(ref line);
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
return true;
 
case 0x08: clipEndTop(ref line); return true;
 
case 0x09:
clipEndLeft(ref line);
if (line.End.Y < _clipMin.Y) clipEndTop(ref line);
return true;
 
case 0x0A:
clipEndRight(ref line);
if (line.End.Y < _clipMin.Y) clipEndTop(ref line);
return true;
 
// Слева
case 0x10: clipStartLeft(ref line); return true;
 
case 0x12: clipStartLeft(ref line); clipEndRight(ref line); return true;
 
case 0x14:
clipStartLeft(ref line);
if (line.Start.Y > _clipMax.Y) return false;
clipEndBottom(ref line);
return true;
 
case 0x16:
clipStartLeft(ref line);
if (line.Start.Y > _clipMax.Y) return false;
clipEndBottom(ref line);
if (line.End.X > _clipMax.X) clipEndRight(ref line);
return true;
 
case 0x18:
clipStartLeft(ref line);
if (line.Start.Y < _clipMin.Y) return false;
clipEndTop(ref line);
return true;
 
case 0x1A:
clipStartLeft(ref line);
if (line.Start.Y < _clipMin.Y) return false;
clipEndTop(ref line);
if (line.End.X > _clipMax.X) clipEndRight(ref line);
return true;
 
// Справа
case 0x20: clipStartRight(ref line); return true;
 
case 0x21: clipStartRight(ref line); clipEndLeft(ref line); return true;
 
case 0x24:
clipStartRight(ref line);
if (line.Start.Y > _clipMax.Y) return false;
clipEndBottom(ref line);
return true;
 
case 0x25:
clipStartRight(ref line);
if (line.Start.Y > _clipMax.Y) return false;
clipEndBottom(ref line);
if (line.End.X < _clipMin.X) clipEndLeft(ref line);
return true;
 
case 0x28:
clipStartRight(ref line);
if (line.Start.Y < _clipMin.Y) return false;
clipEndTop(ref line);
return true;
 
case 0x29:
clipStartRight(ref line);
if (line.Start.Y < _clipMin.Y) return false;
clipEndTop(ref line);
if (line.End.X < _clipMin.X) clipEndLeft(ref line);
return true;
 
// Снизу
case 0x40: clipStartBottom(ref line); return true;
 
case 0x41:
clipStartBottom(ref line);
if (line.Start.X < _clipMin.X) return false;
clipEndLeft(ref line);
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
return true;
 
case 0x42:
clipStartBottom(ref line);
if (line.Start.X > _clipMax.X) return false;
clipEndRight(ref line);
return true;
 
case 0x48:
clipStartBottom(ref line);
clipEndTop(ref line);
return true;
 
case 0x49:
clipStartBottom(ref line);
if (line.Start.X < _clipMin.X) return false;
clipEndLeft(ref line);
if (line.End.Y < _clipMin.Y) clipEndTop(ref line);
return true;
 
case 0x4A:
clipStartBottom(ref line);
if (line.Start.X > _clipMax.X) return false;
clipEndRight(ref line);
if (line.End.Y < _clipMin.Y) clipEndTop(ref line);
return true;
 
// Снизу слева
case 0x50:
clipStartLeft(ref line);
if (line.Start.Y > _clipMax.Y) clipStartBottom(ref line);
return true;
 
case 0x52:
clipEndRight(ref line);
if (line.End.Y > _clipMax.Y) return false;
clipStartBottom(ref line);
if (line.Start.X < _clipMin.X) clipStartLeft(ref line);
return true;
 
case 0x58:
clipEndTop(ref line);
if (line.End.X < _clipMin.X) return false;
clipStartBottom(ref line);
if (line.Start.X < _clipMin.X) clipStartLeft(ref line);
return true;
 
case 0x5A:
clipStartLeft(ref line);
if (line.Start.Y < _clipMin.Y) return false;
clipEndRight(ref line);
if (line.End.Y > _clipMax.Y) return false;
if (line.Start.Y > _clipMax.Y) clipStartBottom(ref line);
if (line.End.Y < _clipMin.Y) clipEndTop(ref line);
return true;
 
// Снизу-справа
case 0x60:
clipStartRight(ref line);
if (line.Start.Y > _clipMax.Y) clipStartBottom(ref line);
return true;
 
case 0x61:
clipEndLeft(ref line);
if (line.End.Y > _clipMax.Y) return false;
clipStartBottom(ref line);
if (line.Start.X > _clipMax.X) clipStartRight(ref line);
return true;
 
case 0x68:
clipEndTop(ref line);
if (line.End.X > _clipMax.X) return false;
clipStartRight(ref line);
if (line.Start.Y > _clipMax.Y) clipStartBottom(ref line);
return true;
 
case 0x69:
clipEndLeft(ref line);
if (line.End.Y > _clipMax.Y) return false;
clipStartRight(ref line);
if (line.Start.Y < _clipMin.Y) return false;
if (line.End.Y < _clipMin.Y) clipEndTop(ref line);
if (line.Start.Y > _clipMax.Y) clipStartBottom(ref line);
return true;
 
// Сверху
case 0x80: clipStartTop(ref line); return true;
 
case 0x81:
clipStartTop(ref line);
if (line.Start.X < _clipMin.X) return false;
clipEndLeft(ref line);
return true;
 
case 0x82:
clipStartTop(ref line);
if (line.Start.X > _clipMax.X) return false;
clipEndRight(ref line);
return true;
 
case 0x84:
clipStartTop(ref line);
clipEndBottom(ref line);
return true;
 
case 0x85:
clipStartTop(ref line);
if (line.Start.X < _clipMin.X) return false;
clipEndLeft(ref line);
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
return true;
 
case 0x86:
clipStartTop(ref line);
if (line.Start.X > _clipMax.X) return false;
clipEndRight(ref line);
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
return true;
 
// Сверху-слева
case 0x90:
clipStartLeft(ref line);
if (line.Start.Y < _clipMin.Y) clipStartTop(ref line);
return true;
 
case 0x92:
clipEndRight(ref line);
if (line.End.Y < _clipMin.Y) return false;
clipStartTop(ref line);
if (line.Start.X < _clipMin.X) clipStartLeft(ref line);
return true;
 
case 0x94:
clipEndBottom(ref line);
if (line.End.X < _clipMin.X) return false;
clipStartLeft(ref line);
if (line.Start.Y < _clipMin.Y) clipStartTop(ref line);
return true;
 
case 0x96:
clipStartLeft(ref line);
if (line.Start.Y > _clipMax.Y) return false;
clipEndRight(ref line);
if (line.End.Y < _clipMin.Y) return false;
if (line.Start.Y < _clipMin.Y) clipStartTop(ref line);
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
return true;
 
// Сверху-справа
case 0xA0:
clipStartRight(ref line);
if (line.Start.Y < _clipMin.Y) clipStartTop(ref line);
return true;
 
case 0xA1:
clipEndLeft(ref line);
if (line.End.Y < _clipMin.Y) return false;
clipStartTop(ref line);
if (line.Start.X > _clipMax.X) clipStartRight(ref line);
return true;
 
case 0xA4:
clipEndBottom(ref line);
if (line.End.X > _clipMax.X) return false;
clipStartRight(ref line);
if (line.Start.Y < _clipMin.Y) clipStartTop(ref line);
return true;
 
case 0xA5:
clipEndLeft(ref line);
if (line.End.Y < _clipMin.Y) return false;
clipStartRight(ref line);
if (line.Start.Y > _clipMax.Y) return false;
if (line.End.Y > _clipMax.Y) clipEndBottom(ref line);
if (line.Start.Y < _clipMin.Y) clipStartTop(ref line);
return true;
}
 
return false;
}
 
public ClippingCapabilities Capablities { get { return ClippingCapabilities.RectangleWindow; } }
 
public override string ToString()
{
return "Fast-Clipping algorithm";
}
}