class DrawCommon def initialize( canvas ) @canvas = canvas end def get_item_coords( item ) coord = item.coords coord_array = [] x = coord.shift y = coord.shift while x != nil coord_array.push( [x.to_f, y.to_f] ) x = coord.shift y = coord.shift end coord_array end def set_coords( item, coord_array ) eval "item.coords( #{ coord_array.flatten.join(',')} )" end def min_max( coord_array, index ) temp = coord_array.collect{|c| c[index]} [ temp.min, temp.max ] end def center( coord_array ) x_min, x_max = min_max( coord_array, 0 ) y_min, y_max = min_max( coord_array, 1 ) x = ( x_min + x_max ) / 2.0 y = ( y_min + y_max ) / 2.0 [x, y] end def axis_shift( coord_array, center ) x0, y0 = center coord_array.collect{|c| [ c[0]-x0, c[1]-y0 ] } end def axis_shift_reverse( coord_array, center ) x0, y0 = center coord_array.collect{|c| [ c[0]+x0, c[1]+y0 ] } end def linear_map( coord_array, matrix ) center = center( coord_array ) temp = axis_shift( coord_array, center ) temp = temp.collect{|c| x = c[0]*matrix[0] + c[1]*matrix[1] y = c[0]*matrix[2] + c[1]*matrix[3] [x, y] } axis_shift_reverse( temp, center ) end def linear_map_with_center( coord_array, matrix, center ) temp = axis_shift( coord_array, center ) temp = temp.collect{|c| x = c[0]*matrix[0] + c[1]*matrix[1] y = c[0]*matrix[2] + c[1]*matrix[3] [x, y] } axis_shift_reverse( temp, center ) end def mirror [-1, 0, 0, 1] end def enlarge( ratio ) [ ratio, 0, 0, ratio ] end def rotate_90 [ 0, 1, -1, 0] end def rotate_degree( degree ) radian = Math::PI * degree / 180.0 cos = Math.cos( radian ) sin = Math.sin( radian ) [cos, sin, -sin, cos] end def get_item_tag( item ) tags = item.gettags a_tag = tags.pop while ( a_tag == 'current' or a_tag == 'selected' ) a_tag = tags.pop end a_tag end def transform( item, matrix ) a_tag = get_item_tag( item ) if a_tag.kind_of? Numeric coord = get_item_coords( item ) temp = linear_map( coord, matrix ) set_coords( item, temp ) else coord = get_item_coords( item ) center = center( coord ) items = @canvas.find_withtag( a_tag ) items.each{|itm| coord = get_item_coords( itm ) temp = linear_map_with_center( coord, matrix, center ) set_coords( itm, temp ) } end end def transform_at_cursor( matrix ) item = @canvas.find_withtag('current').shift transform( item, matrix ) end end class TkdSize < DrawCommon def bind( ratio ) TkRoot.new.cursor('hand2') @canvas.itembind('item', '1', proc{ transform_at_cursor( enlarge( ratio ) ) }) end end class TkdRotate90 < DrawCommon def bind TkRoot.new.cursor('hand2') @canvas.itembind('item', '1', proc{ transform_at_cursor( rotate_90 ) }) end end class TkdRotate < DrawCommon def button_down(x, y) @canvas.dtag 'selected' $coords_org = [] item = @canvas.find_withtag('current').shift tag = @canvas.gettags('current')[-2] @canvas.addtag_withtag 'selected', tag items = @canvas.find_withtag('selected') items.each{|itm| $coords_org.push( get_item_coords( itm ) )} crd = @canvas.bbox('selected') $cx, $cy = (crd[2] + crd[0])/2.0, (crd[3] + crd[1])/2.0 $x0, $y0 = x, y end def button_motion( x, y ) degree = ($x0 - x) * 2 rotator( rotate_degree( degree ) ) end def rotator( matrix ) a_tag = 'selected' center = [$cx, $cy] items = @canvas.find_withtag( a_tag ) items.each_index{|i| coord = $coords_org[i] temp = linear_map_with_center( coord, matrix, center ) set_coords( items[i], temp ) } end def bind TkRoot.new.cursor('hand2') @canvas.itembind('item', '1', proc{|x, y| button_down(x, y)}, "%x %y") @canvas.itembind('item', 'B1-Motion', proc{|x, y| button_motion(x, y)}, "%x %y") end end class TkdMirror < DrawCommon def bind TkRoot.new.cursor('hand2') @canvas.itembind('item', '1', proc{ transform_at_cursor( mirror ) }) end end