Пример #1
0
        Dictionary<Point, int> render(processedResults pr, string filename, bool edges = false)
        {
            List<Node> rivers = pr.rivers;
            List<Point> oceans = pr.oceans;
            List<Point> lakes = pr.lakes;

            List<Node> rendernodes = new List<Node>();
            foreach (Node r in rivers) // rendernodes are different from river nodes in that they are not necessarily actual river trees.
                // They should sometimes be smaller branches of main rivers.
                rendernodes.Add(r);

            List<List<PointF>> curvepoints = new List<List<PointF>>(); // This is the result of this function, a list of list of points for use in drawCurve()
            //
            while (rendernodes.Count > 0)
            {
                List<PointF> points = new List<PointF>();
                Node current = rendernodes.First();
                rendernodes.Remove(current);

                // Initially add the coords to the list.
                points.Add(current.center_coords); // Always starts with the center coords, because the first tile never gets an edge coord set.

                while (current.numChildren() > 0)
                {
                    int largestIndex = current.maxLengthIndex;
                    // Except for the largest index, add every other child node to the rendernodes list as a separate branch.
                    for (int i = 0; i < current._children_.Count; i++)
                    {
                        if (largestIndex != i)
                        {
                            Node newparent = new Node();
                            newparent.center_coords = current.center_coords;
                            newparent.edge_coords = current.edge_coords;
                            newparent.insertChild(current._children_[i]);

                            // Extending new river tree size by 2 for smoother rivers.
                            if (current.parent != null)
                            {
                                Node newnewparent = new Node();
                                newnewparent.center_coords = current.parent.center_coords;
                                newnewparent.edge_coords = current.edge_coords;
                                newnewparent.insertChild(newparent);
                                rendernodes.Add(newnewparent);
                            }
                            else
                                rendernodes.Add(newparent);
                        }
                    }
                    current = current._children_[largestIndex]; // Finally, change the current to point to the new node.

                    if (edges)
                        points.Add(current.edge_coords);
                    else
                        points.Add(current.center_coords); // Also, extend the pointslist.
                }

                curvepoints.Add(points);
            }

            Bitmap output = new Bitmap(width * scale, height * scale);
            Graphics graphic = Graphics.FromImage(output);
            SolidBrush oceanbrush = new SolidBrush(ocean_c);
            SolidBrush landbrush = new SolidBrush(land_c);
            SolidBrush lakebrush = new SolidBrush(lake_c);

            // Draws the land
            graphic.FillRectangle(landbrush, new Rectangle(0, 0, width * scale, height * scale));

            // Draw rivers
            Pen pen = new Pen(river_c, (float)scale/2.0f);
            Random rng = new Random();

            Dictionary<PointF, PointF> RandPointFromPoint = new Dictionary<PointF, PointF>();

            foreach (var pointlist in curvepoints)
            {
                PointF[] points = pointlist.ToArray();
                for (int i = 0; i < pointlist.Count; i++ ) // Scale coordinates
                {
                    if (RandPointFromPoint.ContainsKey(points[i]))
                        points[i] = RandPointFromPoint[points[i]];
                    else
                    {
                        PointF oldpoint = points[i];

                        points[i].X *= scale;
                        points[i].X += scale / 2;
                        points[i].Y *= scale;
                        points[i].Y += scale / 2;

                        // Experimental: Add noise to coordinates.
                        points[i].X += rng.Next(-scale / 4, scale / 4);
                        points[i].Y += rng.Next(-scale / 4, scale / 4);

                        PointF newpoint = points[i];
                        RandPointFromPoint[oldpoint] = newpoint;
                    }

                }

                if (pointlist.Count == 1)
                    continue;//g.DrawRectangle(pen, new Rectangle(points[0].X, points[0].Y, scale, scale));
                else
                    graphic.DrawCurve(pen, points, 0.4f);
            }

            // Finally, draw the oceans and lakes over the rivers to "hide" the ends of the river.
            foreach (var point in oceans)
            {
                graphic.FillRectangle(oceanbrush, new Rectangle(point.X * scale, point.Y * scale, scale, scale));
            }
            foreach (var point in lakes)
            {
                graphic.FillRectangle(lakebrush, new Rectangle(point.X * scale, point.Y * scale, scale, scale));
            }

            output.Save(filename);
            var result = DictionaryFromBitmap(output);
            output.Dispose();
            return result;
        }
Пример #2
0
 public void insertChild(Node child)
 {
     child.parent = this;
     _children_.Add(child);
 }
