Class 8 Recursive Pictures r Recursivelydefined curves r
























- Slides: 24
Class 8 - Recursive Pictures r Recursively-defined curves r The Hilbert curve 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 1
Recursive drawings r Many shapes are “self-similar” - their overall structure is repeated in sub-pictures. r Peano curve: 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 2
Recursive drawings (cont. ) “Koch snowflake”: 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 3
Recursive drawings (cont. ) 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 4
The Hilbert Curve r Created by David Hilbert (1862 -1943), this is a “space-filling” curve. r Hilbert curve of order n is constructed from four copies of the Hilbert curve of order n-1, properly oriented and connected. 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 5
Hilbert curves of order 1 & 2 HC(1): HC(2): 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 6
Hilbert curve of order 3 HC(3): 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 7
Hilbert curve of order 4 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 8
Hilbert curve of order 5 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 9
The Hilbert Curve Pattern Hilbert curves have “open” side on left: n-1 n-1 Form H. C. of order n by combining four copies of H. C. of order n-1, plus three connecting n-1 lines (of length sl): 22/2/00 SEM 107 © Kamin & Reddy n-1 Class 8 - Hilbert’s curve - 10
Recursive definition of H. C. This leads to the basic recursive pattern for defining HC(order, sl): int diam = size of HC of order n-1; hcsub 1 = HC(order-1, sl); hcul = rotate hcsub 1 by -90 degrees; hcur = translate hcsub 1 to (diam+sl, 0); hclr = translate hcsub 1 to (diam+sl, diam+sl); hcll = rotate hcsub 1 by 90 degrees, then translate to (0, diam+sl); hc = append(hcul, append(hcur, append(hclr, hcll))); return hc, with three lines added; 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 11
Translation We have already seen how to translate a Line. List: static Line. List translate (Line. List L, int x, int y) { if (L. empty()) return L; else { Line ln = L. hd(); Line trans. Line = new Line(ln. x 0()+x, ln. y 0()+y, ln. x 1()+x, ln. y 1()+y); return LL. cons(trans. Line, translate(L. tl(), x, y)); } } 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 12
Rotation is more complicated. Consider rotating one point around the origin by angle : (x’, y’) (x, y) 22/2/00 1. Calculate m and m = x 2+y 2 = tan-1(y/x) 2. = + 3. (x’, y’) = point of length m, at angle SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 13
Rotation (cont. ) We’ll rotate shapes (i. e. Line. List’s) about the origin by rotating each line: static Line. List rotate. Shape. About. Origin (Line. List L, double theta) { if (L. empty()) return LL. nil; else return LL. cons(rotate. Line(L. hd(), theta), rotate. Shape. About. Origin(L. tl(), theta)); } 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 14
Rotation (cont. ) Rotating individual lines around the origin is a matter of rotating both endpoints, as we have indicated. Some added complexity comes from two factors: m Math. atan returns angles in the range - /2 to /2 (i. e. only angles in the right half-plane) m The graphics coordinate system is “upsidedown” relative to ordinary Cartesian coordinates. 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 15
Rotation (cont. ) static Line rotate. Line (Line ln, double theta) { int x 0 = ln. x 0(), y 0 = -ln. y 0(), // turn coordinates rightside-up x 1 = ln. x 1(), y 1 = -ln. y 1(); // turn coordinates rightside-up double currangle 0 = Math. atan((double)y 0/x 0); double newangle 0 = currangle 0+theta; if (x 0<0) newangle 0 = newangle 0 + Math. PI; double mag 0 = Math. sqrt(x 0*x 0+y 0*y 0); int newx 0 = (int)Math. round(mag 0*Math. cos(newangle 0)); int newy 0 = -(int)Math. round(mag 0*Math. sin(newangle 0)); 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 16
Rotation (cont. ) double currangle 1 = Math. atan((double)y 1/x 1); double newangle 1 = currangle 1+theta; if (x 1<0) newangle 1 = newangle 1 + Math. PI; double mag 1 = Math. sqrt(x 1*x 1+y 1*y 1); int newx 1 = (int)Math. round(mag 1*Math. cos(newangle 1)); int newy 1 = -(int)Math. round(mag 1*Math. sin(newangle 1)); return new Line(newx 0, newy 0, newx 1, newy 1); } 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 17
Rotation (cont. ) One remaining technicality: when we say “rotate a shape”, we usually mean, “rotate it around its center”. However, so far we know only how to rotate a shape around the origin. The rotate. Shape method takes a shape and an angle and a point (x, y) which is taken to be the center of the shape. 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 18
Rotation (cont. ) It does so by translating the shape, then rotating, then translating back: static Line. List rotate. Shape (Line. List L, double theta, int x, int y) { Line. List trans. L = translate(L, -x, -y); Line. List rotate. L = rotate. Shape. About. Origin(trans. L, theta); return translate(rotate. L, x, y); } 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 19
The Hilbert Curve Recall again the abstract version of HC(order, sl): int diam = size of HC of order n-1; hcsub 1 = HC(order-1, sl); hcul = rotate hcsub 1 by -90 degrees; hcur = translate hcsub 1 to (diam+sl, 0); hclr = translate hcsub 1 to (diam+sl, diam+sl); hcll = rotate hcsub 1 by 90 degrees, then translate to (0, diam+sl); hc = append(hcul, append(hcur, append(hclr, hcll))); return hc, with three lines added; 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 20
Hilbert Curve (cont. ) We can now say that the rotation steps should rotate the shape around the center of the Hilbert curve of order n-1. That center is at (diam/2, diam/2). How do we calculate diam? A review of the Hilbert curve of various orders show that HC(n-1) has diameter ( 2 n-1 -1)*sl. This leads to our solution: 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 21
The HC Method static Line. List HC (int order, int sl) { if (order == 1) return LL. cons(new Line(0, 0, sl, 0), LL. cons(new Line(sl, 0, sl), LL. nil))); else { int diam = sl*(int)(Math. pow(2, order-1)-1); // diameter of HC(order-1) int radius = diam/2; Line. List hcsub 1 = HC(order-1, sl); 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 22
The HC Method (cont. ) Line. List hcul = rotate. Shape(hcsub 1, -Math. PI/2, radius); Line. List hcur = translate(hcsub 1, diam+sl, 0); Line. List hclr = translate(hcsub 1, diam+sl); Line. List hcll = translate( rotate. Shape(hcsub 1, Math. PI/2, radius), 0, diam+sl); Line. List hc = append(hcul, append(hcur, append(hclr, hcll))); 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 23
The HC Method (cont. ) hc = LL. cons(new Line(diam, 0, diam+sl, 0), LL. cons(new Line(diam+sl, diam+sl), LL. cons(new Line(diam+sl, 2*diam+sl, diam, 2*diam+sl), hc))); return hc; } } 22/2/00 SEM 107 © Kamin & Reddy Class 8 - Hilbert’s curve - 24