Version 0 of 2D Integer-based Rotations

Updated 2006-04-01 21:47:33

George Peter Staplin April 1, 2006 - The code that follows performs 2D rotations by using scaling and a precomputed table. The table is generated using sin() and cos(), but it could easily be generated once, and the need for floating point completely eliminated.

Miguel Sofer responded to my question about how to do this, and quite graciously volunteered to write the majority of this code. I wrote the graphical part.


http://www.xmission.com/~georgeps/images/wiki/2D_integer-based_rotations.png


# # This is a joint project -- # by Miguel Sofer (primarily) and George Peter Staplin #

package require Tk

# # This is used by the test procedure to compare the irot result with drot. # proc drot {x y a} {

    set a [expr {($a*acos(0))/90}];# convert to radians
    set c [expr {cos($a)}]
    set s [expr {sin($a)}]
    list [expr {int(round($x*$c-$y*$s))}] [expr {int(round($x*$s+$y*$c))}]

}

# create the table set Cos {}; set Sin {} set M expr {pow(2,30)} set Coeff expr {acos(0)/90} for {set a 0} {$a <= 45} {incr a} {

    set A [expr {$Coeff*$a}]
    lappend Cos [expr {int($M*cos($A))}]
    lappend Sin [expr {int($M*sin($A))}]

} set M expr {int($M)}

proc ifun a {

    global Cos Sin

    set a [expr {$a%360}]
    # sign of sin and sign of cos
    set ss 1; set sc 1

    # Insure -180<$a<=180
    if {$a > 180} {
        set a [expr {$a-360}]
    }

    # Consider negative angles; after this 0<=$a<=180
    if {$a < 0} {
        set ss [expr {-$ss}]
        set a [expr {-$a}]
    }

    # Convert to first quadrant
    if {$a > 90} {
        set sc [expr {-$sc}]
        set a [expr {180-$a}]
    }

    # Lookup only the first 45 degrees
    if {$a <= 45} {
        set cos [expr {$sc*[lindex $Cos $a]}]
        set sin [expr {$ss*[lindex $Sin $a]}]
    } else {
        set a [expr {90-$a}]
        set cos [expr {$sc*[lindex $Sin $a]}]
        set sin [expr {$ss*[lindex $Cos $a]}]
    }

    list $cos $sin

}

proc irot {x y a} {

    global M
    foreach {c s} [ifun $a] break

    set c [expr {wide($c)}]
    set s [expr {wide($s)}]

    set xx [expr {int(($x*$c-$y*$s)/$M)}]
    set yy [expr {int(($x*$s+$y*$c)/$M)}]

    list $xx $yy

}

proc test {x y a} {

    list [irot $x $y $a] [drot $x $y $a]

}

proc point {win x y} {

    $win create rectangle $x $y [expr {$x + 4}] [expr {$y + 4}] -fill white
    $win create text [expr {$x + 5}] [expr {$y - 5}] -text "$x,$y" -fill white

}

proc draw.circle {win radius centerx centery} {

    set lastx [expr {$centerx + $radius}]
    set lasty [expr {$centery + $radius}]

    for {set d 1} {$d < 360} {incr d} {
        set rot [irot $radius $radius $d]
        set x [lindex $rot 0] ; set y [lindex $rot 1]

        set x [expr {$x + $centerx}] ; set y [expr {$y + $centery}]

        $win create line $lastx $lasty $x $y -fill white
        set lastx $x ; set lasty $y
    }

    point $win $centerx $centery

}

proc main {} {

    wm title . "Miguel and George's Excellent Adventure!"
    pack [canvas .c] -fill both -expand 1

    draw.circle .c 50 100 100
    draw.circle .c 25 200 200
    draw.circle .c 50 300 100

} main


Category Image Processing