Пример #3
0
        void processLakeToRiver(List<Point> lakes, List<Node> rivers, HashSet<Point> done)
        {
            List<Tuple<Point, Point>> possibleRiver = new List<Tuple<Point, Point>>();

            // Add (lake tile, river tile) tuple to possibleRiver.
            foreach (Point lake in lakes)
                foreach (Point dP in neighbors)
                {
                    Point neighbor = dP + (Size)lake;
                    if (isRiver(neighbor))
                    {
                        possibleRiver.Add(new Tuple<Point,Point>(lake, neighbor));
                        break;
                    }
                }

            foreach (Tuple<Point, Point> pts in possibleRiver)
            {
                Dictionary<Point, Node> treeWorking = new Dictionary<Point, Node>();
                Node parent = new Node(pts.Item1);
                parent.insertChild(new Node(pts.Item2));
                Point coords = parent._children_[0].center_coords;
                foreach (Point dP in neighbors)
                {
                    Point neighbor = dP + (Size)coords;
                    if (neighbor != pts.Item1) // Make sure not to double back on the origin lake tile.
                        treeWorking[neighbor] = parent._children_[0];
                }
                buildRiverTrees(done, treeWorking);

                rivers.Add(parent);
            }
        }
Пример #4
0
        void processOceanToRiver(List<Point> oceans, List<Node> rivers, HashSet<Point> done)
        {
            List<Point> possibleRiver = new List<Point>(); // Ocean tiles that touch at least one land tile
            HashSet<Point> working = new HashSet<Point>(); // River tiles that have yet to be added to a tree.

            // Move all land tiles bounding ocean tiles to the possibleRiver list.
            foreach (Point pt in oceans)
                foreach (Point dP in neighbors)
                {
                    Point neighbor = dP + (Size)pt; // Von Neumann neighbors! Because C# does not provide an Addition operator for Point + Point for no good reason, one Point must be cast to Size to get the sum.
                    // Check bounds first.
                    if (0 > neighbor.X || width <= neighbor.X || 0 > neighbor.Y || height <= neighbor.Y)
                        continue;
                    if (isLand(neighbor))
                    {
                        possibleRiver.Add(neighbor);
                    }
                }

            // For every land tile neighbor of the Ocean tile, check if there is river. If there is river, add the river point to the working list.
            foreach (Point pt in possibleRiver)
            {
                foreach (Point dP in neighbors)
                {
                    Point neighbor = dP + (Size)pt;
                    if (isRiver(neighbor) && !working.Contains(neighbor)) // If it's any kind of river plus it hasn't already been added to the list, because duplicates are bad
                    {
                        working.Add(neighbor);
                    }
                }
            }

            // Finally, let's start building River trees.
            while (working.Count > 0)
            {
                Point basePoint = working.First();
                working.Remove(basePoint);
                if (done.Contains(basePoint)) // Skip if the point was already touched.
                    continue;
                done.Add(basePoint); // Mark this point as Done, so future iterations don't accidentally touch it.

                Node parent = null;

                // First, find the land tile connecting this river start and the ocean.
                foreach (Point dP in neighbors)
                {
                    Point neighbor = dP + (Size)basePoint;
                    // For each land tile surrounding the start of the ocean, find the nearest ocean tile and go there.
                    if (isLand(neighbor))
                        foreach (Point ddP in neighbors)
                        {
                            Point neighbor2 = ddP + (Size)neighbor;
                            if (isOcean(neighbor2))
                            {
                                parent = new Node(neighbor2);
                                parent.insertChild(new Node(neighbor));
                                parent._children_[0].insertChild(new Node(basePoint));
                                goto exit;
                            }
                        }
                }
                if (parent == null)
                    parent = new Node(basePoint);
            exit:
                Dictionary<Point, Node> treeWorking = new Dictionary<Point, Node>(); // This working hashset is for building a river tree. The Node is a reference to the parent of this node.
                // There is no need for a treeDone set because what's done is done.

                // Now, if the parent has children, it means the place we are going to start looking for the river is the third node of the tree.
                if (parent._children_.Count > 0)
                {
                    Node startnode = parent._children_[0]._children_[0];
                    Point startcoords = startnode.center_coords;
                    foreach (Point dP in neighbors)
                    {
                        treeWorking[dP + (Size)startcoords] = startnode;
                    }
                }
                else
                    foreach (Point dP in neighbors)
                    {
                        treeWorking[dP + (Size)basePoint] = parent;
                    }

                buildRiverTrees(done, treeWorking);

                // At this point, the river tree should be fully built. Add the parent node to a list of rivers.
                rivers.Add(parent);
            }
        }
