cxdraw{⎕IO ⎕ML←0 1                         ⍝ Complex function drawing.

    draw←{                                  ⍝ MouseMove callback.
        _ _ y x _ _←⍵                       ⍝ mouse coords.
        ⍺←y x                               ⍝ previous coords (default here).
        a.onMouseMove←'draw'(y x)           ⍝ starting coords for next segment.
        from←↑⍺(y x)                        ⍝ domain endpoints.
        _from poly blue                    ⍝ blue domain line.
        intorange from                     ⍝ draw range line in segments.
        coords(y x)into                    ⍝ update coords in form Caption.
    }

    marks←{                                 ⍝ double click: mark domain & range.
        _ _ y x _ _←⍵                       ⍝ mouse pointer coords.
        _y x mark 1 blue                   ⍝ domain marker
        into←⊃↓app under zg 3 2⍴y x         ⍝ maps_to (range) point.
        _into mark 1 red                   ⍝ range marker.
        coords(y x)into                    ⍝ update coords in form Caption.
    }

    range←{                                 ⍝ draw range line in segments.
        dom←⍵[0;]-[1](0.01×⍳101)∘.×-⌿⍵      ⍝ 100 domain line segments.
        rngapp under zg dom                ⍝ corresponding range points.
        into←,¯1 2↑rng                      ⍝ final points for coords fn.
        ~1∊(rng)∊⍳101:into                 ⍝ no range points visible: quit.
        cut←100<÷⌿+/|2-/[1]↑rng dom         ⍝ cut where red/blue slope > 100.
        ~1∊cut:intorng poly red            ⍝ no discontinuity: draw red line.
        eps←{⊖2 2↑¯1⊖⍵}                     ⍝ endpoints of range.
        1↑cut:∇ eps 1↓dom                   ⍝ first point is cut: ignore it
        ¯1↑cut:∇ eps ¯1↓dom                 ⍝ last point is cut: ignore it.
        ⊃⌽∇∘eps¨(1,cut)⊂[0]dom              ⍝ draw both halves of line.
    }

    app←⍺⍺{                                 ⍝ complex function application
        11::zg ¯1 ¯1                        ⍝ overflow: map to off-screen.
        5::∇¨under(↓∘⍉)⍵                    ⍝ ⍺⍺ refuses array: try each point.
        cx←1 0J1∘(+.×)                      ⍝ complex from coords
        cd←9 11∘(∘.○)                       ⍝ coords from complex
        0=⎕NC'⍺':cd ⍺⍺ cx ⍵                 ⍝ monadic application
        cd(cx)⍺⍺ cx ⍵                     ⍝ dyadic application
    }                                       ⍝ :: [C] → [C]

    plane←{                                 ⍝ complex plane.
        f←⎕NEW⊂'Form'                       ⍝ containing form
        f.(Posn Size)←(3 0)(60 45)          ⍝ top(ish) left.
        f.Caption←⍵                         ⍝ ref to new form.
        f.onKeyPress←'keyp'                 ⍝ esc to quit.

        coof.Coord                         ⍝ store current prop.
        f.Coord←'Pixel'                     ⍝ change prop.
        f.(Size←2⍴⌊/Size)                   ⍝ make form square.
        f.Coordcoo                         ⍝ reset  prop.

        af.⎕NEW⊂'Static'                   ⍝ white backdrop.
        a.(Posn Size)←(0 0)(100 100)        ⍝ occupies whole form.

        line←{⍺.⎕NEW'Poly'⍵}                ⍝ new line.

        fmto←{'Points'(↓⍉↑⍵)}               ⍝ points property for gui.
        a.rea linefmto 50,¨0 100          ⍝ real axis.
        a.ima linefmto 100 0,¨50          ⍝ imaginary axis.

        posn←'Points'(50-50÷⍺ ⍺)            ⍝ bounding
        size←'Size'(100÷⍺ ⍺)                ⍝   square of
        aa.uca.⎕NEW'Ellipse'(posn size)   ⍝     unit "circle".
    }

    down←{                                  ⍝ MouseDown:
        1≡4⊃⍵:a.onMouseMove←'draw'          ⍝ lft: start drawing.
        2≡4⊃⍵:(a a).Visible←0 1             ⍝ rgt: clear screen.
    }
    stop←{a.onMouseMove←0}                  ⍝ MouseUp: stop drawing.
    keyp←{'EP'≡2⊃⍵:2 ⎕NQ a.##'Close'}       ⍝ Esc key: quit.

    coords←{                                ⍝ domain and range coords.
        nums←~∘' '¨8 2∘⍕¨⍉zg ⍵              ⍝ format of coords to 2 dec places.
        glue←{↑,∘(⍺∘,)/⍵}                   ⍝ ⍺-join vector ⍵.
        text←' -> 'glue↓'j'glue nums        ⍝ 'fm -> to'
        a.##.Caption←'cxdraw ',text         ⍝ display in Caption of Form.
    }

    mbrot←{                                 ⍝ poor man's Mandelbrot.
        _ _ y x _ _←⍵                       ⍝ mouse pointer coords.
        to←,app⍣10⍨zg↑,↓y x                 ⍝ after 10 iterations.
        2∧.≥|to:y x mark 0                  ⍝ in-bounds: mark point.
    }

    zg←↑∘((⍵÷100÷2 ¯2)∘×)∘↓∘(-∘50)∘⊖∘⍉      ⍝ scale: complex from gui coords.
    under{⍵⍵⍣¯1 ⍺⍺ ⍵⍵ ⍵}                   ⍝ aka "dual".

    red blue←{'FCol'(⍵↑255)}¨3 ¯3           ⍝ red and blue line colours.
    mark←{'a.'⎕WC'Marker'⍺,⍵}               ⍝ unnamed marker object.
    poly←{'a.'⎕WC'Poly'⍺ ⍵}                 ⍝ unnamed poly object.

    a←⍵ plane⊃⎕SI                           ⍝ complex plane.

    ⍺←0 ⋄ _←⍺{                              ⍝ regular drawing or mandelbrot?
        ⍺:a.onMouseMove←'mbrot'             ⍝ mandelbrot: set callback.
        a.onMouseDown←'down'                ⍝ otherwise: regular drawing.
        a.onMouseDblClick←'marks'           ⍝ double-click to mark.
        1:a.onMouseUp←'stop'                ⍝ release to stop drawing.
    }⍵

    ⎕DQ a.##                                ⍝ await events.
}

code_colours

test script

Back to: notes

Back to: Workspaces