예제 #1
0
        private static void InsertNodeSegments(RoadTopology topology, IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
        {
            foreach (var node in topology.Nodes)
            {
                foreach (var edgesPerTemplate in node.Edges.GroupBy(e => e.Template))
                {
                    var template = edgesPerTemplate.Key;
                    // possible optimization: only compute angles if necessary?
                    var incomingRoadData = ComputeRoadAngles(node, edgesPerTemplate);

                    switch (edgesPerTemplate.Count())
                    {
                    // TODO support end caps
                    case 1:     // end point
                        break;

                    case 2:
                        CurvedRoadSegment.CreateCurve(incomingRoadData, node.Position, template, edgeSegments);
                        break;

                    case 3:
                    case 4:
                        CrossingRoadSegment.CreateCrossing(incomingRoadData, node.Position, template, edgeSegments);
                        break;
                    }
                }
            }
        }
예제 #2
0
        internal RoadCollection(RoadTopology topology, AssetLoadContext loadContext, HeightMap heightMap)
            : this()
        {
            // The map stores road segments with no connectivity:
            // - a segment is from point A to point B
            // - with a road type name
            // - and start and end curve types (angled, tight curve, broad curve).

            // The goal is to create road networks of connected road segments,
            // where a network has only a single road type.

            // A road network is composed of 2 or more nodes.
            // A network is a (potentially) cyclic graph.

            // A road node has > 1 and <= 4 edges connected to it.
            // A node can be part of multiple networks.

            // An edge can only exist in one network.

            var roadTemplateList = new RoadTemplateList(loadContext.AssetStore.RoadTemplates);

            var networks = RoadNetwork.BuildNetworks(topology, roadTemplateList);

            foreach (var network in networks)
            {
                _roads.Add(AddDisposable(new Road(
                                             loadContext,
                                             heightMap,
                                             network)));
            }
        }
예제 #3
0
        private static void InsertNodeSegments(RoadTopology topology, IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
        {
            foreach (var node in topology.Nodes)
            {
                foreach (var edgesPerTemplate in node.Edges.GroupBy(e => e.Template))
                {
                    switch (edgesPerTemplate.Count())
                    {
                    // TODO support end caps
                    case 1:     // end point
                        break;

                    case 2:     // TODO normal road, create segments for tight/broad curves
                        break;

                    case 3:
                    case 4:
                        var template         = edgesPerTemplate.Key;
                        var incomingRoadData = ComputeRoadAngles(node, edgesPerTemplate);
                        CrossingRoadSegment.CreateCrossing(incomingRoadData, node.Position, template, edgeSegments);
                        break;
                    }
                }
            }
        }
예제 #4
0
        public static IList <RoadNetwork> BuildNetworks(RoadTopology topology)
        {
            var edgeSegments = BuildEdgeSegments(topology);

            InsertNodeSegments(topology, edgeSegments);
            var networks = BuildNetworks(topology, edgeSegments);

            return(networks);
        }
예제 #5
0
        private static void InsertNodeSegments(RoadTopology topology, IDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
        {
            foreach (var node in topology.Nodes)
            {
                foreach (var edgesPerTemplate in node.Edges.GroupBy(e => e.Template))
                {
                    switch (edgesPerTemplate.Count())
                    {
                    // TODO support end caps
                    case 1:     // end point
                        break;

                    case 2:     // TODO normal road, create segments for tight/broad curves
                        break;

                    case 3:
                        // TODO figure out orientation and endpoints
                        // TODO support Y segments
                        //var halfWidth = edgesPerTemplate.Key.RoadWidth / 2;

                        //var segment = new TRoadSegment(
                        //    node.Position,
                        //    new RoadSegmentEndPoint(node.Position + new Vector3(0, halfWidth, 0)),
                        //    new RoadSegmentEndPoint(node.Position + new Vector3(halfWidth, 0, 0)),
                        //    new RoadSegmentEndPoint(node.Position + new Vector3(0, -halfWidth, 0)));

                        //// TODO consider ordering of edges

                        //Connect(edgesPerTemplate.ElementAt(0), segment.Top, Vector3.UnitY);
                        //Connect(edgesPerTemplate.ElementAt(1), segment.Right, Vector3.UnitX);
                        //Connect(edgesPerTemplate.ElementAt(2), segment.Bottom, -Vector3.UnitY);

                        //void Connect(RoadTopologyEdge edge, RoadSegmentEndPoint endPoint, in Vector3 direction)
                        //{
                        //    var edgeSegment = edgeSegments[edge];
                        //    if (edge.Start.Position == node.Position)
                        //    {
                        //        edgeSegment.Start.Position = endPoint.Position;
                        //        edgeSegment.Start.ConnectTo(segment, direction);
                        //        endPoint.ConnectTo(edgeSegment, edge.Start.Position - edge.End.Position);
                        //    }
                        //    else
                        //    {
                        //        edgeSegment.End.Position = endPoint.Position;
                        //        edgeSegment.End.ConnectTo(segment, direction);
                        //        endPoint.ConnectTo(edgeSegment, edge.End.Position - edge.Start.Position);
                        //    }
                        //}

                        break;
                    }
                }
            }
        }
예제 #6
0
 private static void InsertCurveSegments(RoadTopology topology, IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
 {
     foreach (var node in topology.Nodes)
     {
         foreach (var edgesPerTemplate in node.Edges.GroupBy(e => e.Template))
         {
             var connectedEdges = edgesPerTemplate.Count();
             if (connectedEdges == 2)
             {
                 var incomingRoadData = ComputeRoadAngles(node, edgesPerTemplate, edgeSegments);
                 CurvedRoadSegment.CreateCurve(incomingRoadData, node.Position, edgesPerTemplate.Key, edgeSegments);
             }
         }
     }
 }
예제 #7
0
        private static IList <RoadNetwork> BuildNetworks(RoadTopology topology, IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
        {
            var networks = new List <RoadNetwork>();

            // Create one network for each connected set of segments of a specific type.
            foreach (var templateEdges in topology.Edges.GroupBy(e => e.Template))
            {
                var edgesToProcess = new HashSet <IRoadSegment>(templateEdges.Select(e => edgeSegments[e]));

                while (edgesToProcess.Any())
                {
                    var edgeSegment = edgesToProcess.First();
                    edgesToProcess.Remove(edgeSegment);

                    var seenSegments = new HashSet <IRoadSegment>();
                    seenSegments.Add(edgeSegment);

                    var network = new RoadNetwork(templateEdges.Key);
                    networks.Add(network);

                    network._segments.Add(edgeSegment);

                    foreach (var endPoint in edgeSegment.EndPoints)
                    {
                        FollowPath(endPoint);
                    }

                    void FollowPath(RoadSegmentEndPoint endPoint)
                    {
                        if (endPoint.To == null || seenSegments.Contains(endPoint.To))
                        {
                            return;
                        }

                        edgesToProcess.Remove(endPoint.To);
                        network._segments.Add(endPoint.To);
                        seenSegments.Add(endPoint.To);

                        foreach (var nextEndPoint in endPoint.To.EndPoints)
                        {
                            FollowPath(nextEndPoint);
                        }
                    }
                }
            }

            return(networks);
        }
예제 #8
0
 private static void InsertCrossingSegments(RoadTopology topology, IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
 {
     foreach (var node in topology.Nodes)
     {
         foreach (var edgesPerTemplate in node.Edges.GroupBy(e => e.Template))
         {
             if (edgesPerTemplate.Count() >= 3)
             {
                 var incomingRoadData = ComputeRoadAngles(node, edgesPerTemplate, edgeSegments);
                 if (incomingRoadData.Count == 3 || incomingRoadData.Count == 4)
                 {
                     CrossingRoadSegment.CreateCrossing(incomingRoadData, node.Position, edgesPerTemplate.Key, edgeSegments);
                 }
             }
         }
     }
 }
예제 #9
0
        internal RoadCollection(RoadTopology topology, AssetLoadContext loadContext, HeightMap heightMap)
            : this()
        {
            // The map stores road segments with no connectivity:
            // - a segment is from point A to point B
            // - with a road type name
            // - and start and end curve types (angled, tight curve, broad curve).

            // The goal is to create road networks of connected road segments,
            // where a network has only a single road type.

            // A road network is composed of 2 or more nodes.
            // A network is a (potentially) cyclic graph.

            // A road node has > 1 and <= 4 edges connected to it.
            // A node can be part of multiple networks.

            // An edge can only exist in one network.

            // TODO: If a node stored in the map has > 4 edges, the extra edges
            // are put into a separate network.

            var networks = RoadNetwork.BuildNetworks(topology);

            // Roads of different types are rendered in reverse template order:
            // the first template has the lowest z-index, the last one the highest.
            // Since we don't know the index here we start with the templates,
            // join them with the networks and reverse the result.
            var sortedNetworks = loadContext.AssetStore.RoadTemplates
                                 .Join(
                networks,
                t => t.InstanceId,
                n => n.Template.InstanceId,
                (t, n) => n)
                                 .Reverse();

            foreach (var network in sortedNetworks)
            {
                _roads.Add(AddDisposable(new Road(
                                             loadContext,
                                             heightMap,
                                             network)));
            }
        }
예제 #10
0
        public static IEnumerable <RoadNetwork> BuildNetworks(RoadTopology topology, RoadTemplateList roadTemplateList)
        {
            topology.AlignOrientation();
            var edgeSegments = BuildEdgeSegments(topology);

            InsertNodeSegments(topology, edgeSegments);
            InsertEndCapSegments(edgeSegments, roadTemplateList);
            var networks = BuildNetworks(topology, edgeSegments);

            // sort networks in the order specified by roadTemplateList
            var sortedNetworks = roadTemplateList
                                 .Join(
                networks,
                t => t.InstanceId,
                n => n.Template.InstanceId,
                (t, n) => n);

            return(sortedNetworks);
        }
예제 #11
0
        private static void InsertNodeSegments(RoadTopology topology, IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments)
        {
            foreach (var node in topology.Nodes)
            {
                foreach (var edgesPerTemplate in node.Edges.GroupBy(e => e.Template))
                {
                    var template         = edgesPerTemplate.Key;
                    var incomingRoadData = ComputeRoadAngles(node, edgesPerTemplate);

                    switch (edgesPerTemplate.Count())
                    {
                    case 2:
                        CurvedRoadSegment.CreateCurve(incomingRoadData, node.Position, template, edgeSegments);
                        break;

                    case 3:
                    case 4:
                        CrossingRoadSegment.CreateCrossing(incomingRoadData, node.Position, template, edgeSegments);
                        break;
                    }
                }
            }
        }
예제 #12
0
        private static IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> BuildEdgeSegments(RoadTopology topology)
        {
            // create a dictionary from edges to segments
            var edgeSegments = topology.Edges.ToDictionary(e => e, e => new StraightRoadSegment(e.Start.Position, e.End.Position));

            // create end points and connect them to the neighbour edges
            foreach (var edge in topology.Edges)
            {
                var edgeSegment = edgeSegments[edge];

                Connect(edge.Start, edge.Start.Position - edge.End.Position);
                Connect(edge.End, edge.End.Position - edge.Start.Position);

                void Connect(RoadTopologyNode node, in Vector3 direction)
                {
                    foreach (var connectedEdge in node.Edges)
                    {
                        if (connectedEdge == edge || connectedEdge.Template != edge.Template)
                        {
                            continue;
                        }

                        var connectedEdgeSegment = edgeSegments[connectedEdge];

                        if (connectedEdge.Start.Position == node.Position)
                        {
                            connectedEdgeSegment.Start.ConnectTo(edgeSegment, Vector3.Normalize(direction));
                        }
                        else
                        {
                            connectedEdgeSegment.End.ConnectTo(edgeSegment, Vector3.Normalize(direction));
                        }
                    }
                }
            }

            return(edgeSegments);
        }