static JoiningInfo ForeseeJoining(BezierSegment end, BezierSegment start, float halfThickness, float endSegmentLength) { JoiningInfo joinInfo = new JoiningInfo(); // The joining generates the vertices at both ends as well as the joining itself joinInfo.JoinPos = end.P3; joinInfo.TanAtEnd = VectorUtils.EvalTangent(end, 1.0f); joinInfo.NormAtEnd = Vector2.Perpendicular(joinInfo.TanAtEnd); joinInfo.TanAtStart = VectorUtils.EvalTangent(start, 0.0f); joinInfo.NormAtStart = Vector2.Perpendicular(joinInfo.TanAtStart); // If the tangents are continuous at the join location, we don't have // to generate a corner, we do a "simple" join by just connecting the vertices // from the two segments directly float cosAngleBetweenTans = Vector2.Dot(joinInfo.TanAtEnd, joinInfo.TanAtStart); joinInfo.SimpleJoin = Mathf.Approximately(Mathf.Abs(cosAngleBetweenTans), 1.0f); if (joinInfo.SimpleJoin) { return(null); } joinInfo.PosThicknessEnd = joinInfo.JoinPos + joinInfo.NormAtEnd * halfThickness; joinInfo.NegThicknessEnd = joinInfo.JoinPos - joinInfo.NormAtEnd * halfThickness; joinInfo.PosThicknessStart = joinInfo.JoinPos + joinInfo.NormAtStart * halfThickness; joinInfo.NegThicknessStart = joinInfo.JoinPos - joinInfo.NormAtStart * halfThickness; if (joinInfo.SimpleJoin) { joinInfo.PosThicknessClosingPoint = Vector2.LerpUnclamped(joinInfo.PosThicknessEnd, joinInfo.PosThicknessStart, 0.5f); joinInfo.NegThicknessClosingPoint = Vector2.LerpUnclamped(joinInfo.NegThicknessEnd, joinInfo.NegThicknessStart, 0.5f); } else { joinInfo.PosThicknessClosingPoint = VectorUtils.IntersectLines(joinInfo.PosThicknessEnd, joinInfo.PosThicknessEnd + joinInfo.TanAtEnd, joinInfo.PosThicknessStart, joinInfo.PosThicknessStart + joinInfo.TanAtStart); joinInfo.NegThicknessClosingPoint = VectorUtils.IntersectLines(joinInfo.NegThicknessEnd, joinInfo.NegThicknessEnd + joinInfo.TanAtEnd, joinInfo.NegThicknessStart, joinInfo.NegThicknessStart + joinInfo.TanAtStart); if (float.IsInfinity(joinInfo.PosThicknessClosingPoint.x) || float.IsInfinity(joinInfo.PosThicknessClosingPoint.y)) { joinInfo.PosThicknessClosingPoint = joinInfo.JoinPos; } if (float.IsInfinity(joinInfo.NegThicknessClosingPoint.x) || float.IsInfinity(joinInfo.NegThicknessClosingPoint.y)) { joinInfo.NegThicknessClosingPoint = joinInfo.JoinPos; } } // Should we round the positive thickness side or the negative thickness side? joinInfo.RoundPosThickness = PointOnTheLeftOfLine(Vector2.zero, joinInfo.TanAtEnd, joinInfo.TanAtStart); // Inner corner vertex should be calculated by intersection of the inner segments Vector2[] startTrail = null, endTrail = null; Vector2 intersectionOnStart = Vector2.zero, intersectionOnEnd = Vector2.zero; if (!joinInfo.SimpleJoin) { BezierSegment endFlipped = VectorUtils.FlipSegment(end); Vector2 thicknessClosingPoint = joinInfo.RoundPosThickness ? joinInfo.PosThicknessClosingPoint : joinInfo.NegThicknessClosingPoint; Vector2 meetingPoint = end.P3; Vector2 thicknessDiagonalEnd = meetingPoint + (thicknessClosingPoint - meetingPoint) * 10.0f; startTrail = LineBezierThicknessIntersect( start, joinInfo.RoundPosThickness ? -halfThickness : halfThickness, meetingPoint, thicknessDiagonalEnd, out joinInfo.InnerCornerDistFromStart, out intersectionOnStart); endTrail = LineBezierThicknessIntersect( endFlipped, joinInfo.RoundPosThickness ? halfThickness : -halfThickness, meetingPoint, thicknessDiagonalEnd, out joinInfo.InnerCornerDistToEnd, out intersectionOnEnd); } bool intersectionFound = false; if ((startTrail != null) && (endTrail != null)) { var intersect = VectorUtils.IntersectLines(startTrail[0], startTrail[1], endTrail[0], endTrail[1]); var isOnStartTrail = PointOnLineIsWithinSegment(startTrail[0], startTrail[1], intersect); var isOnEndTrail = PointOnLineIsWithinSegment(endTrail[0], endTrail[1], intersect); if (!float.IsInfinity(intersect.x) && isOnStartTrail && isOnEndTrail) { var vStart = intersectionOnStart - intersect; var vEnd = intersectionOnEnd - intersect; joinInfo.InnerCornerDistFromStart += (vStart == Vector2.zero) ? 0.0f : vStart.magnitude; joinInfo.InnerCornerDistToEnd += (vEnd == Vector2.zero) ? 0.0f : vEnd.magnitude; joinInfo.InnerCornerDistToEnd = endSegmentLength - joinInfo.InnerCornerDistToEnd; joinInfo.InnerCornerVertex = intersect; // Found it! intersectionFound = true; } } if (!intersectionFound) { joinInfo.InnerCornerVertex = joinInfo.JoinPos + ((joinInfo.TanAtStart - joinInfo.TanAtEnd) / 2.0f).normalized * halfThickness; joinInfo.InnerCornerDistFromStart = 0; joinInfo.InnerCornerDistToEnd = endSegmentLength; } return(joinInfo); }