public static void SegmentSegment()

in MREUnityRuntimeLib/ProceduralToolkit/Geometry/Closest2D.cs [844:1092]


		public static void SegmentSegment(Vector2 segment1A, Vector2 segment1B, Vector2 segment2A, Vector2 segment2B,
			out Vector2 segment1Point, out Vector2 segment2Point)
		{
			Vector2 from2ATo1A = segment1A - segment2A;
			Vector2 direction1 = segment1B - segment1A;
			Vector2 direction2 = segment2B - segment2A;
			float segment1Length = direction1.magnitude;
			float segment2Length = direction2.magnitude;

			bool segment1IsAPoint = segment1Length < Geometry.Epsilon;
			bool segment2IsAPoint = segment2Length < Geometry.Epsilon;
			if (segment1IsAPoint && segment2IsAPoint)
			{
				if (segment1A == segment2A)
				{
					segment1Point = segment2Point = segment1A;
					return;
				}
				segment1Point = segment1A;
				segment2Point = segment2A;
				return;
			}
			if (segment1IsAPoint)
			{
				direction2.Normalize();
				segment1Point = segment1A;
				segment2Point = PointSegment(segment1A, segment2A, segment2B, direction2, segment2Length);
				return;
			}
			if (segment2IsAPoint)
			{
				direction1.Normalize();
				segment1Point = PointSegment(segment2A, segment1A, segment1B, direction1, segment1Length);
				segment2Point = segment2A;
				return;
			}

			direction1.Normalize();
			direction2.Normalize();
			float denominator = VectorE.PerpDot(direction1, direction2);
			float perpDot1 = VectorE.PerpDot(direction1, from2ATo1A);
			float perpDot2 = VectorE.PerpDot(direction2, from2ATo1A);

			if (Mathf.Abs(denominator) < Geometry.Epsilon)
			{
				// Parallel
				bool codirected = Vector2.Dot(direction1, direction2) > 0;
				if (Mathf.Abs(perpDot1) > Geometry.Epsilon || Mathf.Abs(perpDot2) > Geometry.Epsilon)
				{
					// Not collinear
					Vector2 from1ATo2B;
					if (!codirected)
					{
						PTUtils.Swap(ref segment2A, ref segment2B);
						direction2 = -direction2;
						from1ATo2B = -from2ATo1A;
						from2ATo1A = segment1A - segment2A;
					}
					else
					{
						from1ATo2B = segment2B - segment1A;
					}
					float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
					float segment2BProjection = Vector2.Dot(direction1, from1ATo2B);

					bool segment2AIsAfter1A = segment2AProjection > -Geometry.Epsilon;
					bool segment2BIsAfter1A = segment2BProjection > -Geometry.Epsilon;
					if (!segment2AIsAfter1A && !segment2BIsAfter1A)
					{
						//           1A------1B
						// 2A------2B
						segment1Point = segment1A;
						segment2Point = segment2B;
						return;
					}
					bool segment2AIsBefore1B = segment2AProjection < segment1Length + Geometry.Epsilon;
					bool segment2BIsBefore1B = segment2BProjection < segment1Length + Geometry.Epsilon;
					if (!segment2AIsBefore1B && !segment2BIsBefore1B)
					{
						// 1A------1B
						//           2A------2B
						segment1Point = segment1B;
						segment2Point = segment2A;
						return;
					}

					if (segment2AIsAfter1A && segment2BIsBefore1B)
					{
						// 1A------1B
						//   2A--2B
						segment1Point = segment1A + direction1*segment2AProjection;
						segment2Point = segment2A;
						return;
					}

					if (segment2AIsAfter1A) // && segment2AIsBefore1B && !segment2BIsBefore1B)
					{
						// 1A------1B
						//     2A------2B
						segment1Point = segment1A + direction1*segment2AProjection;
						segment2Point = segment2A;
						return;
					}
					else
					{
						//   1A------1B
						// 2A----2B
						// 2A----------2B
						segment1Point = segment1A;
						float segment1AProjection = Vector2.Dot(direction2, from2ATo1A);
						segment2Point = segment2A + direction2*segment1AProjection;
						return;
					}
				}
				// Collinear

				if (codirected)
				{
					// Codirected
					float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
					if (segment2AProjection > -Geometry.Epsilon)
					{
						// 1A------1B
						//     2A------2B
						SegmentSegmentCollinear(segment1A, segment1B, segment2A, out segment1Point, out segment2Point);
						return;
					}
					else
					{
						//     1A------1B
						// 2A------2B
						SegmentSegmentCollinear(segment2A, segment2B, segment1A, out segment2Point, out segment1Point);
						return;
					}
				}
				else
				{
					// Contradirected
					float segment2BProjection = Vector2.Dot(direction1, segment2B - segment1A);
					if (segment2BProjection > -Geometry.Epsilon)
					{
						// 1A------1B
						//     2B------2A
						SegmentSegmentCollinear(segment1A, segment1B, segment2B, out segment1Point, out segment2Point);
						return;
					}
					else
					{
						//     1A------1B
						// 2B------2A
						SegmentSegmentCollinear(segment2B, segment2A, segment1A, out segment2Point, out segment1Point);
						return;
					}
				}
			}

			// Not parallel
			float distance1 = perpDot2/denominator;
			float distance2 = perpDot1/denominator;
			if (distance1 < -Geometry.Epsilon || distance1 > segment1Length + Geometry.Epsilon ||
				distance2 < -Geometry.Epsilon || distance2 > segment2Length + Geometry.Epsilon)
			{
				// No intersection
				bool codirected = Vector2.Dot(direction1, direction2) > 0;
				Vector2 from1ATo2B;
				if (!codirected)
				{
					PTUtils.Swap(ref segment2A, ref segment2B);
					direction2 = -direction2;
					from1ATo2B = -from2ATo1A;
					from2ATo1A = segment1A - segment2A;
					distance2 = segment2Length - distance2;
				}
				else
				{
					from1ATo2B = segment2B - segment1A;
				}

				float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
				float segment2BProjection = Vector2.Dot(direction1, from1ATo2B);

				bool segment2AIsAfter1A = segment2AProjection > -Geometry.Epsilon;
				bool segment2BIsBefore1B = segment2BProjection < segment1Length + Geometry.Epsilon;
				bool segment2AOnSegment1 = segment2AIsAfter1A && segment2AProjection < segment1Length + Geometry.Epsilon;
				bool segment2BOnSegment1 = segment2BProjection > -Geometry.Epsilon && segment2BIsBefore1B;
				if (segment2AOnSegment1 && segment2BOnSegment1)
				{
					if (distance2 < -Geometry.Epsilon)
					{
						segment1Point = segment1A + direction1*segment2AProjection;
						segment2Point = segment2A;
					}
					else
					{
						segment1Point = segment1A + direction1*segment2BProjection;
						segment2Point = segment2B;
					}
				}
				else if (!segment2AOnSegment1 && !segment2BOnSegment1)
				{
					if (!segment2AIsAfter1A && !segment2BIsBefore1B)
					{
						segment1Point = distance1 < -Geometry.Epsilon ? segment1A : segment1B;
					}
					else
					{
						// Not on segment
						segment1Point = segment2AIsAfter1A ? segment1B : segment1A;
					}
					float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
					segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
					segment2Point = segment2A + direction2*segment1PointProjection;
				}
				else if (segment2AOnSegment1)
				{
					if (distance2 < -Geometry.Epsilon)
					{
						segment1Point = segment1A + direction1*segment2AProjection;
						segment2Point = segment2A;
					}
					else
					{
						segment1Point = segment1B;
						float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
						segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
						segment2Point = segment2A + direction2*segment1PointProjection;
					}
				}
				else
				{
					if (distance2 > segment2Length + Geometry.Epsilon)
					{
						segment1Point = segment1A + direction1*segment2BProjection;
						segment2Point = segment2B;
					}
					else
					{
						segment1Point = segment1A;
						float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
						segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
						segment2Point = segment2A + direction2*segment1PointProjection;
					}
				}
				return;
			}

			// Point intersection
			segment1Point = segment2Point = segment1A + direction1*distance1;
		}