private static Dictionary <int, List <int> > BuildNodeExternalConnections(IStoryGraph sg) { var result = new Dictionary <int, List <int> >(); result.GetOrAdd(sg.Leaves.First(), x => new List <int>()); result.GetOrAdd(sg.Leaves.Last(), x => new List <int>()); foreach (var edge in sg.Edges) { var commonParent = sg.GetCommonParent(edge.First, edge.Second); var first = edge.First; while (sg.Parents[first] != commonParent) { var list = result.GetOrAdd(first, x => new List <int>()); list.Add(edge.Second); first = sg.Parents[first]; } var second = edge.Second; while (sg.Parents[second] != commonParent) { var list = result.GetOrAdd(second, x => new List <int>()); list.Add(edge.First); second = sg.Parents[second]; } } return(result); }
private void PlaceCorridors() { var occupiedLanes = new IntSet32[sg.NodeIds.Max() + 1]; foreach (var edge in sg.Edges) { laneBuilder.StartLane(edge); var disambiguator = 0; var commonOccupiedLanes = new IntSet32(); if (sg.Parents[edge.First] == sg.Parents[edge.Second]) { var commonParent = sg.Parents[edge.First]; var startPoint = relPositions[edge.First] + Vector3.UnitX * halfSizes[edge.First].Width; var endPoint = relPositions[edge.Second] - Vector3.UnitX * halfSizes[edge.Second].Width; if (!IsMultiFloorNode(commonParent)) { if (nodeRows[edge.Second] - nodeRows[edge.First] == 1) { laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.Immediate, true); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(commonParent, true); } else { disambiguator = 1; while (occupiedLanes[commonParent].Contains(disambiguator)) { disambiguator++; } var leafChildrenOnly = !sg.Children[commonParent].SelectMany(x => sg.Children[x]).Any(); if (leafChildrenOnly) { laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.LongRange, true); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(new Vector3(startPoint.X + BuildingConstants.WidthMargin - BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(endPoint.X - BuildingConstants.WidthMargin + BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(commonParent, true); occupiedLanes[commonParent] = occupiedLanes[commonParent].With(disambiguator); } else { laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.LongRange, true); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(new Vector3(startPoint.X + BuildingConstants.WidthMargin - BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(startPoint.X + BuildingConstants.WidthMargin, startPoint.Y, 0)); laneBuilder.EndLaneSegment(commonParent, false); laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.LongRange, false); laneBuilder.AddRawPoint(new Vector3(endPoint.X - BuildingConstants.WidthMargin, startPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(endPoint.X - BuildingConstants.WidthMargin + BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(commonParent, true); occupiedLanes[commonParent] = occupiedLanes[commonParent].With(disambiguator); } } } else { disambiguator = 1; while (occupiedLanes[commonParent].Contains(disambiguator)) { disambiguator++; } var floorDistance = nodeRows[edge.Second] - nodeRows[edge.First]; laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.LongRange, true); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(new Vector3(halfSizes[commonParent].Width, startPoint.Y, startPoint.Z)); laneBuilder.AddRawPoint(new Vector3(halfSizes[commonParent].Width, startPoint.Y, -halfSizes[commonParent].Depth - BuildingConstants.StairsDistance * (floorDistance + 1))); laneBuilder.AddRawPoint(new Vector3(halfSizes[commonParent].Width, endPoint.Y, -halfSizes[commonParent].Depth - BuildingConstants.StairsDistance * (floorDistance + 1))); laneBuilder.AddRawPoint(new Vector3(halfSizes[commonParent].Width, endPoint.Y, endPoint.Z)); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(commonParent, true); } } else { var commonParent = sg.GetCommonParent(edge.First, edge.Second); var laneContainerNodes = new List <int>(); var descendingNodes = new Stack <int>(); { var descNode = edge.Second; while (descNode != commonParent) { descendingNodes.Push(descNode); descNode = sg.Parents[descNode]; } } var node = edge.First; while (sg.Parents[node] != commonParent) { var parent = sg.Parents[node]; commonOccupiedLanes = commonOccupiedLanes.Union(occupiedLanes[parent]); laneContainerNodes.Add(parent); var nodeLoc = node; var transitSiblings = sg.Children[parent].Where(x => relPositions[x].Z == 0f && nodeRows[nodeLoc] < nodeRows[x]); foreach (var transitSibling in transitSiblings) { commonOccupiedLanes = commonOccupiedLanes.Union(occupiedLanes[transitSibling]); laneContainerNodes.Add(transitSibling); } var startPoint = relPositions[node] + Vector3.UnitX * halfSizes[node].Width; laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.InterNode, node == edge.First); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(new Vector3(startPoint.X + BuildingConstants.WidthMargin - BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(halfSizes[parent].Width, startPoint.Y, 0)); laneBuilder.EndLaneSegment(parent, false); node = sg.Parents[node]; } { var topLevelChildFirst = node; var topLevelChildSecond = descendingNodes.Pop(); commonOccupiedLanes = commonOccupiedLanes.Union(occupiedLanes[commonParent]); laneContainerNodes.Add(commonParent); var startPoint = relPositions[topLevelChildFirst] + Vector3.UnitX * halfSizes[topLevelChildFirst].Width; var endPoint = relPositions[topLevelChildSecond] - Vector3.UnitX * halfSizes[topLevelChildSecond].Width; if (!IsMultiFloorNode(commonParent)) { if (nodeRows[topLevelChildSecond] - nodeRows[topLevelChildFirst] == 1) { laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.InterNode, false); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(commonParent, false); } else { var transitSiblings = sg.Children[commonParent].Where(x => relPositions[x].Z == 0f && nodeRows[topLevelChildFirst] < nodeRows[x] && nodeRows[x] < nodeRows[topLevelChildSecond]); foreach (var transitSibling in transitSiblings) { commonOccupiedLanes = commonOccupiedLanes.Union(occupiedLanes[transitSibling]); laneContainerNodes.Add(transitSibling); } laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.InterNode, false); laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(new Vector3(startPoint.X + BuildingConstants.WidthMargin - BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(endPoint.X - BuildingConstants.WidthMargin + BuildingConstants.CorridorBranchingOffset, startPoint.Y, 0)); laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.CorridorBranchingOffset); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(commonParent, false); } } else { var revStartPoint = new Vector3(-startPoint.X, startPoint.Y, startPoint.Z); var revEndPoint = new Vector3(-endPoint.X, endPoint.Y, endPoint.Z); var floorDistance = nodeRows[topLevelChildSecond] - nodeRows[topLevelChildFirst]; laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.Elevator, false); if (!isReversed[topLevelChildFirst]) { laneBuilder.AddRawPoint(startPoint); laneBuilder.AddRawPoint(startPoint + Vector3.UnitX * BuildingConstants.ElevatorOffset); } else { laneBuilder.AddRawPoint(revStartPoint); laneBuilder.AddRawPoint(revStartPoint - Vector3.UnitX * BuildingConstants.ElevatorOffset); } if (!isReversed[topLevelChildSecond]) { if (!isReversed[topLevelChildFirst]) { laneBuilder.AddRawPoint(revEndPoint + Vector3.UnitX * BuildingConstants.ElevatorOffset); laneBuilder.AddRawPoint(revEndPoint); laneBuilder.AddRawPoint(endPoint); } else { laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.ElevatorOffset); laneBuilder.AddRawPoint(endPoint); } } else { if (!isReversed[topLevelChildFirst]) { laneBuilder.AddRawPoint(revEndPoint + Vector3.UnitX * BuildingConstants.ElevatorOffset); laneBuilder.AddRawPoint(revEndPoint); } else { laneBuilder.AddRawPoint(endPoint - Vector3.UnitX * BuildingConstants.ElevatorOffset); laneBuilder.AddRawPoint(endPoint); laneBuilder.AddRawPoint(revEndPoint); } } laneBuilder.EndLaneSegment(commonParent, false); } } while (descendingNodes.Any()) { node = descendingNodes.Pop(); var parent = sg.Parents[node]; commonOccupiedLanes = commonOccupiedLanes.Union(occupiedLanes[parent]); laneContainerNodes.Add(parent); var nodeLoc = node; var transitSiblings = sg.Children[parent].Where(x => relPositions[x].Z == 0f && nodeRows[x] < nodeRows[nodeLoc]); foreach (var transitSibling in transitSiblings) { commonOccupiedLanes = commonOccupiedLanes.Union(occupiedLanes[transitSibling]); laneContainerNodes.Add(transitSibling); } var endPoint = relPositions[node] - Vector3.UnitX * halfSizes[node].Width; laneBuilder.StartLaneSegment(BuildingStoryLayoutLanePartType.InterNode, false); laneBuilder.AddRawPoint(new Vector3(-halfSizes[parent].Width, endPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(endPoint.X - BuildingConstants.WidthMargin + BuildingConstants.CorridorBranchingOffset, endPoint.Y, 0)); laneBuilder.AddRawPoint(new Vector3(endPoint.X - BuildingConstants.CorridorBranchingOffset, endPoint.Y, endPoint.Z)); laneBuilder.AddRawPoint(endPoint); laneBuilder.EndLaneSegment(parent, node == edge.Second); } disambiguator = 1; while (commonOccupiedLanes.Contains(disambiguator)) { disambiguator++; } foreach (var laneContainerNode in laneContainerNodes) { occupiedLanes[laneContainerNode] = occupiedLanes[laneContainerNode].With(disambiguator); } } laneBuilder.EndLane(disambiguator); } }