Changeset 1254
- Timestamp:
- Dec 3, 2008, 2:32:26 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gui/scripts/nanovisviewer.tcl
r1250 r1254 1 2 # ---------------------------------------------------------------------- 1 #!/usr/bin/wish 2 # ---------------------------------------------------------------------- 3 4 3 5 # COMPONENT: nanovisviewer - 3D volume rendering 4 6 # … … 37 39 itcl::class Rappture::NanovisViewer { 38 40 inherit Rappture::VisViewer 39 41 40 42 itk_option define -plotforeground plotForeground Foreground "" 41 43 itk_option define -plotbackground plotBackground Background "" 42 44 itk_option define -plotoutline plotOutline PlotOutline "" 43 44 constructor { hostlist args } { 45 Rappture::VisViewer::constructor $hostlist 46 } { 47 # defined below 48 } 49 destructor { 50 # defined below 45 46 constructor { hostlist args } { 47 Rappture::VisViewer::constructor $hostlist 48 } { 49 # defined below 50 } 51 destructor { 52 # defined below 51 53 } 52 54 public proc SetServerList { namelist } { 53 55 Rappture::VisViewer::SetServerList "nanovis" $namelist 54 56 } 55 57 public method add {dataobj {settings ""}} … … 57 59 public method delete {args} 58 60 public method scale {args} 59 public method GetLimits { tf } 61 public method GetLimits { tf } 60 62 public method download {option args} 61 public method parameters {title args} { 62 # do nothing 63 public method parameters {title args} { 64 # do nothing 63 65 } 64 66 public method isconnected {} … … 93 95 protected method _fixLegend {} 94 96 95 # The following methods are only used by this class. 97 # The following methods are only used by this class. 96 98 private method _NameTransferFunction { ivol } 97 99 private method _ComputeTransferFunction { tf } … … 119 121 private variable isomarkers_ ;# array of isosurface level values 0..1 120 122 private common settings_ 121 private variable activeTf_ "" ;# The currently active transfer function. 122 123 124 125 123 private variable activeTf_ "" ;# The currently active transfer function. 124 # This 125 # indicates which isomarkers and transfer 126 # function to use when changing markers, 127 # opacity, or thickness. 126 128 #common _downloadPopup ;# download options from popup 127 129 } … … 500 502 # Bindings for zoom via keyboard 501 503 bind $itk_component(3dview) <KeyPress-Prior> \ 502 504 [itcl::code $this _zoom out] 503 505 bind $itk_component(3dview) <KeyPress-Next> \ 504 506 [itcl::code $this _zoom in] 505 507 506 508 bind $itk_component(3dview) <Enter> "focus $itk_component(3dview)" 507 509 508 510 if {[string equal "x11" [tk windowingsystem]]} { 509 510 511 511 # Bindings for zoom via mouse 512 bind $itk_component(3dview) <4> [itcl::code $this _zoom out] 513 bind $itk_component(3dview) <5> [itcl::code $this _zoom in] 512 514 } 513 515 … … 626 628 # USAGE: delete ?<dataobj1> <dataobj2> ...? 627 629 # 628 # 629 # 630 # 630 # Clients use this to delete a dataobj from the plot. If no dataobjs 631 # are specified, then all dataobjs are deleted. No data objects are 632 # deleted. They are only removed from the display list. 631 633 # 632 634 # ---------------------------------------------------------------------- … … 737 739 set result [VisViewer::Connect $_hosts] 738 740 if { $result } { 739 740 741 741 set w [winfo width $itk_component(3dview)] 742 set h [winfo height $itk_component(3dview)] 743 _send "screen $w $h" 742 744 } 743 745 return $result … … 782 784 append outbuf_ $string "\n" 783 785 } else { 784 785 786 786 foreach line [split $string \n] { 787 SendEcho >>line $line 788 } 787 789 SendBytes $string 788 790 } … … 814 816 set _id2obj($ivol) [list $dataobj $comp] 815 817 set _obj2id($dataobj-$comp) $ivol 816 818 _NameTransferFunction $ivol 817 819 set _receiveids($ivol) 1 818 820 } … … 828 830 _send "up $axis" 829 831 } 830 831 832 833 834 832 # The active transfer function is by default the first component of 833 # the first data object. This assumes that the data is always 834 # successfully transferred. 835 set comp [lindex [$first components] 0] 836 set activeTf_ $_id2style($_obj2id($first-$comp)) 835 837 } 836 838 foreach key [array names _obj2id *-*] { 837 839 set state [string match $first-* $key] 838 840 set ivol $_obj2id($key) 839 841 _send "volume state $state $ivol" 840 842 } … … 850 852 851 853 if 0 { 852 854 # Add this when we fix grid for volumes 853 855 _send "volume axis label x \"\"" 854 856 _send "volume axis label y \"\"" … … 868 870 itcl::body Rappture::NanovisViewer::_SendTransferFunctions {} { 869 871 if { $activeTf_ == "" } { 870 872 return 871 873 } 872 874 set tf $activeTf_ … … 886 888 887 889 if { ![info exists $_obj2styles($first)] } { 888 889 890 891 890 foreach tf $_obj2styles($first) { 891 _ComputeTransferFunction $tf 892 } 893 _fixLegend 892 894 } 893 895 } … … 903 905 itcl::body Rappture::NanovisViewer::_ReceiveImage {option size} { 904 906 if { [isconnected] } { 905 906 907 global counter 908 incr counter 907 909 set bytes [ReceiveBytes $size] 908 910 $_image(plot) configure -data $bytes … … 914 916 # _ReceiveLegend -- 915 917 # 916 # 917 # 918 # 919 # 920 # 921 # 922 # 923 # 924 # 918 # The procedure is the response from the render server to each "legend" 919 # command. The server sends back a "legend" command invoked our 920 # the slave interpreter. The purpose is to collect data of the image 921 # representing the legend in the canvas. In addition, the isomarkers 922 # of the active transfer function are displayed. 923 # 924 # I don't know is this is the right place to display the isomarkers. 925 # I don't know all the different paths used to draw the plot. There's 926 # "_rebuild", "add", etc. 925 927 # 926 928 itcl::body Rappture::NanovisViewer::_ReceiveLegend { tf vmin vmax size } { 927 929 if { ![isconnected] } { 928 930 return 929 931 } 930 932 set bytes [ReceiveBytes $size] 931 933 $_image(legend) configure -data $bytes 932 934 ReceiveEcho <<line "<read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>" 933 935 934 936 set c $itk_component(legend) 935 937 set w [winfo width $c] … … 939 941 set ly [expr {$h - 1}] 940 942 if {"" == [$c find withtag transfunc]} { 941 942 943 944 945 946 947 948 949 943 $c create image 10 10 -anchor nw \ 944 -image $_image(legend) -tags transfunc 945 $c create text $lx $ly -anchor sw \ 946 -fill $itk_option(-plotforeground) -tags "limits vmin" 947 $c create text [expr {$w-$lx}] $ly -anchor se \ 948 -fill $itk_option(-plotforeground) -tags "limits vmax" 949 $c lower transfunc 950 $c bind transfunc <ButtonRelease-1> \ 951 [itcl::code $this _AddIsoMarker %x %y] 950 952 } 951 953 # Display the markers used by the active transfer function. … … 955 957 $c itemconfigure vmin -text [format %.2g $limits(min)] 956 958 $c coords vmin $lx $ly 957 959 958 960 $c itemconfigure vmax -text [format %.2g $limits(max)] 959 961 $c coords vmax [expr {$w-$lx}] $ly 960 962 961 963 if { [info exists isomarkers_($tf)] } { 962 963 964 964 foreach m $isomarkers_($tf) { 965 $m Show 966 } 965 967 } 966 968 } … … 969 971 # _ReceiveData -- 970 972 # 971 # The procedure is the response from the render server to each "data972 # 973 # 974 # 975 # 976 # tell us what the limits are. Once we've received the limits to all977 # 978 # 979 # 980 # 981 # 982 # back what the data limits are. It means that much of the code983 # 984 # 985 # the data limits. The client code is much messier because of986 # this. The alternative is to parse any of the 3D formats on the987 # client side.973 # The procedure is the response from the render server to each "data 974 # follows" command. The server sends back a "data" command invoked our 975 # the slave interpreter. The purpose is to collect the min/max of the 976 # volume sent to the render server. Since the client (nanovisviewer) 977 # doesn't parse 3D data formats, we rely on the server (nanovis) to 978 # tell us what the limits are. Once we've received the limits to all 979 # the data we've sent (tracked by _receiveids) we can then determine 980 # what the transfer functions are for these volumes. 981 # 982 # 983 # Note: There is a considerable tradeoff in having the server report 984 # back what the data limits are. It means that much of the code 985 # having to do with transfer-functions has to wait for the data 986 # to come back, since the isomarkers are calculated based upon 987 # the data limits. The client code is much messier because of 988 # this. The alternative is to parse any of the 3D formats on the 989 # client side. 988 990 # 989 991 itcl::body Rappture::NanovisViewer::_ReceiveData { args } { 990 992 if { ![isconnected] } { 991 993 return 992 994 } 993 995 # Arguments from server are name value pairs. Stuff them in an array. 994 996 array set info $args 995 997 996 set ivol $info(id); 997 998 set limits_($ivol-min) $info(min); 999 set limits_($ivol-max) $info(max); 1000 set limits_(vmin) $info(vmin);# Overall minimum value.1001 set limits_(vmax) $info(vmax); 998 set ivol $info(id); # Id of volume created by server. 999 1000 set limits_($ivol-min) $info(min); # Minimum value of the volume. 1001 set limits_($ivol-max) $info(max); # Maximum value of the volume. 1002 set limits_(vmin) $info(vmin); # Overall minimum value. 1003 set limits_(vmax) $info(vmax); # Overall maximum value. 1002 1004 1003 1005 unset _receiveids($ivol) 1004 1006 if { [array size _receiveids] == 0 } { 1005 1007 UpdateTransferFunctions 1006 1008 } 1007 1009 } … … 1017 1019 if { [isconnected] } { 1018 1020 set bytes [ReceiveBytes $size] 1019 1020 1021 1021 set f [open /tmp/junk "w"] 1022 puts $f $bytes 1023 close $f 1022 1024 $_image(download) configure -data $bytes 1023 1025 update 1024 1026 puts stderr "<read $size bytes for [image width $_image(download)]x[image height $_image(download)] image>" 1025 1027 } … … 1038 1040 1039 1041 foreach tf [array names isomarkers_] { 1040 1042 foreach m $isomarkers_($tf) { 1041 1043 $m Hide 1042 1044 } … … 1050 1052 # Find any new data that needs to be sent to the server. Queue this up on 1051 1053 # the _sendobjs list, and send it out a little at a time. Do this first, 1052 # before we rebuild the rest. 1054 # before we rebuild the rest. 1053 1055 foreach dataobj [get] { 1054 1056 set comp [lindex [$dataobj components] 0] … … 1070 1072 _send "camera angle $xyz" 1071 1073 _send "camera zoom $view_(zoom)" 1072 1074 1073 1075 _fixSettings light 1074 1076 _fixSettings transp 1075 _fixSettings isosurface 1077 _fixSettings isosurface 1076 1078 _fixSettings grid 1077 1079 _fixSettings axes … … 1081 1083 # send off new data objects 1082 1084 $_dispatcher event -idle !send_dataobjs 1083 1084 } 1085 return 1086 } 1085 1087 1086 1088 # nothing to send -- activate the proper ivol 1087 1089 set first [lindex [get] 0] 1088 1090 if {"" != $first} { 1089 1090 1091 1092 1093 1094 1095 1096 1097 # 1098 1099 1100 1101 # But this problem needs to be fixed not bandaided. 1102 1103 set ivol $_obj2id($first-$comp) 1104 1105 1106 1107 1108 1109 1091 set axis [$first hints updir] 1092 if {"" != $axis} { 1093 _send "up $axis" 1094 } 1095 foreach key [array names _obj2id *-*] { 1096 set state [string match $first-* $key] 1097 _send "volume state $state $_obj2id($key)" 1098 } 1099 # 1100 # The _obj2id and _id2style arrays may or may not have the right 1101 # information. It's possible for the server to know about volumes 1102 # that the client has assumed it's deleted. We could add checks. 1103 # But this problem needs to be fixed not bandaided. 1104 set comp [lindex [$first components] 0] 1105 set ivol $_obj2id($first-$comp) 1106 1107 foreach comp [$first components] { 1108 foreach ivol $_obj2id($first-$comp) { 1109 _NameTransferFunction $ivol 1110 } 1111 } 1110 1112 } 1111 1113 … … 1113 1115 set vols [_currentVolumeIds -cutplanes] 1114 1116 foreach axis {x y z} { 1115 1116 1117 1117 _send "cutplane state [_state ${axis}slice] $axis $vols" 1118 set pos [expr {0.01*[$itk_component(${axis}slicer) get]}] 1119 _send "cutplane position $pos $axis $vols" 1118 1120 } 1119 1121 _send "volume data state [_state volume] $vols" … … 1170 1172 psi 0 1171 1173 zoom 1.0 1172 1173 1174 dx 0 1175 dy 0 1174 1176 } 1175 1177 set xyz [Euler2XYZ $view_(theta) $view_(phi) $view_(psi)] … … 1264 1266 # USAGE: $this _pan click x y 1265 1267 # $this _pan drag x y 1266 # 1268 # $this _pan release x y 1267 1269 # 1268 1270 # Called automatically when the user clicks on one of the zoom … … 1274 1276 set h [winfo height $itk_component(3dview)] 1275 1277 if { $option == "set" } { 1276 1277 1278 1279 1278 set x [expr $x / double($w)] 1279 set y [expr $y / double($h)] 1280 set view_(dx) [expr $view_(dx) + $x] 1281 set view_(dy) [expr $view_(dy) + $y] 1280 1282 _send "camera pan $view_(dx) $view_(dy)" 1281 1282 } 1283 if { $option == "click" } { 1284 1285 1283 return 1284 } 1285 if { $option == "click" } { 1286 set click_(x) $x 1287 set click_(y) $y 1286 1288 $itk_component(3dview) configure -cursor hand1 1287 1289 } 1288 1290 if { $option == "drag" || $option == "release" } { 1289 1290 1291 1292 1293 1294 1295 1291 set dx [expr ($click_(x) - $x)/double($w)] 1292 set dy [expr ($click_(y) - $y)/double($h)] 1293 set click_(x) $x 1294 set click_(y) $y 1295 set view_(dx) [expr $view_(dx) - $dx] 1296 set view_(dy) [expr $view_(dy) - $dy] 1297 _send "camera pan $view_(dx) $view_(dy)" 1296 1298 } 1297 1299 if { $option == "release" } { … … 1347 1349 1348 1350 # show the current value in the readout 1349 1351 #puts "readout: $axis = $newval" 1350 1352 1351 1353 set ids [_currentVolumeIds -cutplanes] … … 1435 1437 opacity { 1436 1438 if {[isconnected] && $activeTf_ != "" } { 1437 1438 1439 1440 1441 1442 1439 set val [$inner.scales.opacity get] 1440 set sval [expr { 0.01 * double($val) }] 1441 set tf $activeTf_ 1442 set settings_($this-$tf-opacity) $sval 1443 UpdateTransferFunctions 1444 } 1443 1445 } 1444 1446 1445 1447 thickness { 1446 1448 if {[isconnected] && $activeTf_ != "" } { 1447 1448 1449 1450 1451 1452 1453 1449 set val [$inner.scales.thickness get] 1450 # Scale values between 0.00001 and 0.01000 1451 set sval [expr {0.0001*double($val)}] 1452 set tf $activeTf_ 1453 set settings_($this-$tf-thickness) $sval 1454 UpdateTransferFunctions 1455 } 1454 1456 } 1455 1457 "outline" { … … 1457 1459 _send "volume outline state $settings_($this-outline)" 1458 1460 } 1459 } 1461 } 1460 1462 "isosurface" { 1461 1463 if {[isconnected]} { 1462 1464 _send "volume shading isosurface $settings_($this-isosurface)" 1463 1465 } 1464 } 1466 } 1465 1467 "grid" { 1466 1468 if { [isconnected] } { … … 1493 1495 _send "legend $activeTf_ $w $h" 1494 1496 } else { 1495 1496 # isomarkers. 1497 1498 1497 # Can't do this as this will remove the items associated with the 1498 # isomarkers. 1499 1500 #$itk_component(legend) delete all 1499 1501 } 1500 1502 } … … 1503 1505 # _NameTransferFunction -- 1504 1506 # 1505 # 1506 # 1507 # 1508 # 1509 # 1510 # 1511 # FIXME: The current way we generate transfer-function names completely1512 # ignores the -markers option. The problem is that we are forced1513 # to compute the name from an increasing complex set of values:1514 # 1515 # 1507 # Creates a transfer function name based on the <style> settings in the 1508 # library run.xml file. This placeholder will be used later to create 1509 # and send the actual transfer function once the data info has been sent 1510 # to us by the render server. [We won't know the volume limits until the 1511 # server parses the 3D data and sends back the limits via _ReceiveData.] 1512 # 1513 # FIXME: The current way we generate transfer-function names completely 1514 # ignores the -markers option. The problem is that we are forced 1515 # to compute the name from an increasing complex set of values: 1516 # color, levels, marker, opacity. I think we're stuck doing it 1517 # now. 1516 1518 # 1517 1519 itcl::body Rappture::NanovisViewer::_NameTransferFunction { ivol } { … … 1533 1535 # _ComputeTransferFunction -- 1534 1536 # 1535 # 1536 # 1537 # 1538 # 1539 # the alpha map of the transfer function.1537 # Computes and sends the transfer function to the render server. It's 1538 # assumed that the volume data limits are known and that the global 1539 # transfer-functions slider values have be setup. Both parts are 1540 # needed to compute the relative value (location) of the marker, and 1541 # the alpha map of the transfer function. 1540 1542 # 1541 1543 itcl::body Rappture::NanovisViewer::_ComputeTransferFunction { tf } { 1542 1544 array set style { 1543 1544 1545 1545 -color rainbow 1546 -levels 6 1547 -opacity 1.0 1546 1548 } 1547 1549 set dataobj ""; set comp "" … … 1563 1565 # maintain a list of markers for each transfer-function. We use the one 1564 1566 # of the volumes (the first in the list) using the transfer-function as a 1565 # reference. 1567 # reference. 1566 1568 # 1567 1569 # FIXME: The current way we generate transfer-function names completely 1568 # 1570 # ignores the -markers option. The problem is that we are forced 1569 1571 # to compute the name from an increasing complex set of values: 1570 1572 # color, levels, marker, opacity. I think the cow's out of the 1571 # 1573 # barn on this one. 1572 1574 1573 1575 if { ![info exists isomarkers_($tf)] } { 1574 1575 1576 1577 1578 1579 1580 } 1576 # Have to defer creation of isomarkers until we have data limits 1577 if { [info exists style(-markers)] } { 1578 _ParseMarkersOption $tf $ivol $style(-markers) 1579 } else { 1580 _ParseLevelsOption $tf $ivol $style(-levels) 1581 } 1582 } 1581 1583 if {$style(-color) == "rainbow"} { 1582 1584 set style(-color) "white:yellow:green:cyan:blue:magenta" … … 1593 1595 set tag $this-$tf 1594 1596 if { ![info exists settings_($tag-opacity)] } { 1595 1597 set settings_($tag-opacity) $style(-opacity) 1596 1598 } 1597 1599 set max $settings_($tag-opacity) … … 1605 1607 1606 1608 if { ![info exists settings_($tag-thickness)]} { 1607 1609 set settings_($tag-thickness) 0.05 1608 1610 } 1609 1611 set delta $settings_($tag-thickness) … … 1621 1623 set x4 [expr {$x+$delta+0.00001}] 1622 1624 if { $x1 < 0.0 } { 1623 set x1 0.0 1625 set x1 0.0 1624 1626 } elseif { $x1 > 1.0 } { 1625 1626 1627 set x1 1.0 1628 } 1627 1629 if { $x2 < 0.0 } { 1628 1630 set x2 0.0 1629 1631 } elseif { $x2 > 1.0 } { 1630 set x2 1.0 1631 1632 set x2 1.0 1633 } 1632 1634 if { $x3 < 0.0 } { 1633 set x3 0.0 1635 set x3 0.0 1634 1636 } elseif { $x3 > 1.0 } { 1635 1636 1637 set x3 1.0 1638 } 1637 1639 if { $x4 < 0.0 } { 1638 set x4 0.0 1639 1640 1640 set x4 0.0 1641 } elseif { $x4 > 1.0 } { 1642 set x4 1.0 1641 1643 } 1642 1644 # add spikes in the middle 1643 lappend wmap $x1 0.0 1645 lappend wmap $x1 0.0 1644 1646 lappend wmap $x2 $max 1645 lappend wmap $x3 $max 1647 lappend wmap $x3 $max 1646 1648 lappend wmap $x4 0.0 1647 1649 } … … 1702 1704 regsub -all "," $levels " " levels 1703 1705 if {[string is int $levels]} { 1704 1705 1706 1707 1708 1709 1706 for {set i 1} { $i <= $levels } {incr i} { 1707 set x [expr {double($i)/($levels+1)}] 1708 set m [IsoMarker \#auto $c $this $tf] 1709 $m SetRelativeValue $x 1710 lappend isomarkers_($tf) $m 1711 } 1710 1712 } else { 1711 1713 foreach x $levels { 1712 1713 1714 1714 set m [IsoMarker \#auto $c $this $tf] 1715 $m SetRelativeValue $x 1716 lappend isomarkers_($tf) $m 1715 1717 } 1716 1718 } … … 1722 1724 # format: 1723 1725 # 1724 # N%Percent of current total data range. Converted to1725 # 1726 # NAbsolute value of marker. If the marker is outside of1727 # 1728 # 1729 # 1726 # N% Percent of current total data range. Converted to 1727 # to a relative value between 0.0 and 1.0. 1728 # N Absolute value of marker. If the marker is outside of 1729 # the current range, it will be displayed on the outer 1730 # edge of the legends, but it range it represents will 1731 # not be seen. 1730 1732 # 1731 1733 itcl::body Rappture::NanovisViewer::_ParseMarkersOption { tf ivol markers } { … … 1765 1767 itcl::body Rappture::NanovisViewer::_AddIsoMarker { x y } { 1766 1768 if { $activeTf_ == "" } { 1767 1769 error "active transfer function isn't set" 1768 1770 } 1769 1771 set tf $activeTf_ … … 1821 1823 set limits_(max) "" 1822 1824 foreach ivol $_style2ids($tf) { 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 } 1833 return [array get limits_] 1834 } 1825 if { ![info exists limits_($ivol-min)] } { 1826 error "can't find $ivol limits" 1827 } 1828 if { $limits_(min) == "" || $limits_(min) > $limits_($ivol-min) } { 1829 set limits_(min) $limits_($ivol-min) 1830 } 1831 if { $limits_(max) == "" || $limits_(max) < $limits_($ivol-max) } { 1832 set limits_(max) $limits_($ivol-max) 1833 } 1834 } 1835 return [array get limits_] 1836 }
Note: See TracChangeset
for help on using the changeset viewer.