# tko_matrix.tcl --
#
#       Matrix support procedures for the path widget.
#
#  Copyright (c) <2018 r.zaumseil@freenet.de>

# All functions inside this namespace return a transformation matrix.
namespace eval ::tko::matrix {
    namespace export *
    namespace ensemble create
}

# Get rotate matrix.
# angle - Angle in grad
# cx    - X-center coordinate
# cy    - Y-center coordinate
# Returns the transformation matrix.
proc ::tko::matrix::rotate {angle cx cy} {
    set myCos [expr {cos(0.0174532925199433*$angle)}]
    set mySin [expr {sin(0.0174532925199433*$angle)}]
    if {$cx == 0 && $cy == 0} {
        return [list $myCos $mySin [expr {-1.*$mySin}] $myCos 0 0]
    }
    return [list $myCos $mySin [expr {-1.*$mySin}] $myCos \
        [expr {$cx - $myCos*$cx + $mySin*$cy}] \
        [expr {$cy - $mySin*$cx - $myCos*$cy}]]
}

# Get scale matrix.
# sx    - Scaling factor x-coordinate
# sy    - Scaling factor y-coordinate
# Returns the transformation matrix.
proc ::tko::matrix::scale {sx {sy {}}} {
    if {$sy eq {}} {set sy $sx}
    return [list $sx 0 0 $sy 0 0]
}

# Get flip matrix.
# fx    - 1 no flip, -1 horizontal flip
# fy    - 1 no flip, -1 vertical flip
# Returns the transformation matrix.
proc ::tko::matrix::flip {{cx 0} {cy 0} {fx 1} {fy 1}} {
    return [list $fx 0 0 $fy [expr {$cx*(1-$fx)}] [expr {$cy*($fy-1)}]]
}

# Get rotate+flip matrix.
# angle - Angle in grad
# cx    - X-center coordinate
# cy    - Y-center coordinate
# fx    - 1 no flip, -1 horizontal flip
# fy    - 1 no flip, -1 vertical flip
# Returns the transformation matrix.
proc ::tko::matrix::rotateflip {{angle 0} {cx 0} {cy 0} {fx 1} {fy 1}} {
    set myCos [expr {cos(0.0174532925199433*$angle)}]
    set mySin [expr {sin(0.0174532925199433*$angle)}]
    if {$cx == 0 && $cy == 0} {
    return [list [expr {$fx*$myCos}] [expr {$fx*$mySin}] \
        [expr {-1.*$mySin*$fy}] [expr {$myCos*$fy}] 0 0]
    }
    return [list [expr {$fx*$myCos}] [expr {$fx*$mySin}] \
        [expr {-1.*$mySin*$fy}] [expr {$myCos*$fy}] \
        [expr {$myCos*$cx*(1.-$fx) - $mySin*$cy*($fy-1.) + $cx - $myCos*$cx + $mySin*$cy}] \
        [expr {$mySin*$cx*(1.-$fx) + $myCos*$cy*($fy-1.) + $cy - $mySin*$cx - $myCos*$cy}] \
    ]

}

# Get skew in x direction matrix.
# angle - Angle in grad
# Returns the transformation matrix.
proc ::tko::matrix::skewx {angle} {
    return [list 1 0 [expr {tan($angle)}] 1 0 0]
}

# Get skew in y direction matrix.
# angle - Angle in grad
# Returns the transformation matrix.
proc ::tko::matrix::skewy {angle} {
    return [list 1 [expr {tan($angle)}] 0 1 0 0]
}

# Get move matrix.
# dx    - Difference in x direction
# dy    - Difference in y direction
# Returns he transformation matrix.
proc ::tko::matrix::move {dx dy} {
    return [list 1 0 0 1 $dx $dy]
}

# Get multiple result of matrices.
# ma    - First matrix
# mb    - Second matrix
# Returns the product of transformation matrices.
proc ::tko::matrix::mult {ma mb} {
    lassign $ma a1 b1 c1 d1 x1 y1
    lassign $mb a2 b2 c2 d2 x2 y2
    return [list \
        [expr {$a1*$a2 + $c1*$b2}] [expr {$b1*$a2 + $d1*$b2}] \
        [expr {$a1*$c2 + $c1*$d2}] [expr {$b1*$c2 + $d1*$d2}] \
        [expr {$a1*$x2 + $c1*$y2 + $x1}] [expr {$b1*$x2 + $d1*$y2 + $y1}]]
}

# Get ellipse path definition.
# x     - Start x coordinate
# y     - Start y coordinate
# rx    - Radius in x direction
# ry    - Radius in y direction
# Returns the path definition.
proc ::tko::path::ellipse {x y rx ry} {
    return [list M $x $y a $rx $ry 0 1 1 0 [expr {2*$ry}] a $rx $ry 0 1 1 0 [expr {-2*$ry}] Z]
}

# Get circle path definition.
# x     - Start x coordinate
# y     - Start y coordinate
# r     - Radius of circle
# Returns the path definition.
proc ::tko::path::circle {x y r} {
    return [list M $x $y a $r $r 0 1 1 0 [expr {2*$r}] a $r $r 0 1 1 0 [expr {-2*$r}] Z]
}

# Utility function to create named example gradient definitions.
# name  - the name of the gradient
# rainbow   - Gradient in rainbow style.
# Returns the stops list.
proc ::tko::path::gradientstopsstyle {name args} {
    switch -- $name {
    rainbow {
        return {
            {0.00 "#ff0000"}
            {0.15 "#ff7f00"}
            {0.30 "#ffff00"}
            {0.45 "#00ff00"}
            {0.65 "#0000ff"}
            {0.90 "#7f00ff"}
            {1.00 "#7f007f"}
        }
    }
    default {
        return -code error "the named gradient '$name' is unknown"
    }
    }
}

# vim: set ts=4 sw=4 sts=4 ff=unix et :
