Exemple #1
0
 private static void AddLeavingEdge(MapNodeHalfEdge edge)
 {
     if (edge.previous.destination.leavingEdge == null)
     {
         edge.previous.destination.leavingEdge = edge;
     }
 }
Exemple #2
0
    private void SnapPoints(MapPoint point, MapNodeHalfEdge edge)
    {
        // Don't snap if the neighboring nodes already have three edges
        if (edge.node.GetEdges().Count() <= 3 || edge.opposite == null || edge.opposite.node.GetEdges().Count() <= 3)
        {
            return;
        }

        // There are issues with this when snapping near the edge of the map
        if (point.GetEdges().Any(x => x.opposite == null) || edge.destination.GetEdges().Any(x => x.opposite == null))
        {
            return;
        }

        // Delete the edges
        edges.Remove(edge);

        // Delete the other point
        points.Remove(new Vector3(edge.destination.position.x, 0, edge.destination.position.z));

        var otherEdges = edge.destination.GetEdges().ToList();

        // Update everything to point to the first point
        if (point.leavingEdge == edge)
        {
            point.leavingEdge = edge.opposite.next;
        }
        if (edge.node.startEdge == edge)
        {
            edge.node.startEdge = edge.previous;
        }
        edge.next.previous = edge.previous;
        edge.previous.next = edge.next;

        // Update the opposite edge as well
        if (edge.opposite != null && edge.opposite.node.GetEdges().Count() > 3)
        {
            // Delete edge
            edges.Remove(edge.opposite);

            // Update pointers
            edge.opposite.next.previous = edge.opposite.previous;
            edge.opposite.previous.next = edge.opposite.next;
            if (edge.opposite.node.startEdge == edge.opposite)
            {
                edge.opposite.node.startEdge = edge.opposite.previous;
            }
        }

        foreach (var otherEdge in otherEdges)
        {
            if (otherEdge.opposite != null)
            {
                otherEdge.opposite.destination = point;
            }
        }
    }
        public MapNodeHalfEdge GetLowestEdge()
        {
            MapNodeHalfEdge lowestEdge = null;

            foreach (var edge in GetEdges())
            {
                if (lowestEdge == null || lowestEdge.destination.position.y > edge.destination.position.y || lowestEdge.previous.destination.position.y > edge.previous.destination.position.y)
                {
                    lowestEdge = edge;
                }
            }
            return(lowestEdge);
        }
Exemple #4
0
    private void ConnectOpposites(Dictionary <Vector3, List <MapNodeHalfEdge> > edgesByStartPosition)
    {
        foreach (var edge in edges)
        {
            if (edge.opposite == null)
            {
                var startEdgePosition = edge.previous.destination.position;
                var endEdgePosition   = edge.destination.position;

                if (edgesByStartPosition.ContainsKey(endEdgePosition))
                {
                    var             list     = edgesByStartPosition[endEdgePosition];
                    MapNodeHalfEdge opposite = null;
                    foreach (var item in list)
                    {
                        // We use .5f to snap the coordinates to each other, otherwise there are holes in the graph
                        if (Math.Abs(item.destination.position.x - startEdgePosition.x) < 0.5f && Math.Abs(item.destination.position.z - startEdgePosition.z) < 0.5f)
                        {
                            opposite = item;
                        }
                    }
                    if (opposite != null)
                    {
                        edge.opposite     = opposite;
                        opposite.opposite = edge;
                    }
                    else
                    {
                        // TODO: We need to check that this is at the world boundry, otherwise it's a bug
                        var isAtEdge = endEdgePosition.x == 0 || endEdgePosition.x == plotBounds.width || endEdgePosition.z == 0 || endEdgePosition.z == plotBounds.height ||
                                       startEdgePosition.x == 0 || startEdgePosition.x == plotBounds.width || startEdgePosition.z == 0 || startEdgePosition.z == plotBounds.height;

                        if (!isAtEdge)
                        {
                            edge.node.nodeType = MapNodeType.Error;
                            Debug.Assert(isAtEdge, "Edges without opposites must be at the boundry edge");
                        }
                    }
                }
            }
        }
    }
Exemple #5
0
    private MapNodeHalfEdge AddEdge(Dictionary <Vector3, List <MapNodeHalfEdge> > edgesByStartPosition, MapNodeHalfEdge previous, Vector3 start, Vector3 end, MapNode node)
    {
        if (start == end)
        {
            Debug.Assert(start != end, "Start and end vectors must not be the same");
        }
        var currentEdge = new MapNodeHalfEdge {
            node = node
        };

        if (!points.ContainsKey(start))
        {
            points.Add(start, new MapPoint {
                position = start, leavingEdge = currentEdge
            });
        }
        if (!points.ContainsKey(end))
        {
            points.Add(end, new MapPoint {
                position = end
            });
        }

        currentEdge.destination = points[end];

        if (!edgesByStartPosition.ContainsKey(start))
        {
            edgesByStartPosition.Add(start, new List <MapNodeHalfEdge>());
        }
        edgesByStartPosition[start].Add(currentEdge);
        edges.Add(currentEdge);

        if (previous != null)
        {
            previous.next        = currentEdge;
            currentEdge.previous = previous;
            AddLeavingEdge(currentEdge);
        }
        return(currentEdge);
    }
