Sierpinski pentagon

From Rosetta Code
Revision as of 02:47, 11 November 2015 by Thundergnat (talk | contribs) (→‎{{header|Perl 6}}: Added implemaentation)
Sierpinski pentagon is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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

Works with: Java version 8

<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

Works with: rakudo version 2015-11-02

Generate an SVG file to STDOUT. Redirect to a file to capture and display it. <lang perl6>constant $order = 5; constant $dim = 1000; constant $sides = 5; constant factor = ( 3 - 5**.5 ) / 2; my @orders = (.6 * $dim) «*» factor «**» (^$order);

my @tr = (0, (-900,1700), (-100,1450), (350,1250), (550,1200), (1000,1000));

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}" version="1.1" xmlns="http://www.w3.org/2000/svg">
   STOP

END say '</svg>';

my @vertices = map { cis( $_ * 2 * pi / $sides ) }, ^$sides;

for 0 .. $sides ** $order -> $i {

  my $vector = [+] @vertices[$i.base($sides).fmt("%05d").comb] «*» @orders;
  say pgon ((@orders[*-1] * (1-factor)) «*» @vertices «+» $vector)».reals».fmt("%0.3f");

};

sub pgon (*@q) {

 qq:to/STOP/;
   <polygon points="{@q}"
   style="fill:blue;stroke:blue;stroke-width:0"
   transform="translate({@tr[$order]}) rotate(-18)" />
   STOP

}</lang>

Racket

Translation of: Java

<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>