// TODO: Land-locked rivers // TODO?: Add the one river tile connecting ocean and river. // TODO: smoother curvier rivers processedResults process() { HashSet <Point> done = new HashSet <Point>(); // River tiles that have been added to a river tree List <Point> oceans = new List <Point>(); // Tiles that are definitely ocean. List <Point> lakes = new List <Point>(); // ditto but for lakes List <Node> rivers = new List <Node>(); // List of parent nodes of finished river trees. // FLOOD FILL AND PUT ALL OCEAN TILES INTO OCEAN LIST // LAKES IN THE LAKE LIST for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Point current = new Point(x, y); if (isOcean(current)) { oceans.Add(current); } else if (isLake(current)) { lakes.Add(current); } } } // Build rivers that start from the ocean processOceanToRiver(oceans, rivers, done); // Build rivers that start from lakes! processLakeToRiver(lakes, rivers, done); // Build rivers that start from land! processInlandRivers(rivers, done); // Update tail length counts. foreach (Node n in rivers) { n.getMaxTailLength(); } ////// TEST: FUNCTION TO MOVE VERTEXES TO EDGE FROM CENTER SEMI-RECURSIVELY for (int i = 0; i < rivers.Count; i++) { startTranslate(rivers[i]); } processedResults prout = new processedResults(); prout.rivers = rivers; prout.oceans = oceans; prout.lakes = lakes; return(prout); }
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; }
// TODO: Land-locked rivers // TODO?: Add the one river tile connecting ocean and river. // TODO: smoother curvier rivers processedResults process() { HashSet<Point> done = new HashSet<Point>(); // River tiles that have been added to a river tree List<Point> oceans = new List<Point>(); // Tiles that are definitely ocean. List<Point> lakes = new List<Point>(); // ditto but for lakes List<Node> rivers = new List<Node>(); // List of parent nodes of finished river trees. // FLOOD FILL AND PUT ALL OCEAN TILES INTO OCEAN LIST // LAKES IN THE LAKE LIST for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { Point current = new Point(x, y); if (isOcean(current)) oceans.Add(current); else if (isLake(current)) lakes.Add(current); } // Build rivers that start from the ocean processOceanToRiver(oceans, rivers, done); // Build rivers that start from lakes! processLakeToRiver(lakes, rivers, done); // Build rivers that start from land! processInlandRivers(rivers, done); // Update tail length counts. foreach (Node n in rivers) n.getMaxTailLength(); ////// TEST: FUNCTION TO MOVE VERTEXES TO EDGE FROM CENTER SEMI-RECURSIVELY for (int i = 0; i < rivers.Count; i++) { startTranslate(rivers[i]); } processedResults prout = new processedResults(); prout.rivers = rivers; prout.oceans = oceans; prout.lakes = lakes; return prout; }
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); }