Пример #5
0
        // This function is a bit different. If a river is encountered while floodfilling the map that is not in the "done" hashset, the river must be crawled in both directions until it meets /any/ end.
        // A river tree can then be created.
        void processInlandRivers(List<Node> rivers, HashSet<Point> done)
        {
            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                {
                    Point coord = new Point(x, y);
                    if (isRiver(coord) && !done.Contains(coord))
                    {
                        // It's a river, and it hasn't already been covered by the other processors.
                        HashSet<Point> searchDone = new HashSet<Point>(); // A sort of "temporary" "done" HashSet.
                        List<Point> working = new List<Point>();
                        Node start = null;

                        working.Add(coord);
                        while (working.Count > 0)
                        {
                            Point current = working.First();
                            working.Remove(current);
                            searchDone.Add(current);
                            int numNeighbors = 0;
                            foreach (Point dP in neighbors)
                            {
                                Point neighbor = dP + (Size)current;
                                if (isRiver(neighbor) && !searchDone.Contains(neighbor)) // Must check that we haven't already been to this river tile to prevent perpetual cycling.
                                {
                                    working.Add(neighbor);
                                    numNeighbors++;
                                }
                            }
                            if (numNeighbors == 0) // We have reached the end of the line.
                            {
                                start = new Node(current);
                                break;
                            }
                        }

                        if (start == null)
                            throw new ArgumentNullException("Could not find starting point for node at " + coord.ToString());

                        // Now that we have a starting place...
                        Dictionary<Point, Node> treeWorking = new Dictionary<Point, Node>();
                        foreach (Point dP in neighbors)
                        {
                            treeWorking[dP + (Size)start.center_coords] = start;
                        }
                        buildRiverTrees(done, treeWorking);

                        rivers.Add(start);
                    }
                }
        }
Пример #6
0
 // Building the actual river tree is identical, whether we start from the ocean or a lake
 // Here, treeWorking contains tiles to investigate for riverness along with the parent node they started from.
 void buildRiverTrees(HashSet<Point> done, Dictionary<Point, Node> treeWorking)
 {
     while (treeWorking.Count > 0) // Next, keep working on tiles until there are no more left to work on.
         {
             Point pt = treeWorking.Keys.First();
             Node myParent = treeWorking[pt];
             // move to done.
             treeWorking.Remove(pt);
             if (done.Contains(pt))
                 continue;
             done.Add(pt);
             if (isLake(pt)) // If it's a lake, add the tile as the final node.
             {
                 Node lake = new Node(pt);
                 myParent.insertChild(lake);
                 continue;
             }
             else if (!isRiver(pt)) // If it's not a river, don't work on it.
                 continue;
             // Make new node and add to parent node of this one.
             Node me = new Node(pt);
             myParent.insertChild(me);
             // Check neighbors for riverness.
             foreach (Point dP in neighbors)
             {
                 Point neighbor = dP + (Size)pt;
                 if (isRiver(neighbor) || isLake(neighbor))
                     treeWorking[neighbor] = me; // Needs to add this node as a reference in the data.
             }
         }
 }
Пример #7
0
 static void startTranslate(Node parent, int depth = 0)
 {
     if (parent._children_.Count == 0)
         return;
     for (int i = 0; i < parent._children_.Count; i++)
         recursiveTranslate(parent, parent._children_[i], depth);
 }
Пример #8
0
        // Semi-recursive function to move all points in a river tree to the edges from the centers.
        static void recursiveTranslate(Node previous, Node next, int depth)
        {
            Node current = previous;
            Node following = next;

            following.edge_coords = edgifyNodes(current, following);
            current = following;
            while (current._children_.Count == 1) // Don't call the recursive function needlessly if there's no need to
            {
                following = current._children_[0];
                following.edge_coords = edgifyNodes(current, following);
                current = following;
            }
            if (depth > 100)
                Console.ReadKey();
            // At this point, either this has more than 1 child or has no children
            if (current._children_.Count > 1)
            {
                startTranslate(current, depth + 1);
                /*for (int i = 0; i < current._children_.Count; i++)
                {
                    recursiveTranslate(current, current._children_[i], depth+1);
                }*/
            }
        }
Пример #9
0
        static PointF edgifyNodes(Node n1, Node n2)
        {
            PointF p1 = n1.center_coords;
            PointF p2 = n2.center_coords;
            PointF p3 = new Point();
            if (p1.X == p2.X && p1.Y != p2.Y)
            {
                p3.X = p1.X;
                p3.Y = (p1.Y + p2.Y) / 2;
            }
            else if (p1.X != p2.X && p1.Y == p2.Y)
            {
                p3.X = (p1.X + p2.X) / 2;
                p3.Y = p1.Y;
            }
            else
                throw new InvalidOperationException("Node n1 and n2 are equal or at diagonals to each other.");

            return p3;
        }