%D \module
%D   [       file=meta-imp-experiments,
%D        version=2020.03.18,
%D          title=\METAPOST\ Graphics,
%D       subtitle=Experimental Graphics,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D This library implements some experimental functionality that eventually
%D might end up someplace else.

\startluacode

    -- I decided to play with this kind of graphics after I read an article in a Dutch
    -- popular science journal. It was an article about virusus in the mids of the time
    -- when covid raged, so it also was a distraction.

    -- This is a typical case of first prototyping it in Lua using the 'context' command
    -- to generate MetaPost code and when that worked okay do it the following way. The
    -- way data is passed is a bit messy.

    do

        local function sum(t)
            local n = 0
            for i=1,#t do
                n = n + t[i]
            end
            return n
        end

        local function checked(data)
            if data then
                local n = #data
                for i=1,n do
                    data[i][i] = 0
                end
                for i=1,n do
                    local di = data[i]
                    for j=i+1,n do
                        local dj = data[j]
                        local dji = dj[i]
                        if not dji then
                            dji = 0
                            dj[i] = 0
                        end
                        di[j] = dji
                    end
                end
                return data
            else
                return { }
            end
        end

        local data, list = nil, nil

        function mp.lmt_overlap_prepare()
            data = checked(metapost.getparameter { "data" })
            list = { }
            for i=1,#data do
                list[i] = sum(data[i])
            end
        end

        function mp.lmt_overlap_reset()
            data = nil
            list = nil
        end

        function mp.lmt_overlap_n()
            return #list
        end

        function mp.lmt_overlap_data(i, j)
            if j then
                return data[i][j]
            else
                return list[i]
            end
        end

        local injectstring = mp.inject.string

        function mp.lmt_overlap_text(i, j)
            injectstring(data[i][j] or "")
        end

        function mp.lmt_overlap_label(i)
            local labels = metapost.getparameter { "labels" }
            injectstring(labels and labels[i] or "")
        end

        function mp.lmt_overlap_color(i)
            local colors = metapost.getparameter { "colors" }
            injectstring(colors and colors[i] or "darkgray")
        end

        function mp.lmt_overlap_total()
            return sum(list)
        end

    end
\stopluacode

\startMPextensions

presetparameters "overlap" [
    options     = "paths,lines",
    gap         = 4,
    subgap      = 2,
    offset      = 8,
    color       = "darkgray",
    alternative = "circular",
    colors      = {
        "darkred",
        "darkgreen",
        "darkblue",
        "darkyellow",
        "darkmagenta",
        "darkcyan"
    },
] ;

def lmt_overlap = applyparameters "overlap" "lmt_do_overlap" enddef ;

vardef lmt_do_overlap_circular =

    astep  := 360 / steps ;

    p := fullcircle scaled steps ;
    r := origin -- (2*steps,0) ;

    start := 0 ;
    stop  := 0 ;
    for i=1 upto n:
        stop  := start + lua.mp.lmt_overlap_data(i) ;
        first := start ;
        last  := stop ;
        for j=1 upto n:
            if i <> j :
                last := first + lua.mp.lmt_overlap_data(i,j) ;
                a := p intersectionpoint (r rotated (first * astep + 0.1)) ; % the 0.1 is somehow needed, why
                b := p intersectionpoint (r rotated (last  * astep - 0.1)) ; % the 0.1 is somehow needed, why
                qq[i][j] := (p cutafter b) cutbefore a ;
                first := last + subgap ;
            fi ;
        endfor ;
        start := stop + gap + (n - 1) * subgap ;
    endfor ;

    if hasoption "options" "paths" :

        for i=1 upto n :
            for j=1 upto n :
                if i <> j :
                    q := qq[i][j] ;
                    freelabeloffset := getparameter "offset" ;
                    freelabel(lua.mp.lmt_overlap_text(i,j), point .5 along q, origin) ;
                    if i < j :
                        s := qq[j][i] ;
                        a := point length(q) of q ;
                        b := point 0 of s ;
                        c := point length(s) of s ;
                        d := point 0 of q ;
                        q := q & a .. controls origin and origin .. b & s & c .. controls origin and origin .. d -- cycle ;
                        fill q withcolor lua.mp.lmt_overlap_color(i) withtransparency (1,.8) ;
                    fi ;
                fi ;
            endfor ;
        endfor ;

    fi ;

    if hasoption "options" "lines" :

        start := 0 ;
        stop  := 0 ;
        for i=1 upto n:
            stop := start + lua.mp.lmt_overlap_data(i) + (n - 2) * subgap ;
            a := p intersectionpoint (r rotated (start * astep)) ;
            b := p intersectionpoint (r rotated (stop  * astep)) ;
            q := (p cutbefore a) cutafter b ;
            freelabeloffset := getparameterdefault "textoffset" (4 * getparameter "offset") ;
            freelabel(lua.mp.lmt_overlap_label(i), point .5 along q, origin) ;
            draw q withcolor white withpen pencircle scaled 5 ;
            draw q withcolor getparameter "color" withpen pencircle scaled 5 ;
            start := stop + gap + subgap ;
        endfor ;

    fi ;

enddef ;

vardef lmt_do_overlap_linear =
    astep  := 1 ; % 1.25

    p := origin -- (astep * steps,0) ;
    r := origin -- (0,astep * steps) ;

    start := 0 ;
    stop  := 0 ;
    for i=1 upto n:
        stop  := start + lua.mp.lmt_overlap_data(i) ;
        first := start ;
        last  := stop ;
        for j=1 upto n:
            if i <> j :
                last := first + lua.mp.lmt_overlap_data(i,j) ;
                qq[i][j] := (first * astep,0) -- (last  * astep,0) ;
                first := last + subgap ;
            fi ;
        endfor ;
        start := stop + gap + (n - 1) * subgap ;
    endfor ;

    if hasoption "options" "paths" :

        for i=1 upto n :
            for j=1 upto n :
                if i < j :
                    qq[i][j] := qq[i][j] { up } .. { down } qq[j][i] { up } .. { down} cycle ;
                    fill qq[i][j] withcolor lua.mp.lmt_overlap_color(i) withtransparency (1,.8) ;
                fi ;
            endfor ;
        endfor ;

        for i=1 upto n :
            for j=1 upto n :
                if i < j :
                    t := thelabel(lua.mp.lmt_overlap_text(i,j), (center topboundary qq[i][j]) ) ;
                    fill boundingbox t enlarged (ExHeight/2) withcolor white ;
                    draw t ;
                fi ;
            endfor ;
        endfor ;

    fi ;

    if hasoption "options" "lines" :

        start := 0 ;
        stop  := 0 ;
        for i=1 upto n:
            stop := start + lua.mp.lmt_overlap_data(i) + (n - 2) * subgap ;
            q := (start * astep,0) -- (stop  * astep,0) ;
            freelabeloffset := getparameterdefault "textoffset" (4 * getparameter "offset") ;
            label.bot(lua.mp.lmt_overlap_label(i), (point .5 along q) shifted (0,- freelabeloffset/4)) ;
            draw q withcolor white withpen pencircle scaled 5 ;
            draw q withcolor getparameter "color" withpen pencircle scaled 5 ;
            start := stop + gap + subgap ;
        endfor ;

    fi ;

enddef ;

vardef lmt_do_overlap =
    image (

        pushparameters "overlap" ;

            save p, q, r, s, qq, a, b, c, d, t, n, gap, subgap, steps, astep, start, stop, first, last ;
            path p, q, r, s, qq[][] ;
            pair a, b, c, d ;
            picture t ;
            numeric n, gap, subgap, steps, astep, start, stop, first, last ;
            save freelabeloffset; freelabeloffset := 8 ;
            interim linecap := butt;
            interim linejoin := squared;

            lua.mp.lmt_overlap_prepare() ;

                n      := lua.mp.lmt_overlap_n();
                gap    := getparameter "gap" ;
                subgap := getparameter "subgap" ;
                steps  := lua.mp.lmt_overlap_total() + (n * gap) + n * (n - 1) * subgap ;

                if ((getparameter "alternative") = "linear") or ((getparameter "alternative") = "line") :
                    lmt_do_overlap_linear ;
                else :
                    lmt_do_overlap_circular ;
                fi ;

            lua.mp.lmt_overlap_reset() ;

        popparameters ;
    )
enddef ;

\stopMPextensions

\continueifinputfile{meta-imp-experiments.mkxl}

% \useMPlibrary[experiments]

\usemodule[article-basic]

\starttext

% todo: datafile: { data = { }, labels = { } }

%   % data   = {
%   %     {  0, 10, 30, 10, 20 },
%   %     { 10,  0, 10, 20, 10 },
%   %     { 30, 10,  0,  5, 15 },
%   %     { 10, 20,  5,  0,  5 },
%   %     { 20, 10, 15,  5,  0 }
%   % },
%   % data = {
%   %     {  0 },
%   %     { 10,  0 },
%   %     { 30, 10,  0 },
%   %     { 10, 20,  5,  0 },
%   %     { 20, 10, 15,  5,  0 }
%   % },
%     data = {
%         { },
%         { 10 },
%         { 30, 10 },
%         { 10, 20,  5 },
%         { 20, 10, 15,  5 }
%     },

\startbuffer
\startMPcode{doublefun}
    draw lmt_overlap [
        alternative = "circular",
        data        = { { }, { 10 }, { 30, 10 }, { 10, 20, 5 }, { 20, 10, 15, 5 } },
        labels      = { "one", "two", "three", "four", "five" }
    ] ;
\stopMPcode
\stopbuffer

\startlinecorrection[blank]
    \getbuffer
\stoplinecorrection

\startbuffer
\startMPcode{doublefun}
    draw lmt_overlap [
        alternative = "linear",
        data        = { { }, { 10 }, { 30, 10 }, { 10, 20, 5 }, { 20, 10, 15, 5 } },
        labels      = { "one", "two", "three", "four", "five" }
    ] ;
\stopMPcode
\stopbuffer

\startlinecorrection[blank]
    \getbuffer
\stoplinecorrection

\stoptext
