220 likes | 354 Views
CSE 20232 Lecture 36 – Procedural Fractals. Line replacement approach Koch Star (Snowflake) Area replacement approach Sierpenski Triangle Iterated Function System approach Heighway Dragon. Line replacement.
E N D
CSE 20232Lecture 36 – Procedural Fractals • Line replacement approach • Koch Star (Snowflake) • Area replacement approach • Sierpenski Triangle • Iterated Function System approach • Heighway Dragon
Line replacement • Fractal shapes are based on lines or curves that are replaced by sequences of similar lines or curves at each level of recursion • Shapes are “self-similar” • Same/similar shapes at every level • Examples • Koch Star (Snowflake) • Sierpenski Dragon • Heighway Dragon
Area Replacement • Fractal shapes are based on simple shapes that are replaced or “cut out” with collections of the same or similar shapes • Again, these are self-similar at all levels of detail • Examples • Box Fractal (our Square) • Sierpenski Triangle (our Gasket) • Sierpenski Carpet
Iterated Function System • A method of generating a fractal by repeated application of a set of functions • Each application typically moves one point on the fractal to another • Examples • Mandelbrot & Julia Sets (escape time measure) • Heighway Dragon (two functions selected at random) • Fern (4 functions randomly chosen with set frequencies)
Koch Star • Based on 3 Koch Curves (triangle shape) • Start each curve with a line segment • Subdivide segment into thirds • Replace middle third with two sides of an equilateral triangle that would have had the replaced edge segment as its third side • These “bump-outs” always go on the same side of the original line • Original segment after first replacement
Koch Star • Initial shape (3 edges forming an equilateral triangle) • Snowflake shown at detail levels 1, 2, 3, 4 • Images from wikipedia.com
Koch Star // need to pass WinStuff &X or use it globally void KochStar::draw(void) { if (Xwin->isOpen()) { // call function to draw (after subdividing as necessary) // each of the three triangle edges subdivide_edge_and_draw(pt[0],pt[1],depth); subdivide_edge_and_draw(pt[1],pt[2],depth); subdivide_edge_and_draw(pt[2],pt[0],depth); } } // NOTE: the corner points are in the vector<Point> pt; // and each has an x and y coordinate. KochStar is a class // that inherits from Shape and the outline of any shape is // a polygon of edges between point pairs in the sequence // pt[0] to pt[1], pt[1] to pt[2], ..., pt[n-1] to pt[0]
Koch Star edge manipulation void KochStar::subdivide_edge_and_draw( const Point& a, const Point& b, int rec_depth) { if (rec_depth > 1) { // Point ab1 is 1/3 distance from a to b Point ab1( (2.0*a.getx()+b.getx()) / 3.0, (2.0*a.gety()+b.gety()) / 3.0); // Point ab2 is 2/3 distance from a to b Point ab2( (a.getx()+2.0*b.getx()) / 3.0, (a.gety()+2.0*b.gety()) / 3.0); // calculate length of current edge (a,b) double dx = b.getx() - a.getx(); double dy = b.gety() - a.gety(); double L = sqrt(dx*dx + dy*dy);
Koch Star edge manipulation // calculate the direction of the current edge (a,b) double theta = atan2(dy,dx); // increase angle by 60 degrees theta += PI/3.0; if (theta < 0.0) theta = 2.0*PI + theta; // calculate coordinates of point bumped out from triangle // it starts at point ab1 and runs at angle theta for 1/3 the // original edge length double outx = ab1.getx() + L*cos(theta)/3.0; double outy = ab1.gety() + L*sin(theta)/3.0;
Koch Star edge manipulation // create a Point with these coordiantes Point bump(outx,outy); // make recursive calls to further subdivide edges and draw // note: rec_depth is decreased by 1 in each call subdivide_edge_and_draw(a,ab1,rec_depth-1); // edge (a,ab1) subdivide_edge_and_draw(ab1,bump,rec_depth-1); // edge (ab1,bump) subdivide_edge_and_draw(bump,ab2,rec_depth-1); // edge (bump,ab2) subdivide_edge_and_draw(ab2,b,rec_depth-1); // edge (ab2,b) } else // now draw the small edge piece from a to b Xwin->X_draw_edge(a.getx(),a.gety(),b.getx(),b.gety(),colorX); }
Sierpenski Dragon • Based on 4 curves (square shape) • Start each curve with a line segment • Subdivide segment into fourths • Replace middle two segments with three sides of a square that would have had the replaced edge segment as its fourth side • These “bump-outs” always go out and then in • Original segment after first replacement
Sierpenski Dragon • Initial shape (4 edges forming a square) • Dragon shown at detail levels 1, 2, 3
Square Gasket • Based on a square shape • Start with a single square • Replace the square with 5, each having a side length 1/3rd that of the original • Replacement squares go in each corner and the center • Original after 1st replacement after 2nd
Square Gasket void Square::draw() { if (Xwin->isOpen()) { // if this is a depth 1 Square then actually draw it if (depth == 1) // Xlib code to draw 4 edges bounding the square for (int i=0; i<4; i++) Xwin->X_draw_edge(pt[i].getx(),pt[i].gety(), pt[(i+1)%4].getx(),pt[(i+1)%4].gety(), colorX); else // Otherwise, subdivide & draw smaller Squares subdivide_and_draw(); } }
Square subdivision void Square::subdivide_and_draw(void) { double mult=1.0; // 0.5 or other value for interesting shapes if (depth > 1) { // new squares have sides 1/3 length of original double newSide = fabs(pt[0].getx()-pt[2].getx())/3.0; // Center is halfway between opposite corners pt[0] & pt[2] double cx = 0.5*(pt[0].getx()+pt[2].getx()); double cy = 0.5*(pt[0].gety()+pt[2].gety()); // 5 new squares 1/3 side size as originals Square s1(Xwin,Point(cx,cy),newSide); Square s2(Xwin,Point(cx+mult*newSide,cy+mult*newSide),newSide); Square s3(Xwin,Point(cx+mult*newSide,cy-mult*newSide),newSide); Square s4(Xwin,Point(cx-mult*newSide,cy+mult*newSide),newSide); Square s5(Xwin,Point(cx-mult*newSide,cy-mult*newSide),newSide);
Square subdivision // set color of 5 new Squares same as this one int r, g, b; getColor(r,g,b); s1.setColor(r,g,b); s2.setColor(r,g,b); s3.setColor(r,g,b); s4.setColor(r,g,b); s5.setColor(r,g,b); // set depth to 1 less than this Square s1.setDepth(depth-1); s2.setDepth(depth-1); s3.setDepth(depth-1); s4.setDepth(depth-1); s5.setDepth(depth-1); // draw the 5 smaller Squares s1.draw(); s2.draw(); s3.draw(); s4.draw(); s5.draw(); } }
Sierpenski Gasket • Based on a triangle shape • Start with a single triangle • Replace the triangle with 3, each having a side length 1/2 that of the original • Replacement triangles go in each corner • Original after 1st replacement after 2nd
Heighway Dragon • Producible in several ways • Folding • Fold strip of paper in half, again and again, in same direction • Unfold so each fold is 90 degrees and look at shape edge-on • Line replacement • Start with a line (length L) • Replace with two segments L/sqrt(2) forming an isosceles triangle with original • The replace each of these in turn, the same way, but alternate direction of bump, left, right, left, … • Levels of detail 1,2,3,4 from wikipedia.com
Heighway Dragon • Producible in several ways • Iterative Function System • Start with Z as the origin of the complex plane • Randomly alternate between these two functions to derive next point Z from previous • Z = ((1+j)*Z)/2 • Z = 1 –((1-j)*Z)/2 • The UNION of all such points is the Dragon • Example: 100,000 iterations
Heighway Dragon IFS (main) // as in Mandelbrot set program, image size is ROWS x COLUMNS, // complex plane is LEFT..RIGHT, TOP..BOTTOM for (r=0;r<ROWS;r++) for (c=0;c<COLUMNS;c++) image[r][c] = 0; // set all pixels to black Z.setReal(0.0); Z.setImaginary(0.0); for (int i=0; i<count; i++) { nextPoint(Z); // finds next Z in IFS defining dragon r = (int)((TOP-Z.getImaginary())/dy); // find image row c = (int)((Z.getReal()- LEFT)/dx); // find image column if (0 <= r && r < ROWS && 0 <= c && c < COLUMNS) image[r][c] = 32 + i%224; // set pixel color else cout << "bad r,c" << r << ' ' << c << endl; }
Heighway Dragon IFS (calc) // the Heighway Dragon is defined by applying each of the // following functions to the previous value of Z in order // to find the next value of Z. The choice of which to // apply is random. void nextPoint(Complex& Z) { if (rand()%2) Z = 0.5*Complex(1.0,1.0)*Z; else Z = 1.0 - 0.5*Complex(1.0,-1.0)*Z; }
A Fractal Shape Inheritance Hierarchy • Point • Simple location in 2D plane • Shape • Polygon with edges between sequence of Point pairs • KochStar : Shape • Triangle based, edge division and replacement • Square : Shape • Square based, area division and replacement • SerpGasket* : Shape • Triangle based, area subdivision and replacement • SerpDragon* : Shape • Square based, edge division and replacement