private static void AddBezierPoints(List <Vector3> meshPoints, Vector3 start, Quaternion startRotation, Vector3 end, Quaternion endRotation) { // Add bezier points between "start" and "end" Vector3 intersectionPoint; bool intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, start, startRotation * Vector3.right, end, endRotation * Vector3.right); if (!intersectionFound) { intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, start, Quaternion.Euler(new Vector3(0, 0, 180f) + startRotation.eulerAngles) * Vector3.right, end, Quaternion.Euler(new Vector3(0, 0, 180f) + endRotation.eulerAngles) * Vector3.right); } if (intersectionFound) { // Intersection found, draw the bezier curve float bezierLength = Math3d.GetBezierLength(start, intersectionPoint, end); float numberOfPoints = bezierLength * WayHelper.BEZIER_RESOLUTION; float step = 1.0f / numberOfPoints; bool doBreak = false; for (float time = step; time < 1.0f + step; time += step) { if (time > 1f) { time = 1f; doBreak = true; } Vector3 bezierPoint = Math3d.GetVectorInBezierAtTime(time, start, intersectionPoint, end); meshPoints.Add(bezierPoint); if (doBreak) { break; } } } else { // No intersection found for way points, just draw a straight line meshPoints.Add(end); } }
private static void GetBezierPoints(List <Vector3> meshPoints, WayReference way1, WayReference way2, Vector3 right, Vector3 leftWay2) { // Add bezier points between this ways "right" and next ways "left" point Vector3 intersectionPoint; bool intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, right, way1.transform.rotation * Vector3.right, leftWay2, way2.transform.rotation * Vector3.right); if (!intersectionFound) { intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, right, Quaternion.Euler(new Vector3(0, 0, 180f) + way1.transform.rotation.eulerAngles) * Vector3.right, leftWay2, Quaternion.Euler(new Vector3(0, 0, 180f) + way2.transform.rotation.eulerAngles) * Vector3.right); } if (intersectionFound) { // Intersection found, draw the bezier curve float bezierLength = Math3d.GetBezierLength(right, intersectionPoint, leftWay2); float numberOfPoints = bezierLength * WayHelper.BEZIER_RESOLUTION; float step = 1.0f / numberOfPoints; bool doBreak = false; for (float time = step; time < 1.0f + step; time += step) { if (time > 1f) { time = 1f; doBreak = true; } Vector3 bezierPoint = Math3d.GetVectorInBezierAtTime(time, right, intersectionPoint, leftWay2); meshPoints.Add(bezierPoint); if (doBreak) { break; } } } else { // No intersection found for way points, just draw a straight line meshPoints.Add(leftWay2); } }
static List <Vector3> getMeshPointsForComplexTwoWay(List <WayReference> wayReferences, List <Bounds> wayBounds, Pos pos) { // if (pos.Id == 945711788L) { // Debug.Break(); // } List <Vector3> meshPoints = new List <Vector3> (); // middle of intersection "pos" Vector3 intersectionPos = Game.getCameraPosition(pos); WayReference way1 = wayReferences [0]; Bounds way1Bounds = wayBounds [0]; bool way1IsNode1 = way1.isNode1(pos); Quaternion way1Rotation = way1IsNode1 ? way1.transform.rotation : Quaternion.Euler(way1.transform.rotation.eulerAngles + new Vector3(0f, 0f, 180f)); bool way1Small = way1.way.CarWay && way1.SmallWay; Vector3 way1Left = intersectionPos + way1Rotation * new Vector3(way1Small ? way1.transform.localScale.x / 2f : way1.transform.localScale.y / 2f, -way1.transform.localScale.y / 2f, 0f); Bounds leftCheckPoint = new Bounds(way1Left + (way1Rotation * new Vector3(way1Small ? way1.transform.localScale.x / 20f : way1.transform.localScale.y / 20f, way1.transform.localScale.y / 20f, 0f)) - new Vector3(0f, 0f, 0.1f), new Vector3(way1Small ? way1.transform.localScale.x / 10f : way1.transform.localScale.y / 10f, way1.transform.localScale.y / 10f, way1.transform.localScale.y / 10f)); // DebugFn.DrawBounds (leftCheckPoint); WayReference way2; Bounds way2Bounds = wayBounds [1]; bool way2IsNode1; Quaternion way2Rotation; if (way2Bounds.Intersects(leftCheckPoint)) { way1 = wayReferences [1]; way1Bounds = wayBounds [1]; way1IsNode1 = way1.isNode1(pos); way1Rotation = way1IsNode1 ? way1.transform.rotation : Quaternion.Euler(way1.transform.rotation.eulerAngles + new Vector3(0f, 0f, 180f)); way1Left = intersectionPos + way1Rotation * new Vector3(way1Small ? way1.transform.localScale.x / 2f : way1.transform.localScale.y / 2f, -way1.transform.localScale.y / 2f, 0f); way2 = wayReferences [0]; way2Bounds = wayBounds [0]; way2IsNode1 = way2.isNode1(pos); way2Rotation = way2IsNode1 ? way2.transform.rotation : Quaternion.Euler(way2.transform.rotation.eulerAngles + new Vector3(0f, 0f, 180f)); } else { way2 = wayReferences [1]; way2Bounds = wayBounds [1]; way2IsNode1 = way2.isNode1(pos); way2Rotation = way2IsNode1 ? way2.transform.rotation : Quaternion.Euler(way2.transform.rotation.eulerAngles + new Vector3(0f, 0f, 180f)); } bool way2IsSmallWay = way2.way.CarWay && way2.SmallWay; Vector3 way2Right = intersectionPos + way2Rotation * new Vector3(way2IsSmallWay ? way2.transform.localScale.x / 2f : way2.transform.localScale.y / 2f, way2.transform.localScale.y / 2f, 0f); // Angles looking towards intersection of ways Vector3 way1IntersectionAngle = (way1IsNode1 ? WayHelper.DEGREES_90_VECTOR : WayHelper.DEGREES_270_VECTOR) + way1.transform.rotation.eulerAngles; Vector3 way2IntersectionAngle = (way2IsNode1 ? WayHelper.DEGREES_270_VECTOR : WayHelper.DEGREES_90_VECTOR) + way2.transform.rotation.eulerAngles; // Get intersection point Vector3 intersectionPoint; bool intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, way1Left, Quaternion.Euler(way1IntersectionAngle) * Vector3.right, way2Right, Quaternion.Euler(way2IntersectionAngle) * Vector3.right); // DebugFn.square (intersectionPoint); if (!intersectionFound) { // TODO DEBUG ONLY // DebugFn.arrow (way1Left, way1IntersectionAngle, new Vector3(0.1f, 0f, 0f)); // DebugFn.arrow (way2Right, way2IntersectionAngle, new Vector3(0.1f, 0f, 0f)); // Debug.Log ("Complex Intersection point not found"); // Debug.Break (); // TODO - Keep this, though return(getMeshPointsForNonComplex(wayReferences, wayBounds, pos, noIntersectSpecialCase: true)); } meshPoints.Add(intersectionPoint); meshPoints.Add(way2Right); // TODO - Can this use GetBezeirPoints below? // Add bezier points between the ways, from "right" point in way2 to "left" point in way1 Vector3 intersectionPointBezier; bool intersectionFoundBezier = Math3d.LineLineIntersection(out intersectionPointBezier, way2Right, way2.transform.rotation * Vector3.right, way1Left, way1.transform.rotation * Vector3.right); if (!intersectionFoundBezier) { intersectionFoundBezier = Math3d.LineLineIntersection(out intersectionPointBezier, way2Right, Quaternion.Euler(new Vector3(0, 0, 180f) + way2.transform.rotation.eulerAngles) * Vector3.right, way1Left, Quaternion.Euler(new Vector3(0, 0, 180f) + way1.transform.rotation.eulerAngles) * Vector3.right); } // DebugFn.arrow (way1Left, way1.transform.rotation.eulerAngles, new Vector3(0.1f, 0f, 0f)); // DebugFn.arrow (way2Right, way2.transform.rotation.eulerAngles, new Vector3(0.1f, 0f, 0f)); // // DebugFn.square (intersectionPointBezier); // Intersection found, draw the bezier curve float bezierLength = Math3d.GetBezierLength(way2Right, intersectionPointBezier, way1Left); float numberOfPoints = bezierLength * WayHelper.BEZIER_RESOLUTION; float step = 1.0f / numberOfPoints; bool doBreak = false; for (float time = step; time < 1.0f + step; time += step) { if (time > 1f) { time = 1f; doBreak = true; } Vector3 bezierPoint = Math3d.GetVectorInBezierAtTime(time, way2Right, intersectionPointBezier, way1Left); meshPoints.Add(bezierPoint); if (doBreak) { break; } } return(meshPoints); }
private static void CreateCurvedDashedLines(GameObject parent, long key, List <WayReference> wayReferences) { GameObject curveDashedLines = new GameObject(); curveDashedLines.name = "Curved dashed lines"; curveDashedLines.transform.SetParent(parent.transform); curveDashedLines.transform.localPosition = Vector3.zero; Pos centerPos = NodeIndex.getPosById(key); Vector3 posPosition = Game.getCameraPosition(centerPos); WayReference firstReference = wayReferences [0]; WayReference secondReference = wayReferences [1]; bool firstIsNode1 = firstReference.isNode1(centerPos); bool secondIsNode1 = secondReference.isNode1(centerPos); GameObject wayFirst = firstReference.gameObject; GameObject waySecond = secondReference.gameObject; // Number of fields in opposite direction float fieldsFromPos2 = firstReference.getNumberOfFieldsInDirection(false); // Number of fields in own direction float fieldsFromPos1 = firstReference.getNumberOfFieldsInDirection(true); // Number of fields in total float numberOfFields = firstReference.getNumberOfFields(); List <float> dashedLineFields = new List <float> (); for (float field = 1; field < fieldsFromPos2; field++) { dashedLineFields.Add(field); } for (float field = 1; field < fieldsFromPos1; field++) { dashedLineFields.Add(fieldsFromPos2 + field); } // If ways have same "isNode1", invert y-axis for second way bool isSameNode1 = firstIsNode1 == secondIsNode1; // Way width float wayHeight = wayFirst.transform.localScale.y; float wayHeightCompensated = wayHeight - GetLineHeight() * 2f; foreach (float field in dashedLineFields) { GameObject curveDashes = new GameObject(); curveDashes.name = "Curved dashes"; curveDashes.transform.SetParent(curveDashedLines.transform); curveDashes.transform.localPosition = Vector3.zero; // Percentual position of way width, where to put middle line float percentualPositionY = field / numberOfFields; // Get our points (center in y-axis) float yPositionInWay = percentualPositionY * wayHeightCompensated; float dashYMiddle = -wayHeightCompensated / 2f + GetLineHeight() + yPositionInWay - GetDashedLineHeight() / 2f; float dashYMiddleSameNode1 = wayHeightCompensated / 2f - yPositionInWay + GetDashedLineHeight() / 2f; Vector3 firstPosMiddle = posPosition + wayFirst.transform.rotation * new Vector3((firstIsNode1 ? 1 : -1) * wayHeight / 2f, dashYMiddle, 0); Vector3 secondPosMiddle = posPosition + waySecond.transform.rotation * new Vector3((secondIsNode1 ? 1 : -1) * wayHeight / 2f, isSameNode1 ? dashYMiddleSameNode1 : dashYMiddle, 0); Vector3 halfDashedLineHeight = new Vector3(0, GetDashedLineHeight() / 2f, 0); // Get our points (top in y-axis) Vector3 wayFirstHalfDashedHeight = wayFirst.transform.rotation * halfDashedLineHeight; Vector3 waySecondHalfDashedHeight = waySecond.transform.rotation * halfDashedLineHeight; Vector3 firstPosTop = firstPosMiddle - wayFirstHalfDashedHeight; Vector3 secondPosTop = secondPosMiddle + (isSameNode1 ? 1 : -1) * waySecondHalfDashedHeight; // Get our points (bottom in y-axis) Vector3 firstPosBottom = firstPosMiddle + wayFirstHalfDashedHeight; Vector3 secondPosBottom = secondPosMiddle + (isSameNode1 ? -1 : 1) * waySecondHalfDashedHeight; Quaternion firstRotation = firstIsNode1 ? WayHelper.ONEEIGHTY_DEGREES * wayFirst.transform.rotation : wayFirst.transform.rotation; Quaternion secondRotation = secondIsNode1 ? WayHelper.ONEEIGHTY_DEGREES * waySecond.transform.rotation : waySecond.transform.rotation; Vector3 firstDirection = firstRotation * Vector3.right; Vector3 secondDirection = secondRotation * Vector3.right; Vector3 intersectionPoint; Vector3 intersectionPointTop; Vector3 intersectionPointBottom; bool intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, firstPosMiddle, firstDirection, secondPosMiddle, secondDirection); if (!intersectionFound && firstRotation.eulerAngles.z == secondRotation.eulerAngles.z) { intersectionFound = true; intersectionPoint = firstPosMiddle + ((secondPosMiddle - firstPosMiddle) / 2); intersectionPointTop = firstPosTop + ((secondPosTop - firstPosTop) / 2); intersectionPointBottom = firstPosBottom + ((secondPosBottom - firstPosBottom) / 2); } else { Math3d.LineLineIntersection(out intersectionPointTop, firstPosTop, firstDirection, secondPosTop, secondDirection); Math3d.LineLineIntersection(out intersectionPointBottom, firstPosBottom, firstDirection, secondPosBottom, secondDirection); } // TODO - Shouldn't be needed - debug only if (!intersectionFound) { Debug.Log("ERR: " + key); return; } // 1. Get bezier length for curve float bezierLength = Math3d.GetBezierLength(firstPosMiddle, intersectionPoint, secondPosMiddle); // 2. Decide how many dashes to fit, with gaps (also calculate each dash and gap length) // If only one line float numberOfLines = 1f; float dashedLineWidth = bezierLength; float dashedLineGap = 0f; // If more lines if (bezierLength > DASHED_LINE_WIDTH + CITY_DASHED_LINE_GAP) { float totalWidth = 0f; for (numberOfLines = 2f; ; numberOfLines++) { totalWidth = DASHED_LINE_WIDTH + (DASHED_LINE_WIDTH + CITY_DASHED_LINE_GAP) * (numberOfLines - 1); if (totalWidth >= bezierLength) { break; } } dashedLineWidth = DASHED_LINE_WIDTH * bezierLength / totalWidth; dashedLineGap = CITY_DASHED_LINE_GAP * bezierLength / totalWidth; } // 3. Calculate each dash along the line t (time) on bezier curve List <KeyValuePair <float, float> > dashTimes = new List <KeyValuePair <float, float> > (); if (numberOfLines == 1f) { dashTimes.Add(new KeyValuePair <float, float>(0f, 1f)); } else { dashTimes.Add(new KeyValuePair <float, float>(0f, dashedLineWidth / bezierLength)); for (float lineStart = dashedLineWidth + dashedLineGap; lineStart < bezierLength; lineStart += dashedLineWidth + dashedLineGap) { float lineStartTime = lineStart / bezierLength; dashTimes.Add(new KeyValuePair <float, float>(lineStartTime, lineStartTime + dashedLineWidth / bezierLength)); } } foreach (KeyValuePair <float, float> dashTime in dashTimes) { float startTime = dashTime.Key; float endTime = dashTime.Value; float dashLengthPercent = endTime - startTime; float numberOfPoints = Mathf.Max(bezierLength / dashLengthPercent * WayHelper.BEZIER_RESOLUTION, 4f); float eachPointTime = dashLengthPercent / numberOfPoints; List <Vector3> dashPoints = new List <Vector3>(); // Top line for (float t = startTime; t <= endTime; t += eachPointTime) { dashPoints.Add(Math3d.GetVectorInBezierAtTime(t, firstPosTop, intersectionPointTop, secondPosTop)); } // Bottom line for (float t = endTime; t >= startTime; t -= eachPointTime) { dashPoints.Add(Math3d.GetVectorInBezierAtTime(t, firstPosBottom, intersectionPointBottom, secondPosBottom)); } GameObject lineMiddle = MapSurface.createPlaneMeshForPoints(dashPoints); lineMiddle.name = "Curved dash"; WayLine.SetWhiteMaterial(lineMiddle); lineMiddle.transform.SetParent(curveDashes.transform); lineMiddle.transform.localPosition = new Vector3(0, 0, -0.01f); } } }