public static float RaySegment()

in MREUnityRuntimeLib/ProceduralToolkit/Geometry/Distance2D.cs [404:537]


		public static float RaySegment(Vector2 rayOrigin, Vector2 rayDirection, Vector2 segmentA, Vector2 segmentB)
		{
			Vector2 segmentAToOrigin = rayOrigin - segmentA;
			Vector2 segmentDirection = segmentB - segmentA;
			float denominator = VectorE.PerpDot(rayDirection, segmentDirection);
			float perpDotA = VectorE.PerpDot(rayDirection, segmentAToOrigin);
			// Normalized direction gives more stable results 
			float perpDotB = VectorE.PerpDot(segmentDirection.normalized, segmentAToOrigin);

			if (Mathf.Abs(denominator) < Geometry.Epsilon)
			{
				// Parallel
				float segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
				Vector2 originToSegmentB = segmentB - rayOrigin;
				float segmentBProjection = Vector2.Dot(rayDirection, originToSegmentB);
				if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
				{
					// Not collinear
					if (segmentAProjection > -Geometry.Epsilon)
					{
						float distanceSqr = segmentAToOrigin.sqrMagnitude - segmentAProjection*segmentAProjection;
						// distanceSqr can be negative
						return distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr);
					}
					if (segmentBProjection > -Geometry.Epsilon)
					{
						float distanceSqr = originToSegmentB.sqrMagnitude - segmentBProjection*segmentBProjection;
						// distanceSqr can be negative
						return distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr);
					}

					if (segmentAProjection > segmentBProjection)
					{
						return Vector2.Distance(rayOrigin, segmentA);
					}
					return Vector2.Distance(rayOrigin, segmentB);
				}
				// Collinear
				if (segmentAProjection > -Geometry.Epsilon || segmentBProjection > -Geometry.Epsilon)
				{
					// Point or segment intersection
					return 0;
				}
				// No intersection
				return segmentAProjection > segmentBProjection ? -segmentAProjection : -segmentBProjection;
			}

			// Not parallel
			float rayDistance = perpDotB/denominator;
			float segmentDistance = perpDotA/denominator;
			if (rayDistance < -Geometry.Epsilon ||
				segmentDistance < -Geometry.Epsilon || segmentDistance > 1 + Geometry.Epsilon)
			{
				// No intersection
				bool codirected = Vector2.Dot(rayDirection, segmentDirection) > 0;
				Vector2 segmentBToOrigin;
				if (!codirected)
				{
					PTUtils.Swap(ref segmentA, ref segmentB);
					segmentDirection = -segmentDirection;
					segmentBToOrigin = segmentAToOrigin;
					segmentAToOrigin = rayOrigin - segmentA;
					segmentDistance = 1 - segmentDistance;
				}
				else
				{
					segmentBToOrigin = rayOrigin - segmentB;
				}

				float segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
				float segmentBProjection = -Vector2.Dot(rayDirection, segmentBToOrigin);
				bool segmentAOnRay = segmentAProjection > -Geometry.Epsilon;
				bool segmentBOnRay = segmentBProjection > -Geometry.Epsilon;
				if (segmentAOnRay && segmentBOnRay)
				{
					if (segmentDistance < 0)
					{
						Vector2 rayPoint = rayOrigin + rayDirection*segmentAProjection;
						Vector2 segmentPoint = segmentA;
						return Vector2.Distance(rayPoint, segmentPoint);
					}
					else
					{
						Vector2 rayPoint = rayOrigin + rayDirection*segmentBProjection;
						Vector2 segmentPoint = segmentB;
						return Vector2.Distance(rayPoint, segmentPoint);
					}
				}
				else if (!segmentAOnRay && segmentBOnRay)
				{
					if (segmentDistance < 0)
					{
						Vector2 rayPoint = rayOrigin;
						Vector2 segmentPoint = segmentA;
						return Vector2.Distance(rayPoint, segmentPoint);
					}
					else if (segmentDistance > 1 + Geometry.Epsilon)
					{
						Vector2 rayPoint = rayOrigin + rayDirection*segmentBProjection;
						Vector2 segmentPoint = segmentB;
						return Vector2.Distance(rayPoint, segmentPoint);
					}
					else
					{
						Vector2 rayPoint = rayOrigin;
						float originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
						Vector2 segmentPoint = segmentA + segmentDirection*originProjection/segmentDirection.sqrMagnitude;
						return Vector2.Distance(rayPoint, segmentPoint);
					}
				}
				else
				{
					// Not on ray
					Vector2 rayPoint = rayOrigin;
					float originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
					float sqrSegmentLength = segmentDirection.sqrMagnitude;
					if (originProjection < 0)
					{
						return Vector2.Distance(rayPoint, segmentA);
					}
					else if (originProjection > sqrSegmentLength)
					{
						return Vector2.Distance(rayPoint, segmentB);
					}
					else
					{
						Vector2 segmentPoint = segmentA + segmentDirection*originProjection/sqrSegmentLength;
						return Vector2.Distance(rayPoint, segmentPoint);
					}
				}
			}
			// Point intersection
			return 0;
		}