Rasagar/Library/PackageCache/com.unity.probuilder/Runtime/Core/Clipping.cs
2024-08-26 23:07:20 +03:00

131 lines
5.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}