Sierpinski pentagon: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Perl 6}}: fix off-by-one error, stabilize display coordinates, rename some variables, add image link)
m (→‎{{header|Perl 6}}: reduce unnecessary repetition in SVG file, reduce file size by 40%)
Line 124: Line 124:
Generate an SVG file to STDOUT. Redirect to a file to capture and display it.
Generate an SVG file to STDOUT. Redirect to a file to capture and display it.
<lang perl6>constant order = 5;
<lang perl6>constant order = 5;
constant $dim = 500;
constant $dim = 250;
constant $sides = 5;
constant $sides = 5;
constant scaling-factor = ( 3 - 5**.5 ) / 2;
constant scaling-factor = ( 3 - 5**.5 ) / 2;
Line 132: Line 132:
<?xml version="1.0" standalone="no"?>
<?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">
<!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">
<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
STOP
END say '</svg>';
END say '</svg>';
Line 143: Line 144:
};
};


sub pgon (@q) {
sub pgon (@q) { qq|<polygon points="{@q}"/>| }
</lang>
qq|<polygon points="{@q}" style="fill:blue" transform="translate($dim,$dim) rotate(-18)" />|;
}</lang>


See [https://gist.github.com/thundergnat/c1b6cde8fff98dcd3f1e#file-pentaflake-svg 5th order pentaflake]
See [https://gist.github.com/thundergnat/c1b6cde8fff98dcd3f1e#file-pentaflake-svg 5th order pentaflake]

Revision as of 16:38, 15 November 2015

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 = 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( $_ * 2 * pi / $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>

See 5th order pentaflake

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>