Rasagar/Library/PackageCache/com.unity.probuilder/Runtime/Core/Clipping.cs

131 lines
5.1 KiB
C#
Raw Normal View History

2024-08-26 13:07:20 -07:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.ProBuilder
{
/// <summary>
/// Rect to line segment clipping implementation.
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
/// </remarks>
static class Clipping
{
[System.Flags]
enum OutCode
{
Inside = 0, // 0000
Left = 1, // 0001
Right = 2, // 0010
Bottom = 4, // 0100
Top = 8, // 1000
}
// Compute the bit code for a point (x, y) using the clip rectangle
// bounded diagonally by (xmin, ymin), and (xmax, ymax)
static OutCode ComputeOutCode(Rect rect, float x, float y)
{
OutCode code = OutCode.Inside; // initialised as being inside of [[clip window]]
if (x < rect.xMin) // to the left of clip window
code |= OutCode.Left;
else if (x > rect.xMax) // to the right of clip window
code |= OutCode.Right;
if (y < rect.yMin) // below the clip window
code |= OutCode.Bottom;
else if (y > rect.yMax) // above the clip window
code |= OutCode.Top;
return code;
}
// CohenSutherland clipping algorithm clips a line from
// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
// diagonal from (xmin, ymin) to (xmax, ymax).
internal static bool RectContainsLineSegment(Rect rect, float x0, float y0, float x1, float y1)
{
// compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
OutCode outcode0 = ComputeOutCode(rect, x0, y0);
OutCode outcode1 = ComputeOutCode(rect, x1, y1);
bool accept = false;
while (true)
{
if ((outcode0 | outcode1) == OutCode.Inside)
{
// bitwise OR is 0: both points inside window; trivially accept and exit loop
accept = true;
break;
}
else if ((outcode0 & outcode1) != OutCode.Inside)
{
// bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP,
// or BOTTOM), so both must be outside window; exit loop (accept is false)
break;
}
else
{
// failed both tests, so calculate the line segment to clip
// from an outside point to an intersection with clip edge
float x = 0f, y = 0f;
// At least one endpoint is outside the clip rectangle; pick it.
OutCode outcodeOut = outcode0 != OutCode.Inside ? outcode0 : outcode1;
// Now find the intersection point;
// use formulas:
// slope = (y1 - y0) / (x1 - x0)
// x = x0 + (1 / slope) * (ym - y0), where ym is ymin or ymax
// y = y0 + slope * (xm - x0), where xm is xmin or xmax
// No need to worry about divide-by-zero because, in each case, the
// outcode bit being tested guarantees the denominator is non-zero
if ((outcodeOut & OutCode.Top) == OutCode.Top)
{
// point is above the clip window
x = x0 + (x1 - x0) * (rect.yMax - y0) / (y1 - y0);
y = rect.yMax;
}
else if ((outcodeOut & OutCode.Bottom) == OutCode.Bottom)
{
// point is below the clip window
x = x0 + (x1 - x0) * (rect.yMin - y0) / (y1 - y0);
y = rect.yMin;
}
else if ((outcodeOut & OutCode.Right) == OutCode.Right)
{
// point is to the right of clip window
y = y0 + (y1 - y0) * (rect.xMax - x0) / (x1 - x0);
x = rect.xMax;
}
else if ((outcodeOut & OutCode.Left) == OutCode.Left)
{
// point is to the left of clip window
y = y0 + (y1 - y0) * (rect.xMin - x0) / (x1 - x0);
x = rect.xMin;
}
// Now we move outside point to intersection point to clip
// and get ready for next pass.
if (outcodeOut == outcode0)
{
x0 = x;
y0 = y;
outcode0 = ComputeOutCode(rect, x0, y0);
}
else
{
x1 = x;
y1 = y;
outcode1 = ComputeOutCode(rect, x1, y1);
}
}
}
return accept;
}
}
}