forked from BilalY/Rasagar
131 lines
5.1 KiB
C#
131 lines
5.1 KiB
C#
|
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;
|
|||
|
}
|
|||
|
|
|||
|
// Cohen–Sutherland 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;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|