Sierpinski pentagon: Difference between revisions
Thundergnat (talk | contribs) m →{{header|Perl 6}}: Use tau instead of 2 pi |
→{{header|Java}}: added image |
||
Line 9: | Line 9: | ||
=={{header|Java}}== |
=={{header|Java}}== |
||
[[File:sierpinski_pentagon.png|300px|thumb|right]] |
|||
{{works with|Java|8}} |
{{works with|Java|8}} |
||
<lang java>import java.awt.*; |
<lang java>import java.awt.*; |
Revision as of 11:49, 2 March 2016
Produce a graphical or ASCII-art representation of a Sierpinski pentagon (aka a Pentaflake) of order 5. Your code should also be able to correctly generate representations of lower orders: 1 to 4.
- See also
Java
![](http://static.miraheze.org/rosettacodewiki/thumb/7/7e/Sierpinski_pentagon_java.png/300px-Sierpinski_pentagon_java.png)
<lang java>import java.awt.*; import java.awt.event.ActionEvent; import java.awt.geom.Path2D; import static java.lang.Math.*; import java.util.Random; import javax.swing.*;
public class SierpinskiPentagon extends JPanel {
// exterior angle final double degrees072 = toRadians(72);
/* After scaling we'll have 2 sides plus a gap occupying the length of a side before scaling. The gap is the base of an isosceles triangle with a base angle of 72 degrees. */ final double scaleFactor = 1 / (2 + cos(degrees072) * 2);
final int margin = 20; int limit = 0; Random r = new Random();
public SierpinskiPentagon() { setPreferredSize(new Dimension(640, 640)); setBackground(Color.white);
new Timer(3000, (ActionEvent e) -> { limit++; if (limit >= 5) limit = 0; repaint(); }).start(); }
void drawPentagon(Graphics2D g, double x, double y, double side, int depth) { double angle = 3 * degrees072; // starting angle
if (depth == 0) {
Path2D p = new Path2D.Double(); p.moveTo(x, y);
// draw from the top for (int i = 0; i < 5; i++) { x = x + cos(angle) * side; y = y - sin(angle) * side; p.lineTo(x, y); angle += degrees072; }
g.setColor(RandomHue.next()); g.fill(p);
} else {
side *= scaleFactor;
/* Starting at the top of the highest pentagon, calculate the top vertices of the other pentagons by taking the length of the scaled side plus the length of the gap. */ double distance = side + side * cos(degrees072) * 2;
/* The top positions form a virtual pentagon of their own, so simply move from one to the other by changing direction. */ for (int i = 0; i < 5; i++) { x = x + cos(angle) * distance; y = y - sin(angle) * distance; drawPentagon(g, x, y, side, depth - 1); angle += degrees072; } } }
@Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth(); double radius = w / 2 - 2 * margin; double side = radius * sin(PI / 5) * 2;
drawPentagon(g, w / 2, 3 * margin, side, limit); }
public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Sierpinski Pentagon"); f.setResizable(true); f.add(new SierpinskiPentagon(), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); }
}
class RandomHue {
/* Try to avoid random color values clumping together */ final static double goldenRatioConjugate = (sqrt(5) - 1) / 2; private static double hue = Math.random();
static Color next() { hue = (hue + goldenRatioConjugate) % 1; return Color.getHSBColor((float) hue, 1, 1); }
}</lang>
Perl 6
Generate an SVG file to STDOUT. Redirect to a file to capture and display it. <lang perl6>constant order = 5; constant $dim = 250; constant $sides = 5; constant scaling-factor = ( 3 - 5**.5 ) / 2; my @orders = ((1 - scaling-factor) * $dim) «*» scaling-factor «**» (^order);
INIT say qq:to/STOP/;
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg height="{$dim*2}" width="{$dim*2}" style="fill:blue" transform="translate($dim,$dim) rotate(-18)" version="1.1" xmlns="http://www.w3.org/2000/svg"> STOP
END say '</svg>';
my @vertices = map { cis( $_ * τ / $sides ) }, ^$sides;
for 0 ..^ $sides ** order -> $i {
my $vector = [+] @vertices[$i.base($sides).fmt("%{order}d").comb] «*» @orders; say pgon ((@orders[*-1] * (1 - scaling-factor)) «*» @vertices «+» $vector)».reals».fmt("%0.3f");
};
sub pgon (@q) { qq|<polygon points="{@q}"/>| } </lang>
Racket
<lang racket>#lang racket/base (require racket/draw pict racket/math racket/class)
- exterior angle
(define 72-degrees (degrees->radians 72))
- After scaling we'll have 2 sides plus a gap occupying the length
- of a side before scaling. The gap is the base of an isosceles triangle
- with a base angle of 72 degrees.
(define scale-factor (/ (+ 2 (* (cos 72-degrees) 2))))
- Starting at the top of the highest pentagon, calculate
- the top vertices of the other pentagons by taking the
- length of the scaled side plus the length of the gap.
(define dist-factor (+ 1 (* (cos 72-degrees) 2)))
- don't use scale, since it scales brushes too (making lines all tiny)
(define (draw-pentagon x y side depth dc)
(let recur ((x x) (y y) (side side) (depth depth)) (cond [(zero? depth) (define p (new dc-path%)) (send p move-to x y) (for/fold ((x x) (y y) (α (* 3 72-degrees))) ((i 5)) (send p line-to x y) (values (+ x (* side (cos α))) (- y (* side (sin α))) (+ α 72-degrees))) (send p close) (send dc draw-path p)] [else (define side/ (* side scale-factor)) (define dist (* side/ dist-factor)) ;; The top positions form a virtual pentagon of their own, ;; so simply move from one to the other by changing direction. (for/fold ((x x) (y y) (α (* 3 72-degrees))) ((i 5)) (recur x y side/ (sub1 depth)) (values (+ x (* dist (cos α))) (- y (* dist (sin α))) (+ α 72-degrees)))])))
(define (dc-draw-pentagon depth w h #:margin (margin 4))
(dc (lambda (dc dx dy) (define old-brush (send dc get-brush)) (send dc set-brush (make-brush #:style 'transparent)) (draw-pentagon (/ w 2) (* 3 margin) (* (- (/ w 2) (* 2 margin)) (sin (/ pi 5)) 2) depth dc) (send dc set-brush old-brush)) w h))
(dc-draw-pentagon 1 120 120) (dc-draw-pentagon 2 120 120) (dc-draw-pentagon 3 120 120) (dc-draw-pentagon 4 120 120) (dc-draw-pentagon 5 640 640)</lang>
Sidef
Generates a SVG image to STDOUT. Redirect to a file to capture and display it. <lang ruby>define order = 5 define sides = 5 define dim = 500 define scaling_factor = ((3 - 5**0.5) / 2) var orders = order.of {|i| ((1-scaling_factor) * dim) * scaling_factor**(i-1) }
say <<"STOP"; <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg height="#{dim*2}" width="#{dim*2}"
style="fill:blue" transform="translate(#{dim},#{dim}) rotate(-18)" version="1.1" xmlns="http://www.w3.org/2000/svg">
STOP
var vertices = sides.of {|i| Complex(0, i * Math::tau / sides).exp }
(sides**order).range.each { |i|
var vector = ([vertices.@["%#{order}d" % i.base(sides) -> chars]] »*« orders «+») var points = (vertices »*» orders[-1]*(1-scaling_factor) »+» vector »reals»() «%« '%0.3f') say ('<polygon points="' + points.join(' ') + '"/>')
}
say '</svg>'</lang>