Exemple #6
0
    private void CreateFromVoronoi(Voronoi voronoi)
    {
        points = new Dictionary <Vector3, MapPoint>();
        nodesByCenterPosition = new Dictionary <Vector3, MapNode>();
        var edgesByStartPosition = new Dictionary <Vector3, List <MapNodeHalfEdge> >();

        edges = new List <MapNodeHalfEdge>();


        plotBounds = voronoi.plotBounds;
        var bottomLeftSite  = voronoi.NearestSitePoint(voronoi.plotBounds.xMin, voronoi.plotBounds.yMin);
        var bottomRightSite = voronoi.NearestSitePoint(voronoi.plotBounds.xMax, voronoi.plotBounds.yMin);
        var topLeftSite     = voronoi.NearestSitePoint(voronoi.plotBounds.xMin, voronoi.plotBounds.yMax);
        var topRightSite    = voronoi.NearestSitePoint(voronoi.plotBounds.xMax, voronoi.plotBounds.yMax);

        var topLeft     = new Vector3(voronoi.plotBounds.xMin, 0, voronoi.plotBounds.yMax);
        var topRight    = new Vector3(voronoi.plotBounds.xMax, 0, voronoi.plotBounds.yMax);
        var bottomLeft  = new Vector3(voronoi.plotBounds.xMin, 0, voronoi.plotBounds.yMin);
        var bottomRight = new Vector3(voronoi.plotBounds.xMax, 0, voronoi.plotBounds.yMin);

        var siteEdges = new Dictionary <Vector2, List <LineSegment> >();

        var edgePointsRemoved = 0;

        foreach (var edge in voronoi.Edges())
        {
            if (edge.visible)
            {
                var p1      = edge.clippedEnds[Delaunay.LR.Side.LEFT];
                var p2      = edge.clippedEnds[Delaunay.LR.Side.RIGHT];
                var segment = new LineSegment(p1, p2);

                if (Vector2.Distance(p1.Value, p2.Value) < 0.001f)
                {
                    edgePointsRemoved++;
                    continue;
                }

                if (edge.leftSite != null)
                {
                    if (!siteEdges.ContainsKey(edge.leftSite.Coord))
                    {
                        siteEdges.Add(edge.leftSite.Coord, new List <LineSegment>());
                    }
                    siteEdges[edge.leftSite.Coord].Add(segment);
                }
                if (edge.rightSite != null)
                {
                    if (!siteEdges.ContainsKey(edge.rightSite.Coord))
                    {
                        siteEdges.Add(edge.rightSite.Coord, new List <LineSegment>());
                    }
                    siteEdges[edge.rightSite.Coord].Add(segment);
                }
            }
        }
        Debug.Assert(edgePointsRemoved == 0, string.Format("{0} edge points too close and have been removed", edgePointsRemoved));

        foreach (var site in voronoi.SiteCoords())
        {
            var boundries   = GetBoundriesForSite(siteEdges, site);
            var center      = ToVector3(site);
            var currentNode = new MapNode {
                centerPoint = center
            };
            nodesByCenterPosition.Add(center, currentNode);

            MapNodeHalfEdge firstEdge    = null;
            MapNodeHalfEdge previousEdge = null;

            for (var i = 0; i < boundries.Count; i++)
            {
                var edge = boundries[i];

                var start = ToVector3(edge.p0.Value);
                var end   = ToVector3(edge.p1.Value);
                if (start == end)
                {
                    continue;
                }

                previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, end, currentNode);
                if (firstEdge == null)
                {
                    firstEdge = previousEdge;
                }
                if (currentNode.startEdge == null)
                {
                    currentNode.startEdge = previousEdge;
                }

                // We need to figure out if the two edges meet, and if not then insert some more edges to close the polygon
                var insertEdges = false;
                if (i < boundries.Count - 1)
                {
                    start       = ToVector3(boundries[i].p1.Value);
                    end         = ToVector3(boundries[i + 1].p0.Value);
                    insertEdges = start != end;
                }
                else if (i == boundries.Count - 1)
                {
                    start       = ToVector3(boundries[i].p1.Value);
                    end         = ToVector3(boundries[0].p0.Value);
                    insertEdges = start != end;
                }

                if (insertEdges)
                {
                    // Check which corners are within this node
                    var startIsTop    = start.z == voronoi.plotBounds.yMax;
                    var startIsBottom = start.z == voronoi.plotBounds.yMin;
                    var startIsLeft   = start.x == voronoi.plotBounds.xMin;
                    var startIsRight  = start.x == voronoi.plotBounds.xMax;

                    var hasTopLeft     = site == topLeftSite && !(startIsTop && startIsLeft);
                    var hasTopRight    = site == topRightSite && !(startIsTop && startIsRight);
                    var hasBottomLeft  = site == bottomLeftSite && !(startIsBottom && startIsLeft);
                    var hasBottomRight = site == bottomRightSite && !(startIsBottom && startIsRight);

                    if (startIsTop)
                    {
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, topRight, currentNode);
                        }
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomRight, currentNode);
                        }
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomLeft, currentNode);
                        }
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topLeft, currentNode);
                        }
                    }
                    else if (startIsRight)
                    {
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, bottomRight, currentNode);
                        }
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomLeft, currentNode);
                        }
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topLeft, currentNode);
                        }
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topRight, currentNode);
                        }
                    }
                    else if (startIsBottom)
                    {
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, bottomLeft, currentNode);
                        }
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topLeft, currentNode);
                        }
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topRight, currentNode);
                        }
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomRight, currentNode);
                        }
                    }
                    else if (startIsLeft)
                    {
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, topLeft, currentNode);
                        }
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topRight, currentNode);
                        }
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomRight, currentNode);
                        }
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomLeft, currentNode);
                        }
                    }

                    previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, end, currentNode);
                }
            }

            // Connect up the end of the loop
            previousEdge.next  = firstEdge;
            firstEdge.previous = previousEdge;
            AddLeavingEdge(firstEdge);
        }

        ConnectOpposites(edgesByStartPosition);
    }