2007-09-30 EH A simple sample to plot a 3D surface for function f(x,y). Use left button to rotate scene, right button to zoom in/out.
# Load packages package require Tk package require scene proc hsv2rgb {h s v} { if {$s<1.e-6} { return [list $v $v $v] } set h [expr {fmod($h/60.,6.)}] set f [expr {fmod($h,1.)}] set p [expr {$v*(1.-$s)}] set q [expr {$v*(1.-$s*$f)}] set t [expr {$v*(1.-$s*(1.-$f))}] if {$h<1.0} { return [list $v $t $p] } if {$h<2.0} { return [list $q $v $p] } if {$h<3.0} { return [list $p $v $t] } if {$h<4.0} { return [list $p $q $v] } if {$h<5.0} { return [list $t $p $v] } return [list $v $p $q] } proc plot3dShape {w} { variable plot3d if {![info exists plot3d(shape)] || !$plot3d(shape)} { set plot3d(shape) 1 $w render } } proc plot3dRedraw {w clist} { variable plot3d foreach l $clist { $w lcall $l } if {[info exists plot3d(shape)] && $plot3d(shape)} { # Capture scene content with transparency # into a Tk photo set img [$w dump] # Apply shape catch {shape set [winfo toplevel $w] -bound photo $img} # Drop image image delete $img } } proc plot3d {w f} { set xmin -1 set xmax 1 set ymin -1 set ymax 1 set zmin 0.0 set zmax 0.0 set nbx 50 set nby 50 set gridx 2 set gridy 2 for {set nx 0} {$nx<=$nbx} {incr nx} { for {set ny 0} {$ny<=$nby} {incr ny} { set x [expr {$xmin+(($xmax-$xmin)*$nx)/double($nbx)}] set y [expr {$ymin+(($ymax-$ymin)*$ny)/double($nby)}] set z [eval $f $x $y] if {$z<$zmin} { set zmin $z } if {$z>$zmax} { set zmax $z } set vertex($nx,$ny) [list $x $y $z] } } # Compile list set surfaceid [$w lbegin] # Draw surface $w enable offset $w begin quads for {set nx 0} {$nx<$nbx} {incr nx} { for {set ny 0} {$ny<$nby} {incr ny} { set z [lindex $vertex($nx,$ny) 2] # Up side (in color) if {0} { set hue [expr {360.0*(0.2+0.7*($z-$zmin)/($zmax-$zmin))}] set color [hsv2rgb $hue 1.0 0.8] $w color $color } else { set red [expr {0.2+(0.7*$nx)/double($nbx)}] set green [expr {0.2+(0.7*$ny)/double($nby)}] set blue [expr {0.2+0.7*($z-$zmin)/($zmax-$zmin)}] $w color [list $red $green $blue] } eval $w vertex $vertex($nx,$ny) incr ny eval $w vertex $vertex($nx,$ny) incr nx eval $w vertex $vertex($nx,$ny) incr ny -1 eval $w vertex $vertex($nx,$ny) incr nx -1 # Down side (in grayscale) set gray [expr {0.5+0.45*($z-$zmin)/($zmax-$zmin)}] $w color $gray eval $w vertex $vertex($nx,$ny) incr nx eval $w vertex $vertex($nx,$ny) incr ny eval $w vertex $vertex($nx,$ny) incr nx -1 eval $w vertex $vertex($nx,$ny) incr ny -1 } } $w end $w disable offset $w lend # Draw grid set gridid [$w lbegin] $w color [list 0 0 0] for {set nx 0} {$nx<=$nbx} {incr nx $gridx} { $w begin line_strip for {set ny 0} {$ny<=$nby} {incr ny} { eval $w vertex $vertex($nx,$ny) } $w end } for {set ny 0} {$ny<=$nby} {incr ny $gridy} { $w begin line_strip for {set nx 0} {$nx<=$nbx} {incr nx} { eval $w vertex $vertex($nx,$ny) } $w end } $w lend # Draw bbox set boxid [$w lbegin] $w color [list 30 20 20] $w begin line_loop $w vertex $xmin $ymin $zmin $w vertex $xmax $ymin $zmin $w vertex $xmax $ymax $zmin $w vertex $xmin $ymax $zmin $w vertex $xmin $ymin $zmin $w end $w begin line_loop $w vertex $xmin $ymin $zmax $w vertex $xmax $ymin $zmax $w vertex $xmax $ymax $zmax $w vertex $xmin $ymax $zmax $w vertex $xmin $ymin $zmax $w end foreach x [list $xmin $xmax] { foreach y [list $ymin $ymax] { $w begin lines $w vertex $x $y $zmin $w vertex $x $y $zmax $w end } } $w lend # Callback to redraw/render scene set cmd [list plot3dRedraw $w [list $surfaceid $gridid $boxid]] $w configure -redraw $cmd } # Function to plot proc f {x y} { return [expr {cos(16.*($x*$x+$y*$y))/(1.+16.*($x*$x+$y*$y))}] } proc main {} { set w [scene .toto -width 320 -height 320 -bg black] pack $w -fill both -expand true $w navigate -mode camera $w enable cull_face plot3d $w f # Adding transparency (to see desktop behind scene) is still experimental #wm overrideredirect [winfo toplevel $w] 1 #if {![catch {package require shape}]} { # bind $w <Button-3> [list after idle [list plot3dShape $w]] #} tkwait window $w return } main exit
Category 3D Graphics