6 changed files with 335 additions and 28 deletions
@ -0,0 +1,157 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using EasyRoads3Dv3; |
||||||
|
using UnityEngine; |
||||||
|
using UnityEngine.Assertions; |
||||||
|
using UnityEngine.PlayerLoop; |
||||||
|
|
||||||
|
namespace ERVertexPath |
||||||
|
{ |
||||||
|
public class ERMultiRoadPathCreator : MonoBehaviour |
||||||
|
{ |
||||||
|
public ERNetworkVertexPathCreator allRoadsPathCreator; |
||||||
|
public string roadNameMask; |
||||||
|
public bool isShowPathGizmo; |
||||||
|
public bool cleanupSourcePaths; |
||||||
|
|
||||||
|
private ERPathAdapter unionAdapter; |
||||||
|
|
||||||
|
private bool isInitialized; |
||||||
|
|
||||||
|
public ERPathAdapter UnionAdapter => unionAdapter; |
||||||
|
|
||||||
|
private void Awake() |
||||||
|
{ |
||||||
|
Init(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Init(bool forceInit = false) |
||||||
|
{ |
||||||
|
if (!forceInit && isInitialized) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
isInitialized = true; |
||||||
|
|
||||||
|
allRoadsPathCreator.Init(); |
||||||
|
var lowerNameMask = roadNameMask.ToLower(); |
||||||
|
var roads = new ERRoadNetwork().GetRoads().Where(_road => _road.GetName().ToLower().Contains(lowerNameMask)); |
||||||
|
|
||||||
|
var initialRoad = roads.First(); |
||||||
|
var road = initialRoad; |
||||||
|
Assert.IsNotNull(road, "Only implicitly closed tracks are supported, can't find any roads with name contains given mask"); |
||||||
|
const int traverseLimit = 1000; |
||||||
|
var traverseConnectionCount = 0; |
||||||
|
|
||||||
|
var vertexPathWrappers = new List<ERPathToVertexPathWrapper>(); |
||||||
|
|
||||||
|
DebugLog($"Building union vertex path for roads with mask {roadNameMask}"); |
||||||
|
|
||||||
|
do |
||||||
|
{ |
||||||
|
vertexPathWrappers.Add(road.roadScript.GetComponent<ERPathToVertexPathWrapper>()); |
||||||
|
|
||||||
|
DebugLog($"Search connections for road: {road.GetName()}"); |
||||||
|
var endConnector = road.GetConnectionAtEnd(out _); |
||||||
|
|
||||||
|
if (endConnector != null) |
||||||
|
{ |
||||||
|
for (var i = 0; i < endConnector.GetConnectionCount(); i++) |
||||||
|
{ |
||||||
|
var connectedRoad = endConnector.GetConnectedRoad(i, out _); |
||||||
|
if (connectedRoad != null && connectedRoad != road) |
||||||
|
{ |
||||||
|
road = connectedRoad; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
traverseConnectionCount++; |
||||||
|
} while (road != initialRoad && traverseConnectionCount < traverseLimit); |
||||||
|
|
||||||
|
if (traverseConnectionCount == traverseLimit) |
||||||
|
{ |
||||||
|
throw new Exception($"Too much roads, limit {traverseLimit} reached"); |
||||||
|
} |
||||||
|
|
||||||
|
BuildUnionVertexPath(vertexPathWrappers); |
||||||
|
} |
||||||
|
|
||||||
|
private void BuildUnionVertexPath(IEnumerable<ERPathToVertexPathWrapper> wrappers) |
||||||
|
{ |
||||||
|
var vertexList = new List<Vector3>(); |
||||||
|
var directionsList = new List<Vector3>(); |
||||||
|
var normalsList = new List<Vector3>(); |
||||||
|
var rotationsList = new List<Quaternion>(); |
||||||
|
var distanceList = new List<float>(); |
||||||
|
var startIndexToRoad = new Dictionary<int, GameObject>(); |
||||||
|
|
||||||
|
var totalDistance = 0f; |
||||||
|
var positionIndex = 0; |
||||||
|
foreach (var wrapper in wrappers) |
||||||
|
{ |
||||||
|
vertexList.AddRange(wrapper.Positions); |
||||||
|
directionsList.AddRange(wrapper.Directions); |
||||||
|
normalsList.AddRange(wrapper.Normals); |
||||||
|
rotationsList.AddRange(wrapper.Rotations); |
||||||
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
|
var updatedDistances = wrapper.Distances.Select(distance => distance + totalDistance); |
||||||
|
distanceList.AddRange(updatedDistances); |
||||||
|
totalDistance += wrapper.TotalDistance; |
||||||
|
|
||||||
|
startIndexToRoad.Add(positionIndex, wrapper.gameObject); |
||||||
|
Debug.Log($"Adding road {wrapper.gameObject.name} from index: {positionIndex}"); |
||||||
|
|
||||||
|
if (cleanupSourcePaths) |
||||||
|
{ |
||||||
|
wrapper.ClearPathData(); |
||||||
|
var pathAdapter = wrapper.gameObject.GetComponent<ERPathAdapter>(); |
||||||
|
if (pathAdapter) |
||||||
|
{ |
||||||
|
pathAdapter.ClearPathData(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
positionIndex = vertexList.Count; |
||||||
|
} |
||||||
|
|
||||||
|
unionAdapter = gameObject.AddComponent<ERPathAdapter>(); |
||||||
|
unionAdapter.InitFromData(totalDistance, vertexList.ToArray(), directionsList.ToArray(), |
||||||
|
normalsList.ToArray(), rotationsList.ToArray(), distanceList.ToArray(), startIndexToRoad); |
||||||
|
|
||||||
|
DebugLog($"Created union adapter for roads with mask = {roadNameMask}, distance = {unionAdapter.TotalDistance}, vertex count = {vertexList.Count}"); |
||||||
|
} |
||||||
|
|
||||||
|
private void OnDrawGizmos() |
||||||
|
{ |
||||||
|
if (!isShowPathGizmo) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var verticalOffset = Vector3.up * 0.5f; |
||||||
|
for (var i = 0; i < unionAdapter.Positions.Length; i++) |
||||||
|
{ |
||||||
|
var start = unionAdapter.Positions[i]; |
||||||
|
var end = i == unionAdapter.Positions.Length - 1 ? unionAdapter.Positions[0] : unionAdapter.Positions[i + 1]; |
||||||
|
start += verticalOffset; |
||||||
|
end += verticalOffset; |
||||||
|
Debug.DrawLine(start, end, i % 2 == 0 ? Color.white : Color.magenta); |
||||||
|
Debug.DrawLine(start, start + verticalOffset, Color.yellow); |
||||||
|
Debug.DrawLine(start, start + unionAdapter.Normals[i], Color.red); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void DebugLog(string msg) |
||||||
|
{ |
||||||
|
if (!allRoadsPathCreator.logEnabled) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
Debug.Log(msg); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue