Rebol3 Code Examplex


Harriss Spiral

Draw the Harris spiral pattern.

Rebol [
    title: "Rosetta code: Harriss Spiral"
    file:  %Harriss_Spiral.r3
    url:   https://rosettacode.org/wiki/Harriss_Spiral
    needs: Blend2D
]

hariss-spiral: function/with [
    options [block! map!]
][
    turtle-pos:   options/start          ;; starting position (pair!)
    turtle-angle: options/angle          ;; starting heading in degrees
    limit:        any [options/limit 9]  ;; minimum segment length - stops recursion
    start-length: any [options/start-length 400]

    clear turtle-stack
    append clear draw-cmds [
        ;fill 20.20.20 fill-all           ;; dark background
        line-cap 2
        pen off fill off line-width 1
    ]
    to-harriss :start-length :limit 1    ;; kick off recursive drawing
    draw options/size draw-cmds
][
    hsr: 1.3247179                       ;; plastic constant — the Harriss spiral ratio

    ;; Turtle state
    turtle-pos:   0x0                    ;; current position (pair!)
    turtle-angle: 0.0                    ;; current heading (degrees, 0 = right, 90 = down)

    turtle-stack: []                     ;; saved turtle states for push/pop
    draw-cmds:    []                     ;; accumulated Draw dialect commands

    push-turtle: does [
        ;; save pos + heading
        repend turtle-stack [turtle-pos turtle-angle]
    ]
    pop-turtle: does [
        ;; restore last frame
        set [turtle-pos turtle-angle] take/part/last turtle-stack 2
    ]

    turn-left:  func [deg] [turtle-angle: turtle-angle - deg]
    turn-right: func [deg] [turtle-angle: turtle-angle + deg]

    draw-arc: func [
        radius sweep-deg dir                                ;; dir: 1 = left turn, -1 = right turn
        /local center start-ang end-ang r b color
    ][
        dir: negate dir                                     ;; flip: screen Y-axis is inverted

        center: turtle-pos + either dir = 1 [
            as-pair (radius * cosine (turtle-angle + 90))   ;; center is left of heading
                    (radius * sine   (turtle-angle + 90))
        ][
            as-pair (radius * cosine (turtle-angle - 90))   ;; center is right of heading
                    (radius * sine   (turtle-angle - 90))
        ]

        start-ang: arctangent2 turtle-pos - center          ;; angle from center to turtle

        end-ang: either dir = 1 [
            start-ang + sweep-deg
        ][  start-ang - sweep-deg ]

        ;; brightness by radius: large arcs bright, small arcs dark
        r: min 1.0 max 0.0 (radius - 5) / 395.0             ;; 0 = small, 1 = large
        b: 100 + (r * 155)                                  ;; brightness 100–255
        color: to tuple! reduce [b  b * 0.6  b * 0.3]

        append draw-cmds compose [
            pen (color) line-width (radius / 10)
            arc (center) (as-pair radius radius) (start-ang) (sweep-deg * dir)
        ]

        turtle-pos: center + as-pair                        ;; advance turtle to arc's endpoint
            (radius * cosine end-ang)
            (radius * sine   end-ang)

        turtle-angle: turtle-angle + (sweep-deg * dir)      ;; update heading
    ]

    to-curve: func [len dir] [
        draw-arc (len * (square-root 2) / 2) 90 dir         ;; inscribed quarter-circle
        turn-left 180                                       ;; reverse direction for next branch
    ]

    to-harriss: func [len lim dir] [
        if len > lim [                                      ;; base case: stop when segment is too small
            to-curve len dir
            push-turtle
            to-harriss (len / 1.8) lim 1                    ;; smaller sub-spiral (≈ 1/φ² branch)
            pop-turtle
            turn-left 180
            to-harriss (len / hsr) lim 1                    ;; larger sub-spiral (1/plastic-constant branch)
            turn-right 90
        ]
    ]
]

img: hariss-spiral [
    size:  1000x800
    start: 570x750
    angle: 315
    start-length: 400
    limit: 3
]

browse save %Harriss_Spiral.png img