/// <summary> /// Cycles through a list of points and creates a fractal /// version of the points by splitting each one in half and /// moving it a random amount. /// </summary> /// <returns>A true if at least one point was changed.</returns> public static bool StaggerPoints( CenterPointList points, MersenneRandom random, float minimumDistance) { // Ignores blanks and null if (points == null) throw new ArgumentException("points cannot be null"); if (random == null) throw new ArgumentException("random cannot be null"); if (points.Count < 2) return false; // Go through each set of points CenterPointList newPoints = new CenterPointList(); bool changed = false; for (int i = 0; i < points.Count - 1; i++) { // Get the points CenterPoint p1 = points[i]; CenterPoint p2 = points[i + 1]; // Add the first point newPoints.Add(p1); // Get the distance float distance = CalculateDistance(p1.Point, p2.Point); if (distance > minimumDistance) { // These two are far enough to calculate a new point CenterPoint mp = new CenterPoint((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); float delta = distance * Constants.FractalDecay; float diff = random.NextSingle(-delta, delta); // Calculate the new point float dy = p2.Y - p1.Y; float dx = p2.X - p1.X; if (dy == 0) { // This is a horizontal line mp.Y += diff; } else if (dx == 0) { // This is a vertical line mp.X += diff; } else { // Figure out the slope of the line double theta1 = Math.Tanh(dy / dx); double theta2 = theta1 - Math.PI / 2; mp.X = (float) (mp.X + diff * Math.Cos(theta2)); mp.Y = (float) (mp.Y + diff * Math.Sin(theta2)); } // Add the created point newPoints.Add(mp); changed = true; } // Add the second point newPoints.Add(p2); } // See if we changes something if (changed) { // Swap the points points.Clear(); points.AddAll(newPoints); newPoints.Clear(); } // Return our status return changed; }
/// <summary> /// Loops through the points and staggers them repeatedly. /// </summary> public static void StaggerPoints( CenterPointList points, MersenneRandom random, float minimumDistance, int passes) { // Go through the minimum number of passes for (int i = 0; i < passes; i++) { if (!StaggerPoints(points, random, minimumDistance)) break; } }
/// <summary> /// Creates a segment from a child junction to its parent. /// </summary> public Segment Create( Junction child, PointF childPoint, double distance) { // Sanity checking if (child.ParentJunction == null) throw new Exception("Cannot generate with a null parent"); // Get the distance between the two points Segment segment = new Segment(); Junction parent = child.ParentJunction; // Add the two end points CenterPointList points = new CenterPointList(); points.Add(new CenterPoint(0, 0)); points.Add(new CenterPoint(childPoint)); // Split apart the line #if DEBUG Stopwatch stopwatch = Stopwatch.StartNew(); #endif // Stagger (fractalize) the points Geometry.StaggerPoints(points, parent.Random, Constants.MinimumSegmentDistance, Constants.StaggerSegmentPasses); #if DEBUG // Show timing information stopwatch.Stop(); Log.Debug("Fractal Time: {0}", stopwatch.Elapsed); stopwatch.Reset(); stopwatch.Start(); #endif // Once we generated a set of center points, we go through // and add a randomly-sized and angled square to each // point, unioning the results to get the shape of the // entire segment. IPoly shape = null; float log = 0; if (distance > 0) log = (float) Math.Log(distance) * 10; foreach (CenterPoint point in points) { // Keep track of our retries int retry = 1; while (true) { // Create a shape IPoly p = Geometry.CreateShape(parent, point.Point, retry * (Constants.SegmentAverageWidth - log)); // If we have no shape, this is automatically // included. if (shape == null) { shape = p; break; } // We have another shape, so we want to build up // an intersection to make sure they are touching. if (!shape.HasIntersection(p)) { // If there is no intersection, then we need // to try again and make the radius range larger. retry++; continue; } // Make a union of the two shapes IPoly union = shape.Union(p); // See if we have two shapes if (union.InnerPolygonCount > 1) { // We didn't quite reach each other retry++; continue; } // Set the new shape shape = union; break; } } // Remove both junction shapes from this //shape = shape.Difference(parent.InternalShape); //shape = shape.Difference(child.InternalShape); #if DEBUG // Show timing information stopwatch.Stop(); Log.Debug(" Shape Time: {0}", stopwatch.Elapsed); stopwatch.Reset(); stopwatch.Start(); #endif // Add the shape to the list segment.InternalShape = shape; // Set up the center line and optimize it segment.CenterPoints.AddAll(points); segment.CenterPoints.Optimize(); #if DEBUG // Show timing information stopwatch.Stop(); Log.Debug("Optimze Time: {0}", stopwatch.Elapsed); #endif // Return the results return segment; }