pax_global_header00006660000000000000000000000064142322770510014515gustar00rootroot0000000000000052 comment=db83ba80d1aa57ecdc709ec10466cd856be36179 amide-1.0.6/000077500000000000000000000000001423227705100126005ustar00rootroot00000000000000amide-1.0.6/LICENSE000077700000000000000000000000001423227705100173722amide-current/COPYINGustar00rootroot00000000000000amide-1.0.6/README.md000077700000000000000000000000001423227705100200702amide-current/README.mdustar00rootroot00000000000000amide-1.0.6/amide-current/000077500000000000000000000000001423227705100153375ustar00rootroot00000000000000amide-1.0.6/amide-current/.gitignore000066400000000000000000000024051423227705100173300ustar00rootroot00000000000000src/*.o configure autom4te.cache/ config.log po/Makefile po/Makefile.in po/Makefile.in.in Makefile aclocal.m4 amide_config.h config.status doc/reference/version.xml etc/amide-1.0.6-1.info etc/amide-1.0.6-1.iss etc/amide.spec libtool macosx/amide.plist po/POTFILES po/stamp-it src/.deps/ stamp-h1 amide_config.h.in* Makefile.in doc/Makefile.in doc/reference/Makefile.in etc/Makefile.in help/Makefile.in macosx/Makefile.in man/Makefile.in pixmaps/Makefile.in src/Makefile.in win32/Makefile.in etc/amide.desktop help/amide-C.omf help/amide-es.omf help/es/amide.xml help/es/es.mo pixmaps/*.h po/.intltool-merge-cache po/zh_CN.gmo po/zh_TW.gmo src/amide src/amitk_data_set_D*.* src/amitk_data_set_F*.* src/amitk_data_set_S*.* src/amitk_data_set_U*.* src/amitk_marshal.c src/amitk_marshal.h src/amitk_raw_data_D*.* src/amitk_raw_data_F*.* src/amitk_raw_data_S*.* src/amitk_raw_data_U*.* src/amitk_roi_B*.* src/amitk_roi_C*.* src/amitk_roi_E*.* src/amitk_roi_F*.* src/amitk_roi_I*.* src/amitk_type_builtins.* src/stamp-amitk_type_builtins.* intltool-* m4/intltool.m4 m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 m4/gtk-doc.m4 m4/gnome-doc-utils.m4 INSTALL config.guess config.sub depcomp install-sh ltmain.sh gtk-doc.make gnome-doc-utils.make compile missing amide-1.0.6/amide-current/AUTHORS000066400000000000000000000007721423227705100164150ustar00rootroot00000000000000Programmers: ----------- Andreas Loening Additions: ---------- Mutual information alignment - Ian Miller Translations: ------------ Spanish Manual Translation: Pablo Sau Interface Translations: Chinese (Simplified) wormwang@holdfastgroup.com Chinese (Traditional) William Chao Misc. Credits: -------------- Pencil icon is taken from the GIMP, and is used under terms of the GPL. amide-1.0.6/amide-current/COPYING000066400000000000000000000431101423227705100163710ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. amide-1.0.6/amide-current/ChangeLog000066400000000000000000001337031423227705100171200ustar00rootroot000000000000001.0.6 * fixed dicom sort function to allow slices in gated/dynamic studiesff that have same location * add dicom mimetype to desktop.in file [1] * added ability to read in DICOM files via DCMTK utilizing jpeg compression [2] note - JPEG 2000 is not supported by dcmtk by default * add support for gsl-2.0 [3] * add support for vistaio files [3] * add support for libc-2.23 [3] * fix for compatibility with ffmpeg-2.9 [4] * updated autotools * updated copyright notices for 2017 * fix for newer ffmpeg encoding [5] note, this uses a command avcodec_encode_video2 that's already deprecated * for dynamic data with interframe time gaps, give preference over frame start times over frame durations for adjustment into continous 4D data set [6] * correction of dicom quantitation, was incorrectly using scaling_intercept [7] dicom is y = RescaleSlope * x + RescaleIntercept. amide is y = scaling_factor * (x + scaling_intercept) amide now divides RescaleIntercept by RescaleSlope when reading in DICOM * similarly, reading in from the medcon library, most file formats are y = mx+b, now fixing things as amide is y = m(x+b) [1] Contributed by Ville Skytta [2] Suggested by Marc Rechte [3] Contributed by Gert Wollney [4] Contributed by Andreas Cadhalpun [5] From Reinhard Tartler [6] Noticed by Dan Farber [7] Noticed by Richard Taschereau 1.0.5 2014.01.25 * raw_data_import now shows correct file size if file > 2GB * new math functions: remove-negatives, t2* calc * increased bitrate of ffmpeg encoding by 5-fold * fixed func definition for amitk_color_table_menu_new [1] * default ROI transparency increased to 0.5 * switch to non-deprecated libavcodec functions [1] * various edits for hardening using strings [1] * workaround for gtk+ bug of endless loop when spin buttons in toolbars are double or triple clicked * remove "inline" on functions in amitk_point and amitk_space, was causing issues with clang on osx as wasn't C99 compliant, and didn't seem to increase speed as -O2 optimization probably already inlines these [1] Reported by Andreas Tille 1.0.4 2012.11.20 * fixed exporting views, height incorrectly substituted with width * initialize scaling_intercept to 0 when creating new data set - was problem importing DICOM on Mac, as mem not init'ed to 0 * amide_gconf_set_float had bug on OS X, only saved integer value - seen as error in export dataset - wrong voxel size [1] [1] Reported by Daniel Vonwil 1.0.3 2012.10.04 * reinabling gnomecanvas antialiased support, hopefully now stable - roi's now filled in, alpha of fill can be customized * resets view center if initial dataset loaded * error message dialog now scrollable, so won't cover entire screen * added "threshold" and "multiple" math operations * autoplay feature for flipping between gates on gated study * reexpanded the local slice cache size, now 3 * # frames or gates * now keeps track of gate times (dicom trigger time) * when reading in xmedcon, tries to use orientation/offset provided for DICM data, and orientation for ECAT. * fixed scroll wheel on win32 (required libgnomecanvas-2.30.3) * now able to specify colors of ROIs and fiducial marks [1] * added a tool for measuring distances between fiducials/ROIs [2] * ffmpeg library fix, switch avcodec_init to avcodec_register_all [3] [1] Requested by Ajay Kumar and Janet O'Sullivan [2] Requested by Josef Vizkelety, Michael Braden, A. Mehranian, etc. [3] Contributed by Peter Bloomfield 1.0.2 2012.04.27 * Added MIP and MINIP rendering methods for thick slices * mac bundle now is able to export JPEG images [1] * will now separate diffusion data into two volumes * enabled scrollwheel use on canvases * widend the tree box * mutual information alignment now handles negative values * cleaned up spec file * zh_TW translation file [2] * fixed several bugs related to translations * thickness now not overwritten when loading in .xif * try to read in DICOMDIR files with lower/upper case reference issues * canvas slice cache size now fixed, was getting too large if multiple datasets * nearest neighbor/trilinear algorithm now more graceful at data set edges * POINT_TO_VOXEL macro now casts instead of floor, slight speed boost for slicing * configure fix to us LIBS instead of LDFLAGS for dcmtk detection [3] [1] Noticed by Youngho Seo [2] contributed by William Chao [3] contributed by Gert Wollny 1.0.1 2011.11.11 * conversion between different raw data formats in dcmtk_export no longer fails * data_set_copy_in_place no longer forces calculation of max/min values * now reads in injected dose correctly from DCMTK [1] * default injected dose/weight now NaN * additional tags in exported DICOM files for compliance [2] * "default directory" preference fixed [3] * added preference to utilize exec directory as default * will now separate multi-TI dicom data * added flat-file preferences (used on mac os x) [1] Noticed by Wangxi Hai [2] Requested by Chih-Ann Yang [3] Noticed by Victor Yushmanov 1.0.0 2011.07.22 * fixed color table for inverse hot metal contour * fixed uninitialized iterator in data_set_reduce_scaling_dimensions [1] * fixed manual entry of voxel size on tb_export_data_set dialog [2] * updated configure.in for 3.6.0 [3] * zoom no longer corrupted if no data sets [4] * fixed orientation errors on dcmtk_export [5] * added a mutual information alignment algorithm [6] * updates to Mac OSX package to allow saving prefs [7] [1] Encountered by Done Ugarte [2] Noticed by Morton Ostergard [3] Noticed by Wolfgang Pichl [4] Noticed by Erik Nolf [5] Noticed by Chih-Ann Yang [6] Contribution by Ian Miller [7] Noticed by Janet O'Sullivan 0.9.3 2011.03.06 * altered ffmpeg include paths for compiling on non-fedora systems [1] * more gtk deprecated cleanups [2] * converted GtkFileSelection to GtkFileChooserDialog * got rid of AmitkXifSel widget (old GTK code) * saving studies as XIF directories now done via a separate File menu item removed "save as XIF directory" preference * use xmedcon's pixdim[4] for frame duration on static analyze [3] * incorrect initialization of affine[] in amitk_canvas (also noted by [4]) * we're dependent on gtk >= 2.16 [4] * updates for dcmtk 3.6.0 * multiframe dicom file support via DCMTK [5] * problems deleting objects in amitk_tree_view [6] * exporting in mac os x version broken due to dbus issues [7] [1] Suggested by Peter Bloomfield [2] Suggested by Ian Miller [3] Suggested by Felix Gremse [4] Found by Henrique Rocha [5] Suggested by Robert Miletich [6] Found by Otto Muzik [7] Found by Jul Lea 0.9.2 2009.12.17 * switched from libfame based mpeg encoding to ffmpeg * more acurate gnome-vfs/gconf requirements in configure [1] * fixed error compiling without DCMTK [2] * fixed error with warning message strings containing '%' [3] * G_DISABLE_DEPRECATED and GTK_DISABLE_DEPRECATED now off by default [4] * Fix on win32 DCMTK build to allow exporting DICOM on win32 [1] Suggested by Peter Bloomfield [2] Found by Marko Kauzlaric [3] Found by Kris Thielemans [4] Found by Wolfram Brenig [5] Found by Joe Paugh 0.9.1 2007.12.16 * added gtk_disable_locale on win32 to keep i18n from screwing up * import raw on win32 was crashing due to NULL string [1] * transformed help docs into gnome-doc-utils format * fixed .spec file, rpm build now working again [1] Found by Kai-Hsiang Chuang 0.9.0 2007.12.02 * removing gtk 2.2 dependencies, now dependent on gtk >= 2.10 -gtk_option_menu switched to gtk_combo -gnome_config use switched to GConf on unix -config settings now saved in registry on win32 -bug with dragging of off canvases now gone * removed dependencies on libgnome and libgnomeui -GNOMEUI menu/toolbar switched to GtkAction -GnomeDruid replaced with GtkAssistant -gnome_program_init replaced with gtk_init * amitk_space_transform now propagates correctly through children * xpm icons removed, all icons now from .h pixbuf data * dicom import now reads in full series date and time [1] * now can export data sets via libdcmdata [2,3] * fixed errors with cropping type conversion * change Categories in .desktop file [4] * extended math capabilities for multi-frame data sets [5] * changed labeling of %ID/g to %ID/cc to make explicit [6] [1] Requested by David Yerushalmi [2] Requested by Aurlie Dutour [3] Requested by Matthew Leonard [4] Change by Dominique Belhachemi [5] Requested by Michael Braden [6] Requested by James Yu 0.8.23 * help window incorrect for freehand roi's [1] * changed erase outside roi to shift-m3 from shift-ctrl-m3 * incorrect exporting of multi-frame data sets, values zero [2] * poor threshold setting on all negative value data sets [3] * import file dialog now closed prior to importing [1] Found by Marco Bucci [2] Found by Andre Manook [3] Noticed by David Yerushalmi 0.8.22 2007.09.28 * fixed bug with drawing 1st voxel of freehand (introduced 0.8.21) [1] * autodetect xmedcon format support (requires xmedcon > 0.9.10) * button to set the view center as origin [2] [1] Found by Jeff Arkles [2] Requested by Michael Braden 0.8.21 2007.07.14 * switched index to strchr in xml.c, amitk_point.c * man page fix [1] * freehand roi's now initially line up with the voxels of the dataset * hopefully finally now have a true radix sign fix, as mingw can't really use setlocale * flip around NIFTI images to get right orientation [2] [1] From Dominique Belhachemi [2] Suggested by Buyean Lee 0.8.20 2007.06.29 * message popup for export raw data dimensions * init allocated density memory to 0 in render.c * check that voxel sizes are valid in imported data sets [1] * tightened up raw_data_import dialog * added millimeter indicators to crop dialog [2] * update for NIFTI support in XMedCon [3] * even more correct placement/orientation of dicom data [3] * added ability to output PNG instead of JPG [4] * added a contour form of hot metal [4] * add a preference for the initial directory to look in [4] * added ability to manually enter in the rotation transform [4] * fixed a bug with rotations * internationalization, now uses en_US instead of POSIX on windows, also guesses if incorrect radix sign, and tries to fix [1] Suggested by Gokhan Ozer [2] Suggested by Luca Guerrieri [3] Suggested by Buyean Lee [4] Suggested by Andre Manook 0.8.19 2006.10.22 * fixed string error in dcmtk_interface.cc [1] * somewhat more correct placement/orientation of dicom data * fixed bug for reading in dynamic dicom data * DCMTK returns number strings as POSIX [2] * added progress bars for filters * object movement in alignment wizard now propagates correctly [1] Found by Kris Thielemans [2] Found by Marco Bucci 0.8.18 2006.10.08 * validate strings from xmedcon as utf8 [1] * another potential fix for 64bit check xml_check_file_32bit_okay [2] * added export dataset dialog - allows selection of output voxel size [3] - allows selecting bounding box (tight or inclusive) [3] * better guessing for reading in DICOM datasets [4,5] * first try at DICOM gated support [5] * added ability to import objects (like ROI's) from previous .xif's [6] * better handling of edges in tri-linear interpolation [7] * active data set now required to be visible when moved/rotated [1] Found by Buyean Lee [2] Found by Marco Bucci [3] Suggested by Luca Guerrieri [4] Help from Han Chunlei [5] Help from Kris Thielemans [6] Suggested by Marco Bucci and many others [7] Suggested by Patrick Chow 0.8.17 2006.08.30 * added toolbox for doing image math between data sets [1] * now saves weight/dob/dose/etc. when exporting with xmedcon [1] * fixed bug loading DICOM on windows [2] [1] with help from Matthew Leonard [2] found by Martin Rodriguez-Porcel 0.8.16 2006.06.29 * wasn't reading in intercepts correctly from .xif files [1] * potential fix for 64 bit check in xml_check_file_32bit_okay [2] * fixed bug with rendering of ROI's [3] * in help panel, button "1" now refered to as "m1" for clarity [1] Found by Peter Bloomfield and Marwan Elkoussy [2] Found by Jose Manuel Quesada [3] Found by John Storey-Bishoff 0.8.15.3 2006.05 * export->series for dynamic data sets led to core dump [1] * now handles DICOM files without scale factors (eg MR) [1] Found by Tove Olafsen 0.8.15.2 2006.04.15 * fix to libecat support - includes calibration when possible * fixed 64bit/32bit file detection on Mac OS X * fixed several glitches with DICOM handling [1] - better guestimation of slice thickness - correctly handles patient orientation [1] Found by Andre Manook 0.8.15.1 2006.04.09 * slight xmedcon tweaks - now require xmedcon >= 0.9.9.0 * various small fixes for gcc 4.1 (fedora core 5) * fixed independent threshold - menu now gets enabled properly * modified libmdc/libecat support, allow reading in truncated data sets * fix for exporting data sets 0.8.15 2006.02.21 * added independent color tables for 2nd and 3rd sets of views [1] * strip NaN's on export->resliced data set to make xmedcon happy * added internal scaling intercept - more compatible with dicom - intercept gets removed if all are zero * added additional support for DICOM through the DCMTK library - has support for reading in DICOMDIR files * updates for MinGW build * added a field of view parameter - to look at only a subset of data * now reduces scale factor dimension of imported data when possible * can now specify how multiple canvases are layed out (panel_layout option) [1] Suggested by Freimut Juengling [2] Suggested by Kris Thielemans 0.8.14 2005.11.17 * faster functions for initialized amitk_raw_data structures [1] * fast roi quantitation now gives more accurate median value * freehand/isocontour drawing speed-ups * can export underlying raw roi values to file [2] * canvases and tree/help can torn off as separate windows [3] * removed 'logic' for placing orthogonal sets of canvases -now simply left to right * Default rendering opacity can now be specified as density only [4] * raw data import dialog values are now persistent [5] * distribution on threshold now only shown for global thresholding * can now display thresholds as center/window as well as min/max [6] * additional CT windowing options [6] * added "subject orientation", and appropriate displays on canvas [6] * added subject name, id, and dob entries [6] * toolbox dialogs now correctly free memory on destroy signal [1] Requested by Buyean Lee [2] Requested by Daniel Rubin [3] Suggested by Jonathan Bailleul [4] Suggested by Jeff Tseng [5] Suggested by Robert Hunter [6] Suggested by Freimut Juengling 0.8.13 2005.06.24 * added freehand ROI's [1] * added drawing mode for isocontour ROI's * Makefile update for gnome 2.10 [2] [1] Requested by Buyean Lee and many other people [2] Found by CG Hsu 0.8.12.1 2005.06.16 * slight tweek to the zoom setting code 0.8.12 2005.06.15 * added an option to recover corrupted xif files * various small bug fixes for some warnings generated by gcc 4.0 * changing voxel_dim (from adding or removing data sets) now compensates zoom [1] * analysis now uses NAN for undefined stuff if available * slice functions now return NAN for undefined pixels instead of zero * implemented function to output multiple data sets as single file [2] * can now put a time label on flythrough and rendered movies [3] * new dynamic movie type - frame with smoothing * three isocontour ranges - above min, below max, between min/max [4] [1] Found by Steve Jones [2] Requested by Sheena Lee [3] Requested by Anna Wu [4] Requested by Karen Herbst 0.8.11 2005.03.12 * ROI analysis wasn't correctly freeing the pointer array [1] * disabled reporting of "total" statistic, as this is often wrong depending on the underlying data type * error in saving of .xif files with dynamic data on win32 [2] [1] Found by Michael Kreissl [2] Found by Steve Jones 0.8.10 2005.01.26 * ui_series no longer requires corresponding ui_study canvas to be shown [1] * Slices of thickness greater then the voxel size were offset in the depth direction [2] [1] Found by Peter Bloomfield [2] Found by Jeff Tseng 0.8.9.1 2005.01.13 * another try at a win32 internationalization fix [1] Found by Alien and Liesje 0.8.9 2005.01.08 * Makefile.am problems for compiling w/o xmedcon [1] * saving roi statistics records isocontour value [2] * ui_study titlebar includes filename as well as study name[2] * internationalization problems [3,4] * set default action on dialogs [3] * clean building without scrollkeeper [3] * center of an isocontour now defined as the center of mass [5] [1] Found by Iain [2] Requested by Steve Jones [3] Found/Requested by Alien [4] Found by Erik Nolf [5] Requested by Steve Jones 0.8.8.1 2004.11.10 * updates for x86_64 compilation 0.8.8 2004.11.02 * crash when poping up object dialog of non-viewed data set [1] * accurate roi quantitation algorithm didn't work in inverse mode [2] * isocontour's were overdrawing by one voxel [3] * can now add roi to study object in tree * new preference: can have isocontours drawn as filled * incorrect use of MdcSwapBytes was causing rotated images on big endian [4] * added ability to specify isocontour value (lower value) [3] * updates for (X)MedCon 0.9.8.0 [1] Found by Patrick Chow [2] Found by David Stout [3] Found/Requested by Steve Jones [4] Found by Anna Wu 0.8.7 2004.08.22 * spin buttons on roi initial popup didn't take decimal places [1] * ui_series panel size can now be adjusted [2] * new isocontour, wasn't showing image value on help window [3] * fixed isocontour erasing [3] * fixed error in profile tool, incorrect values for view_duration < frame_duration [4] * users now have the option of a more accurate roi quantitation algorithm [5] * increased accuracy of the fast roi quantitation algorithm [1] Found by Keon Kang [2] Requested by Freimut Juengling [3] Found by Steve Jones [4] Found by Patrick Chow [5] Found by Peter Bloomfield 0.8.6 2004.06.22 * raw data import dialog didn't take gates into account for calculating bytes * fixed rendered movie generation * can now calculate inside ROI for values greater than specific value * amitk_xif_sel crashed when browsing "/" directory [1] * fixed importing of analyze files [2] * get configure script to end if m4 not found [3] * rpm now builds correctly on FC2 [1] Found by Peter Bloomfield [2] Found by Charles Henri Malbert [3] Found by Emily Heath 0.8.5 2004.06.07 * fixed fopen binary versus text bug on windows [1] * export view function now includes roi's, etc. [1] * fly through mpeg's now include roi's, etc. * data sets can now also be exported resliced [2] * slice generation slightly more accurate for iterating over depth * fixed core dumps with filtering [3] * added export jpeg abilities to ui_series * added gated study support to ui_series * added ability to select which objects go onto series on init * added ability to select which objects go into rendering on init * libecat strings aren't necesarrily NULL terminated [4] * some gtk 2.4 updates (switch to g_idle) * switched to libmdc progressive loader * values read through libmdc are now quantified & calibrated, they had only been quantified before (branching factor hadn't been added) * updates to gtk-doc reference doc generation process [1] Found/Requested by Steve Jones [2] Requested by Jayashree Kanchana [3] Found by Vania Kenanova [4] Found by Kris Thielemans 0.8.4 2004.04.26 * fixed bug in *_calc_frame_max_min [1] [1] Found by Peter Bloomfield 0.8.3 2004.04.21 * added support for gated files [1,3] * profile tool now updated automatically on data set (de)select * fixed small graphical glitch with line between full/scaled bars * fixed errors with scale_factor and filtering/cropping [1] * fixed crash with double clicking finish on filter/crop * can now validly pop up a dialog on an undrawn roi [2] * added ROI quantitation based on Lee et al, Nuc Med Comm 2000 21:685-690 [1] Found/Suggested by Chris Deroose [2] Found/Suggested by Keon Kang [3] Suggested by David Stout 0.8.2 2004.02.16 * incorrect loading of frame duration through libecat [1] * rendering conversion had diff. dimension between slice and rendering lead to core dump on Mac OS X, and with some gcc's [2, 5] * SUV calculations were off by a factor of 1000 [3] * ignore gdk warnings on win32 work around for gdkproperty.c "Not Implemented" warnings (gtk 2.2.4) * got popt/icons working on win32 * updated win32 install. .xif files now associated with AMIDE * updated most of the icons (exception of the toolbar icons) * better interactivity on threshold for remote displays [1] * roi analysis "copy to clipboard" now left justifies roi names [3] * max/min calculations now done on demand * changed mechanism for changing isocontours old mechanism wasn't working on win32 * added x limits to the gaussian fit on the profile tool [1] * added scientific notation support to most of the spin buttons [2] [1] Found/Suggested by Kris Thielemans [2] Found by Anna Wu [3] Found/Suggested by Chris Deroose [4] Found by Keon Kang [5] Found by Chris Heier 0.8.1 2004.01.13 * specifying import types was messed up [1] [1] Found by Patrick Chow & Peter Bloomfield 0.8.0 2004.01.11 * finally added a (much requested) profile tool * improved (correct) loading of non-float data files via (X)MedCon * can drag file's from Nautilus onto the tree * updated for new dynamic data structure coming in (X)MedCon 0.9.0 * preferences now saved on a per study/data set basis default preferences used only for new studies/data sets * added the ability to set a bone and soft tissue window for CT data sets * removed standard error from roi stats. wasn't sure if it was calculated correctly (wasn't weighted), and it's not the experimental std. err. anyway * added copy button to roi statistics window (for copy and paste of values) * various AmitkThreshold cleanups * saving on windows to samba share crashed for large files [1] not sure why... work around is saving in 16MB chunks in amitk_raw_data.c * default roi stat file is probably annotated as .tsv (was .csv) * warning messages to console/dialogs is now a preference, (was compiled in) * added ability to export data sets * i18n broke reading in .xif's, concorde files for European locales [2] * was trying to change permissions on non-existant files [3] * reading from libecat7 versus libmdc was setting offset inconsistently [3] * filter fwhm was off by a factor of 2 * roi analysis results now have more precision, as does the time dialog * Spanish translation of the manual [4] * got rid of console on windows [1] Found by Patrick Chow [2] Found by Chris Deroose [3] Found by Kris Thielemans [4] Contributed by Pablo Sao 0.7.14 2003.08.15 * disabled anti-aliasing on canvas, was getting core dumps on ROI resizing. * problems with self-referencing with slice_parent fixed, data sets now freed * crop wizard now allows data type/scaling conversions too * updates to help in rois.xml * added help button to several dialogs * fixed small bug with rendering isocontours alone * removed data type specific crop and projection functions complexity not worth incremental performance improvement * amitk_data_set_get_projection now does all 3 planes at once * cursor color now changes immediately when data set changed * erase outside roi no longer core dumps * when voxel sizes of a data set are changed, the children now try to follow the scaling changes. 0.7.13 2003.07.09 * fixed problems with selecting XIF files in the file selector 0.7.12 2003.07.05 * added ability to save XIF files as flat file, made default * put in configure ability to detect libgnomecanvas version, disable anti-aliases canvases previous to libgnomecanvas 2.2.0 * .iss file now configure time generated * configure.in file tweaks * zh_CN i18n update from Wales Wang * threshold "abolute" legend now reflects current conversion (%id/g, etc.) * file/xif selection widgets paths are set to last used 0.7.11 2003.06.20 * zh_CN i18n contributed by Wales Wang * added back in support for internationalization * ui_common axis works on OS X (was a double free bug, that didn't manifest on linux) * variance is now calculated correctly (was overconservative previously). * generalized FIR filtering added * gaussian filtering done with FIR filtering code, 50% slower, but eliminates a lot of otherwise redundent code * median/filter code no longer data type specific. * ui_series now tracks changes to data sets/rois/and fiducial marks * fiducial mark "point" parameter eliminated. redundant * switched over to anti-aliased canvases for all canvases * misc. fly through canvas fixups * switched form of raw format entry in .xif files * rewrote isocontour selecting function, no longer recurseive * changed look of rendering window/added toolbar 0.7.10 2003.05.27 * enable-win32-hacks option, allows compilation on cygwin/mingw32 * multiple small fixes for cygwin/mingw32 * amitk_dir_sel, slight update, and copied _gtk_fnmatch from gtk * added slice caching system * various canvas cleanups * study can now be active_object -> can rotate entire study from canvas * default color tables (set in preference dialog) applied to imported data * enabled subject_weight/injected_dose in medcon_import.c * resets initial study name on first data set load * canvas target on/off is now a study parameter, not a preference * fixes for how multi-frame slices are weighted * fixed problem with "flashing" canvases -> inadvertent update_layout call * stereoscopic rendering on inverse background no longer gives gray background * roi's can now be drawn center-out and edge-to-edge * smaller font for ui_series * various ui_series fixes for dealing with no data sets in object list * can now compile w/o gsl again * compilation now detects that it's being compiled on OS X - disables axis guide, errant font handling on OS X was causing crashes - disables esd, esd was locking files after amide crash * roi stats are now on a single pane for static studies * versions of various compiled in libraries shown in about box 0.7.9 2003.04.22 * added subject_weight, injected_dose, and cylinder_factor to data_set object * can now easily calculate scale factor for %ID/g and SUV * amitk_object_copy now recurses, children also copied * dynamic, rotating rendered movies now generated correctly - was due to a problem with handling of context volume * series now keeps the correct zoom even if all data sets not shown * canvas now minimizes thickness correctly if not all data sets shown * threshold widget more bullet proof, good for retarded data sets * spin buttons can now accept scientific notation input * ROI's now calculated correctly for data sets with one of the dim ==1 * fixed filtering (got screwed up in 0.7.7 with add. of scaling_type) * fixed filtering of dynamic data sets * fixes for initializing the toolbar * was not removing the active_object ref. appropriately in amitk_tree * fixed selection incorrectly going to study row in amitk_tree * slightly less idiotic handling of cursors * now requests to change read permissions if import file can't be read * more intelligent CTI/ECAT data set naming * more intelligent medcon data set naming * remove iscontour_3d signal from amitk_canvas by moving code from ui_study_cb.c * user now asked to specify the depth of geometric ROI's on drawing * all warnings on reading xml are condensed into a single warning message * stats now point out difference between voxels and fractional voxels * variance now calculated using voxels, not fractional voxels * building rpm/deb files without libecat by default - xmedcon now supports ECAT 7 * building rpm with enable-amide-debug=no * fixed help window not popping up problem 0.7.8 * fixed "crazy spin button" bug, again * stats can now be calculated on only a percentile of the voxels in an ROI * added principle component analysis to the factor analysis wizard 0.7.7 2003.03.03 * added ability to only look at a subset of the canvases at a time * added new preference - canvas size can now be fixed to the dimensions of all data sets, not just the visible ones. * now have a 3-way linked view too * view mode is now saved with the study, and is kept with the study object * fixed problem with amitk_data_set_set_scale_factor not always running when needed * added scaling_type to amitk_data_set, to indicate dimensionality of scaling array * ui_time_dialog won't crash if destroyed while event pending * on data_set_copy min threshold set was getting ignored * canvas now only uses data sets as bounds. avoids problems with pathologic ROI's * added .info file generation for fink building 0.7.6 2003.01.18 * fixed long standing bug, dealing with slices generated via nearest neighbhor over multiple frames. Would cause "flickering" in dynamic movies * added a factor analysis tool - implemented Sitek, et al. penalized least squares algorithm * ui_fly_through's can now be done over time * ui_series now shows roi's and fiducial marks too * added an option so that moving of rendered object can be click-n-drag * encoding of selected objects now in amitk_object - new signal, "object_selection_changed" - canvas and tree now automatically adjust for changed in selection - canvas and tree also keep track of the entire object tree * more progress bar popups - histograming - flythrough and rendering movie progress bars now popup - cropping - importing * dropped the "IDL" file type * was crashing on interpolation change after object dialog is closed, fixed * crop dialog: added idle loop handler for canvas update, fixs spin button bug * scrollbar's on canvas now do a better job of guessing their adjustment values * managed to get rid of dump double clicking bug on canvas * study_copy wasn't copying view_start_time 0.7.5 2002.12.17 * medcon importing now allows negative values (had been set to zero) * added progress bars for rendering context initialization * added progress bars for series slicing * added option to set values above threshold to zero when rendering - a poor man's "strip" function * projection image voxel units are now in terms of 1/mm^3 * object dialog now lists memory usage of data sets * fixed unref'ing bug with gtkdial * compiling without libmdc works again * slices correctly generated for data sets with negative values * added ability to leave cross hairs on canvases (in preferences dialog) * added ability to increase the central "empty area" of cross hairs (in preferences dialog) * removed annoying characters from suggested export file names * switched over to using g_try_malloc, g_malloc crashes on failed allocations * fixed bug in rendering, was allocating 5x more memory then it needed * allowing optimized versus non-optimized (less memory) rendering * switched all numerical entries to spin buttons for better behavior on focus out * rendering is now done in idle loop * series slicing is now done in idle loop * ui_series wasn't disconnecting data_set handlers * added popup dialogs before roi analysis and rendering to allow picking of options 0.7.4 2002.11.26 * switched mpeg encoding to using libfame * number of voxels now displayed on roi_analysis dialog * fixed problem with spin_button callback's running on delete_event of program * better medcon data set name guessing * threshold doesn't crash now when dealing with negative values * fixed multiple misuses of EPSILON * isocontour drawing on dynamic scan frames > 0 caused crashes, fixed * resizing of 2D isocontour's thickness now works 0.7.3 2002.11.11 * added median filtering to the filter dialog * distribution data now saved in .xif file when available * corrected an error in the generation of roi stats * fixed some small bugs with dual cursor display * on roi clear, max and min are now recalculated, along with the distribution * no longer moving canvas view when shifting roi * now sets thickness correctly when loaded up directly with an imported data set * added ability to erase data set outside of an roi * removed slop in moving fiducial marks * dual cursor display weirdness is now (hopefully) fixed for real * help is working again 0.7.2 2002.10.20 * anisotropic filtering added, low pass gaussian filter current implemented * fixed some bugs with rotating/moving data sets * changed rendering x axis again, think it's right now * interpolation is now specified per data set * several entries in amitk_object_dialog are now spinners * disabled main window resizability, this allows the window to autoshrink * roi stat's page now comes up as a better size on small screens * time dialog now resizeable 0.7.1 2002.10.06 * can now generate fly through mpeg movies * can now choose between blended and overlay fusion modes * adding a data set cropping wizard * added the ability to erase a portion of a data set * most internal formats are now double * shifting and rotating data sets now uses an overlay image * can now compile correctly without libgsl support * alignment's only need 3 points now. problem was with SVD decomposition * rendering flipped left and right. that's now fixed * object modification dialog reads in entries a little more sensible now * big endian raw data importing works again * speed increase in reslicing. loops now iterate only over portion of slice that encompases the data set * fixed some small bugs with changing the view thickness on the canvas * fixed some small bugs with setting the minimum thickness of a multi data set study * data set icons now change with the data set's color scale * added black/white/black and white/black/white colormaps * cursor now shows current voxel value on active volume * removed extraneous memory consumption of raw_data_import * now ignores "per slice" scaling when converting to rendering 0.7.0 2002.8.16 A complete rewrite of almost all of the code in AMIDE Major Changes: * ported program to GTK 2.0 and GNOME 2.0 * data set's, roi's, etc. code has now been totally rewritten - these items are now subclasses of GObject - any object can be a child of any object - single object modification dialog that handles all objects * new .xif format (2.0) that follows new object code * old .xif format supported via legacy.c * dropped notion of having a "view coordinate frame", same as base * canvas updates are now done by an idle handler * switched internally used data type to double (was float) Minor Changes: * when threshold or popup button hit, and dialog already up, brought to front * dropped all remaining uses of imlib - can now only export images as jpeg... * user is prompted/warned on inverting an axis * ROI's can also be used as fiducial markers for alignments. * added total counts to roi analysis * single tree now used for linked viewing * EPSILON value is now used correctly for comparing floats * ROI rendering conversion speeded up greatly 0.6.4 2002.8.16 * view center notifier on help panel now gives correct location * fixed subtle floating point rounding error in drawing isocontours 0.6.3 2003.05.27 * Mac OS X doesn't have lround, using rint instead * canvas arrows weren't being updated with canvas slider change * with dual cursor display, second display wasn't being adjusted with canvas slider change * canvas voxel size adjusted when volume's voxel size adjusted * now better at guessing names from xmedcon imported files * can now shift data sets around on the canvas * help info panel slightly rewritten, more legible 0.6.2 2003.05.07 * fixed brown bag type error concerning active volume 0.6.1 2003.05.06 * added a "linked" view mode, so that data sets can be looked at simultaneously but not superimposed * spin buttons (zoom, thickness) no longer "go crazy", required a cludge widget, amitk_spin_button * when volume/roi/align_pt is changed on canvas, modification dialog also changes * when changing layout, canvases now reset coord frame's appropriately * objects no longer get unselected when ok/apply hit in the modification dialog * loading a new study replaces the old study if it's empty * deleting objects works again * now confirms quit when unsaved changes exist * cursors now handled better * 3D isocontour's now warn if drawn over multiple data frames * switched all canvases to antialiased except for amit_canvas and ui_preferences 0.6.0 2003.04.11 * realspace_t's are now a referenced object type * widgetized the coord frame rotate panel as amitk_coord_frame_edit * widgetized the canvas as amitk_canvas * widgetized the tree, got rid of ui_volume, ui_roi, ui_align_pt * raw_data_read_volume/read_file no longer requires preinitialized structures * added "per frame" scaling ability * added ability to generate movies "over frames" * added "interpolate between frames" scaling ability. * changed threshold dialog to a linear layout * threshold types (per slice/global/etc.) are now for each volume * setrlimit no longer screws up on MacOS X compile * threshold widget is no longer so picky about inputs * fixed some compile/installation problems (thanks to Juha Koivisto) -unnecessary include of matrix.h (from libecat) -unintended install of amide_export.h -libxml include file location changes 0.5.0 2002.02.05 * added ability to place fiducial reference points and align data sets using a rigid body transform (procrustes method) * stereoscopic rendering support added * roi's are now also rendered * improved alpha blending algorithm * fixed bug with loading in ASCII data * imported files now are centered on 0,0,0 to begin with * added ability to import CTI attenuation and sinogram files * dropped the use of an inverse axis in the coord frame, as we can just use the transpose * cheasy eye candy color scales on option menu in amitk_threshold * removed colons from default exported file names * roi statistics dialog now is resizeable, scrollable, and lists frame duration * zoom is now based on all data sets in study, not just currently selected ones * fixed small configuration bug when compiling without libmdc (thanks Adam Hupp) 0.4.7 2003.12.20 * can now pick between linear and orthogonal layouts for the 3 views * alignment lines work again * series views were showing incorrect locations * can now erase points from an isocontour ROI * dropped double click activating in tree list, too annoying to support in GDK * configure script checks for gcc 2.96, and complains loudly if found 0.4.6 2001.12.09 * added 2D and 3D isocontour ROI's * no more notion of an "active" roi. All roi's are now always moveable * multiple fixes for closing widgets * fix for crashing study parameter window * fixed cti import bug that screwed up the value for small frame durations * added more logic for dealing with corrupted CTI files * canvas event processing functions combined and rewritten for clarity * (X)medcon importing now (hopefully) get's scaling constants right * specific (X)medcon import fallbacks can be specified by the user * added ability to load in PDP and VAX raw data formats * can now handle data set with inf and nan values * fixed the bug with saving ROI statistics * gcc requirement is now listed as gcc 3.0.2 0.4.5 2003.11.18 * removed notion of "grains" for calculating ROI statistics * added a "scaled" color strip to the threshold widget * redesigned the roi analysis dialog box * added a button to the roi analysis dialog save stats info to a text file * fixed minor bug with time button display * fixed minor bug with threshold changes getting lost in volume dialog * can now import files from the command line * dropped 2x2x1 and 2x2x2 interpolations * gtkgammacurve setting is now faster in ui_rendering_dialog * can now set the width of drawn roi's as a user preference * added a gtkdirsel widget, this means .xif directories look more like files * better (but still not perfect) ROI resizing. * axis indicators on the roi and data set dialogs 0.4.4 2003.10.31 * rendering dialog changed considerably - user can now grab canvas and spin it using buttons 1 and 2 - x,y,z rotations have been moved - all rotations are now relative to the canvas * rendering parameters dialog fixed up, now allows colormap changing * rendering movies can now be done over time * can now change the name of the output movie * medcon importing importing was a little off, hopefully we have the right scale factors now * rewrote the threshold widget as a gtk style widget * added toolbar and menu to series widget * allow independent thresholding of series display * added captions to the series pic's * now importing correcting the frame durations of dynamic CTI files * now adding in image offsets from CTI files 0.4.3 2001.10.18 * multiple speed improvements (at least 2x faster now for slice generation) -changed multiple functions to defines (based on profiling) -inverse matrix is now pregenerated and stored -default compile is now -O6 * now have multiple internal data representations (not just float) * can have multi-dimensional scaling constants, useful for CTI files and such that have a scaling constant for each plane (let alone frame) * changed color compositing to an alpha based method, so that colormaps with white backgrounds can be composited together * changed voxelpoint_t to 4D, volumes are now considered 4D, rather than 3D with multiple frames * new data type, data_set_t. The volume's data set and distribution array are kept in this format * interpolation type used for conversion to a rendering context can now be specified * can now export renderings to graphics files * added "reset axis" button to rendering dialog * fixed a bunch of stupid bugs with the threshold widget * no longer save max/min in xml files, as these are regenerated * no longer save far corner in volume .xml files, redundant information * fixed stupid bug with the raw data import dialog box * fixed problem with adjusting the dimension of ROI's that were not lined up with the transverse plane * wait cursor no longer stays on erroneously when series widget used * library no longer built by default 0.4.2 2001.10.01 * global scaling is now default for new studies * threshold arrows now move better with relation to the cursor * keeps better track of which directory we're current working/saving in * can now export the views as image files (jpeg/tiff/ps/eps/png/etc.) * fixed endian issues with loading in floats and doubles * now ensures save files end with .xif * numerous build chain bugfixes (now compiles and runs on Mac OS X) * rewrote trilinear interpolation (much faster) * dropped bilinear interpolation (doing it correctly would be slower then trilinear) * fixed interpolation bug for slices of depth != volume->voxel_size.z * upgraded almost all the program from using gdk_imlib to gdk_pixbuf * changed the origin of our image volume to the far left bottom corner - world coordinate system is now right handed (this is a good thing) - new .xif version (y axis now points in opposite direction) - medcon, idl, and pem inputs also updated - many many updates to make this change work * elimination of several unneeded and confusing realspace functions * got rid of the "main" window * changes with command line parsing, no longer use "-i" to specify the input file. Also can specify multiple input files * fixed a long standing problem with destroying already dereferenced roi_item canvas objects - thanks to awu * updated config.guess, config.sub, libtool, etc. 0.4.1 * MPEG-1 movie generation capabilities added. Currently, all output files are saved as "out.mpg", due to an obscure gtk? bug. * added the ability to do horiz. and vert. leveling with the mouse * added an ascii file format for the raw data file input function * added a new menu item, so that users can specify the import method * added the ability to load in studies from the command line * you can now compile and run amide as a library, exported functions are in amide_export.h * add a creation date to the study data structure * add 'scan_date to the volume structure 0.4.0 * moved the functionality in the right column to a toolbar on top * fixed some dumb errors with the mouse-depth change * couple small documentation updates * more sensible initial classification function for rendering * the density and gradient classification functions now work correctly for multiple volumes * fixed stupid bug in rendering_context_free() * rendering parameters dialog changes now make more sense * did a first-draft of user documentation for rendering 0.3.5 * added Hot Blue/Hot Green colormaps * changed study tree from GtkCTree to GtkTree * context sensitive help window working better * add/edit/delete buttons removed from main panel * when moving an ROI, the view_center is now linked to the center of the ROI * disabled bug-reporting, as I only read the sourceforge bug reports 0.3.4 * corrected stupid roi-zooming error, although roi-zooming still not correct * added a little display to indicate the current coordinates * added a continously running help window to indicate what the different mouse buttons indicate at any given time. * corrected activating an object without selecting it (now not possible) 0.3.3 * added "targets" onto the canvases * can now change thickness by click-n-dragging on canvases * fixed rotating of roi's by mouse-click-n-dragging. Zooming still doesn't work right * mouse cursors now work correctly * fixed fatal errors in loading in many types of raw data (unsigned shorts, unsigned ints, etc.) * fixed a fatal error in referencing a free'd ui_threshold structure * blank images are now background color, not black * the currently active object is now noted in the study tree * code cleanups 0.3.2 2001.06.11 * big endian compile fix * additional viewing parameters saved in amide study files 0.3.1 * multiple fixes with viewing series of images * multiple fixes with calculating roi statistics 0.3.0 * added study parameter modification dialog * accelerated nearest neighbhor reslicing by a factor of 5 * massive bug hunt 0.2.4 * added loading/saving support in an XML file format 0.2.3 * added volume rendering support * numerous bug fixes 0.1 2001.01.03 * first released version amide-1.0.6/amide-current/Makefile.am000066400000000000000000000007451423227705100174010ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 if DISABLE_DOC HELPDIR = else HELPDIR = help endif # note, win32 needs to be before src SUBDIRS = \ pixmaps \ win32 \ macosx \ src \ doc \ man \ po \ etc \ $(HELPDIR) EXTRA_DIST = \ intltool-extract.in \ intltool-merge.in \ intltool-update.in \ gnome-doc-utils.make \ m4 CLEANFILES = \ intltool-extract \ intltool-merge \ intltool-update DISTCLEANFILES = *~ DISTCHECK_CONFIGURE_FLAGS = --disable-scrollkeeper --enable-gtk-doc amide-1.0.6/amide-current/NEWS000066400000000000000000000000451423227705100160350ustar00rootroot00000000000000No news here. Check the ChangeLog. amide-1.0.6/amide-current/README000077700000000000000000000000001423227705100174712README.mdustar00rootroot00000000000000amide-1.0.6/amide-current/README.md000066400000000000000000000130661423227705100166240ustar00rootroot00000000000000AMIDE ===== AMIDE stands for: AMIDE's a Medical Image Data Examiner AMIDE is intended for viewing and analyzing 3D medical imaging data sets. For more information on AMIDE, check out the AMIDE web page at: http://amide.sourceforge.net AMIDE is licensed under the terms of the GNU GPL included in the file COPYING. Quick Linux instructions ------------------------ cd /tmp/ git clone https://github.com/ferdymercury/amide # If Ubuntu 22: sudo apt install libgnomecanvas2-dev libgconf2-dev libmdc2-dev libvolpack1-dev libavcodec-dev gtk-doc-tools intltool libxml2-dev libgsl-dev libdcmtk-dev # ElseIf Ubuntu 20: sudo apt install libgnomecanvas2-dev libgconf2-dev libmdc2-dev libvolpack1-dev libavcodec-dev gtk-doc-tools intltool libxml2-dev python-libxml2 libgsl-dev libdcmtk-dev wget http://launchpadlibrarian.net/402991440/gnome-doc-utils_0.20.10-5_all.deb sudo dpkg -i gnome-doc-utils_0.20.10-5_all.deb # ElseIf Ubuntu 18: sudo apt install libgnomecanvas2-dev libgconf2-dev libgnomevfs2-dev gnome-doc-utils libmdc2-dev libvolpack1-dev libavcodec-dev gtk-doc-tools intltool libxml2-dev python-libxml2 libgsl-dev libdcmtk-dev # EndIf cd amide/amide-current intltoolize libtoolize gtkdocize # If Ubuntu 22: touch gnome-doc-utils.make # Else (Ubuntu 18/20 or Fedora32): gnome-doc-prepare # EndIf autoreconf --install # If Ubuntu 22: ./configure --prefix /opt/amide --enable-gnome-vfs=no --disable-scrollkeeper --disable-doc # ElseIf Ubuntu 20: ./configure --prefix /opt/amide --enable-gnome-vfs=no --disable-scrollkeeper # Else (Ubuntu 18 or Fedora32): ./configure --prefix /opt/amide # EndIf make sudo mkdir -p /opt/amide sudo chown $USER /opt/amide/ make install For system-wide install, do not use a prefix when running ./configure, and then just: make sudo make install Requirements ------------ 1) Compiler: I currently use gcc-6.3. The later 3.* series (e.g. 3.3) should work as well, along with version 2.95. Early 3.* Versions of gcc will quite likely generate compilation errors (and make AMIDE unstable) if optimizations are used when compiling. 2) GTK+: The current series of AMIDE requires GTK+-2, at least version 2.16. I'm currently developing on a Fedora Core 24 system, although other distributions of Linux with equivalent library support should work. Scrollkeeper is required for generating the help documentation. If you don't care about that, it's not needed. 3) Additional libraries: libgnomecanvas libxml-2 libgnomeui-2 (not needed on win32) These are various other libraries are needed for installation, most of which you will most likely already have installed if you have GTK+. Optional Packages ----------------- 1) (X)MedCon/libmdc (X)MedCon includes a library (libmdc) which allows AMIDE to import the following formats; Acr/Nema 2.0, Analyze (SPM), Concorde microPET, DICOM 3.0, ECAT/Matrix 6/7, InterFile3.3 and Gif87a/89a. (X)MedCon can be obtained from: http://xmedcon.sourceforge.net 2) DCMTK - DICOM Toolkit DCMTK provides expanded support for DICOM files, allowing the reading in of many clinical format DICOM datasets that (X)MedCon doesn't support. Version 3.6.0 is required. It can be downloaded at: http://dicom.offis.de/dcmtk.php.en 3) z_matrix_70/libecat This library can be used as an alternative for importing ECAT 6/7 files, and is released under a fairly restrictive license. It can be found on the AMIDE sourceforge website, or at it's original site: ftp://dormeur.topo.ucl.ac.be/pub/ecat/z_matrix_70/ecat.tar.gz The source file off of amide.sourceforge.net is preferable, as it includes a Makefile which will make a shared library, and a small patch. Since the license for libecat is non-GPL compatible, you really should only link to it as a shared library. A README file is included with the tarball that explains how to configure/compile the library. RPM packages are also available off the AMIDE web site. 4) volpack/libvolpack Volpack includes a library (libvolpack) which is used for the optional volume rendering component of AMIDE. The original version can be found at: http://graphics.stanford.edu/software/volpack/ The version available on the AMIDE web site is preferable, as it's been updated to compile cleanly under Linux. RPM packages are also available. 5) ffmpeg (libavcodec) [alternatively libfame] Another optional package, the ffmpeg library is used for generating MPEG-1 movies from series of rendered images and for generating fly-through movies. Information, code, and binaries for ffmpeg can be found at; http://ffmpeg.mplayerhq.hu and Linux RPM binaries are available at: http://rpmfusion.org/ If for whatever reasons you do not want to use the ffmpeg package for generating MPEG-1 movies, there is still code in AMIDE for using the libfame package for doing this. Information, code, and binaries for libfame can be found at: http://fame.sourceforge.net and Linux RPM binaries are available at: http://atrpms.net/name/libfame/ Building -------- See Quick instructions for Linux above. After running autoreconf, you can also inspect the file INSTALL for info on compiling and installing. If you don't feel like reading that, try: ./configure make make install (as root) If you're wondering about configuration options, a lot of information can be obtained by running: ./configure --help Building gtk-doc files ---------------------- The majority of the source code for AMIDE is structured as a library extension of GTK, called AMITK. Documentation for this library can be built using gtk-doc as follows: ./configure --enable-libdcmdata=no --enable-gtk-doc=yes make amide-1.0.6/amide-current/RELEASE_NOTES000066400000000000000000000004351423227705100173140ustar00rootroot00000000000000AMIDE is a tool for viewing and analyzing medical image data sets. It's capabilities include the simultaneous handling of multiple data sets imported from a variety of file formats, image fusion, 3D region of interest drawing and analysis, volume rendering, and rigid body alignments. amide-1.0.6/amide-current/amide.spec000066400000000000000000000047611423227705100173020ustar00rootroot00000000000000Name: amide Version: 1.0.6 Release: 2%{?dist} Summary: Program for viewing and analyzing medical image data sets License: GPLv2+ Group: Applications/Engineering URL: http://amide.sourceforge.net Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) Packager: Andy Loening Requires: xmedcon >= 0.10.0 Requires: gsl Requires: volpack Requires: ffmpeg-libs >= 0.4.9 Requires: dcmtk >= 3.6.0 Requires: gtk2 >= 2.16 Requires: gnome-vfs2 Requires: libgnomecanvas BuildRequires: xmedcon-devel BuildRequires: volpack-devel BuildRequires: libxml2-devel BuildRequires: gnome-doc-utils BuildRequires: libgnomecanvas-devel BuildRequires: ffmpeg-devel >= 0.4.9 BuildRequires: gsl-devel BuildRequires: dcmtk-devel BuildRequires: perl-XML-Parser BuildRequires: glib2-devel BuildRequires: gtk2-devel >= 2.10 BuildRequires: gnome-vfs2-devel %description AMIDE is a tool for viewing and analyzing medical image data sets. It's capabilities include the simultaneous handling of multiple data sets imported from a variety of file formats, image fusion, 3D region of interest drawing and analysis, volume rendering, and rigid body alignments. %prep %setup -q %build %configure \ --enable-libecat=no \ --enable-vistaio=no \ --enable-amide-debug=no \ --disable-scrollkeeper make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT desktop-file-install --vendor gnome --delete-original \ --dir $RPM_BUILD_ROOT%{_datadir}/applications \ --add-category X-Red-Hat-Extra \ $RPM_BUILD_ROOT%{_datadir}/applications/* %clean rm -rf $RPM_BUILD_ROOT %post update-desktop-database %{_datadir}/applications %postun update-desktop-database %{_datadir}/applications %files %defattr(-, root, root) %doc AUTHORS COPYING ChangeLog NEWS README todo %{_bindir}/* %{_datadir}/pixmaps %{_datadir}/gnome %{_datadir}/omf %{_datadir}/applications %{_datadir}/locale %{_mandir}/* %changelog * Fri Feb 24 2011 Andy Loening - cutout gtk-doc building and scrollkeeper * Sun Dec 16 2007 Andy Loening - small tweak for new gnome-doc help files * Tue Nov 05 2002 Andy Loening - get it to work with scrollkeeper * Sun Dec 19 2000 Andy Loening - wrote this fool thing amide-1.0.6/amide-current/attic/000077500000000000000000000000001423227705100164435ustar00rootroot00000000000000amide-1.0.6/amide-current/attic/amitk_list_view.c000066400000000000000000000262201423227705100220030ustar00rootroot00000000000000/* amitk_list_view.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2004 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapted from gtkcolorsel.c */ #include "amide_config.h" #include "amitk_list_view.h" #include "amitk_study.h" #include "amitk_marshal.h" #include "image.h" enum { SELECT_OBJECT, LAST_SIGNAL } amitk_list_view_signals; enum { COLUMN_ICON, COLUMN_NAME, COLUMN_OBJECT, NUM_COLUMNS }; typedef struct { AmitkObject * object; GtkTreeIter iter; gboolean found; } list_view_find_t; static void list_view_class_init (AmitkListViewClass *klass); static void list_view_init (AmitkListView *list_view); static void list_view_destroy (GtkObject *object); static void list_view_object_update_cb(AmitkObject * object, gpointer list); static void list_view_object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer list_view); static void list_view_object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer list_view); static gboolean list_view_find_recurse(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); static gboolean list_view_find_object(AmitkListView * list_view, AmitkObject * object, GtkTreeIter * iter); static void list_view_add_object(AmitkListView * list_view, AmitkObject * object); static void list_view_remove_object(AmitkListView * list_view, AmitkObject * object); static GtkTreeViewClass *parent_class; static guint list_view_signals[LAST_SIGNAL]; GType amitk_list_view_get_type (void) { static GType list_view_type = 0; if (!list_view_type) { static const GTypeInfo list_view_info = { sizeof (AmitkListViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) list_view_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkListView), 0, /* # preallocs */ (GInstanceInitFunc) list_view_init, NULL /* value table */ }; list_view_type = g_type_register_static(GTK_TYPE_TREE_VIEW, "AmitkListView", &list_view_info, 0); } return list_view_type; } static void list_view_class_init (AmitkListViewClass *klass) { GtkObjectClass *gtkobject_class; GtkTreeViewClass *list_view_class; GtkWidgetClass *widget_class; gtkobject_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; list_view_class = (GtkTreeViewClass*) klass; parent_class = g_type_class_peek_parent(klass); gtkobject_class->destroy = list_view_destroy; list_view_signals[SELECT_OBJECT] = g_signal_new ("select_object", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkListViewClass, select_object), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, AMITK_TYPE_OBJECT); } static void list_view_init (AmitkListView * list_view) { list_view->study = NULL; } static void list_view_destroy (GtkObject * object) { AmitkListView * list_view; g_return_if_fail (object != NULL); g_return_if_fail (AMITK_IS_LIST_VIEW (object)); list_view = AMITK_LIST_VIEW (object); if (list_view->study != NULL) { list_view_remove_object(list_view, AMITK_OBJECT(list_view->study)); list_view->study = NULL; } if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } static void list_view_object_update_cb(AmitkObject * object, gpointer data) { AmitkListView * list_view = data; GtkTreeIter iter; GtkTreeModel * model; GdkPixbuf * pixbuf; g_return_if_fail(AMITK_IS_LIST_VIEW(list_view)); g_return_if_fail(AMITK_IS_OBJECT(object)); if (list_view_find_object(list_view, object, &iter)) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view)); pixbuf = image_get_object_pixbuf(object); gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_ICON, pixbuf, COLUMN_NAME, AMITK_OBJECT_NAME(object), -1); g_object_unref(pixbuf); } // g_signal_emit(G_OBJECT(list_view), list_view_signals[SELECT_OBJECT], 0,object); return; } static void list_view_object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { AmitkListView * list_view = data; g_return_if_fail(AMITK_IS_LIST_VIEW(list_view)); g_return_if_fail(AMITK_IS_OBJECT(child)); list_view_add_object(AMITK_LIST_VIEW(list_view), child); return; } static void list_view_object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { AmitkListView * list_view = data; g_return_if_fail(AMITK_IS_LIST_VIEW(list_view)); g_return_if_fail(AMITK_IS_OBJECT(child)); list_view_remove_object(AMITK_LIST_VIEW(list_view), child); return; } static gboolean list_view_find_recurse(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { list_view_find_t * list_view_find=data; AmitkObject * object; gtk_tree_model_get(model, iter, COLUMN_OBJECT, &object, -1); g_return_val_if_fail(object != NULL, FALSE); if (object == list_view_find->object) { list_view_find->iter = *iter; list_view_find->found = TRUE; return TRUE; } else { return FALSE; } } static gboolean list_view_find_object(AmitkListView * list_view, AmitkObject * object, GtkTreeIter * iter) { GtkTreeModel * model; list_view_find_t list_view_find; g_return_val_if_fail(AMITK_IS_LIST_VIEW(list_view),FALSE); model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view)); list_view_find.object = object; list_view_find.found = FALSE; gtk_tree_model_foreach(model, list_view_find_recurse, &list_view_find); if (list_view_find.found) { *iter = list_view_find.iter; return TRUE; } else return FALSE; } static void list_view_add_object(AmitkListView * list_view, AmitkObject * object) { GList * children; GtkTreeIter parent_iter; GtkTreeIter iter; GtkTreeModel * model; GdkPixbuf * pixbuf; amitk_object_ref(object); /* add a reference */ if (AMITK_IS_STUDY(object)) { /* save a pointer to thestudy object */ if (list_view->study != NULL) { list_view_remove_object(list_view, AMITK_OBJECT(list_view->study)); } list_view->study = AMITK_STUDY(object); } model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view)); if (AMITK_OBJECT_PARENT(object) == NULL) gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire a top-level iterator */ else { if (list_view_find_object(list_view, AMITK_OBJECT_PARENT(object), &parent_iter)) gtk_list_store_insert_after (GTK_LIST_STORE(model), &iter, &parent_iter); else g_return_if_reached(); } pixbuf = image_get_object_pixbuf(object); gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_ICON, pixbuf, COLUMN_NAME, AMITK_OBJECT_NAME(object), COLUMN_OBJECT, object, -1); g_object_unref(pixbuf); g_signal_connect(G_OBJECT(object), "object_name_changed", G_CALLBACK(list_view_object_update_cb), list_view); g_signal_connect(G_OBJECT(object), "object_selection_changed", G_CALLBACK(list_view_object_update_cb), list_view); if (AMITK_IS_DATA_SET(object)) { g_signal_connect(G_OBJECT(object), "modality_changed", G_CALLBACK(list_view_object_update_cb), list_view); g_signal_connect(G_OBJECT(object), "color_table_changed", G_CALLBACK(list_view_object_update_cb), list_view); } else if (AMITK_IS_ROI(object)) { g_signal_connect(G_OBJECT(object), "roi_type_changed", G_CALLBACK(list_view_object_update_cb), list_view); } g_signal_connect(G_OBJECT(object), "object_add_child", G_CALLBACK(list_view_object_add_child_cb), list_view); g_signal_connect(G_OBJECT(object), "object_remove_child", G_CALLBACK(list_view_object_remove_child_cb), list_view); /* add children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { list_view_add_object(list_view, children->data); children = children->next; } } static void list_view_remove_object(AmitkListView * list_view, AmitkObject * object) { GList * children; GtkTreeIter iter; GtkTreeModel * model; g_return_if_fail(AMITK_IS_LIST_VIEW(list_view)); g_return_if_fail(list_view_find_object(list_view, object, &iter)); /* shouldn't fail */ /* unselect the object */ amitk_object_unselect(object, AMITK_SELECTION_ALL); /* recursive remove children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { list_view_remove_object(list_view, children->data); children = children->next; } /* disconnect the object's signals */ g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(list_view_object_update_cb), list_view); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(list_view_object_add_child_cb), list_view); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(list_view_object_remove_child_cb), list_view); /* remove the object */ model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view)); gtk_list_store_remove(GTK_LIST_STORE(model), &iter); /* and unref */ amitk_object_unref(object); return; } GtkWidget* amitk_list_view_new (void) { AmitkListView * list_view; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; list_view = g_object_new(amitk_list_view_get_type(), NULL); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list_view), FALSE); store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_BOOLEAN, /* COLUMN_VISIBLE_SINGLE */ G_TYPE_BOOLEAN,/* COLUMN_VISIBLE_LINKED_2WAY */ G_TYPE_BOOLEAN, /* COLUMN_VISIBLE_LINKED_3WAY */ G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model (GTK_TREE_VIEW(list_view), GTK_TREE_MODEL (store)); g_object_unref(store); /* icon */ renderer = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new_with_attributes("", renderer, "pixbuf", COLUMN_ICON, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column); /* name */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes("name", renderer, "text", COLUMN_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); return GTK_WIDGET (list_view); } void amitk_list_view_set_study(AmitkListView * list_view, AmitkStudy * study) { g_return_if_fail(AMITK_IS_LIST_VIEW(list_view)); g_return_if_fail(AMITK_IS_STUDY(study)); list_view_add_object(list_view, AMITK_OBJECT(study)); return; } amide-1.0.6/amide-current/attic/amitk_list_view.h000066400000000000000000000042271423227705100220130ustar00rootroot00000000000000/* amitk_list_view.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2004 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_LIST_VIEW_H__ #define __AMITK_LIST_VIEW_H__ /* includes we always need with this widget */ #include #include "amide.h" #include "amitk_type_builtins.h" #include "amitk_study.h" G_BEGIN_DECLS #define AMITK_TYPE_LIST_VIEW (amitk_list_view_get_type ()) #define AMITK_LIST_VIEW(obj) (GTK_CHECK_CAST ((obj), AMITK_TYPE_LIST_VIEW, AmitkListView)) #define AMITK_LIST_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLD, AmitklistViewClass)) #define AMITK_IS_LIST_VIEW(obj) (GTK_CHECK_TYPE ((obj), AMITK_TYPE_LIST_VIEW)) #define AMITK_IS_LIST_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_LIST_VIEW)) typedef struct _AmitkListView AmitkListView; typedef struct _AmitkListViewClass AmitkListViewClass; struct _AmitkListView { GtkTreeView tree; AmitkStudy * study; }; struct _AmitkListViewClass { GtkTreeViewClass parent_class; void (* select_object) (AmitkListView * list, AmitkObject * object); }; GType amitk_list_view_get_type (void); GtkWidget* amitk_list_view_new (void); void amitk_list_view_set_study (AmitkListView * list_view, AmitkStudy * study); G_END_DECLS #endif /* __AMITK_LIST_VIEW_H__ */ amide-1.0.6/amide-current/attic/amitk_xif_sel.c000066400000000000000000003453421423227705100214400ustar00rootroot00000000000000/* amitk_xif_sel.c - this is gtkfilesel, but slightly modified so that it lists .xif files and directories in the file list, and compiles cleanly under AMIDE */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include "amide_config.h" #include "amitk_common.h" #include "amitk_xif_sel.h" #include /* for g_mkdir */ #include #include #include #ifdef HAVE_SYS_PARAM_H #include #endif #include #ifndef G_PLATFORM_WIN32 #ifdef HAVE_UNISTD_H #include #endif #endif #include #include #ifdef HAVE_PWD_H #include #endif #include /* Include early to get G_OS_WIN32 etc */ #if defined(G_PLATFORM_WIN32) #include #define STRICT #include #undef STRICT #endif /* G_PLATFORM_WIN32 */ #ifdef G_OS_WIN32 #include /* For gethostname */ #endif #include /* gtkfilesel still uses gtkoptionmenu... */ #undef GTK_DISABLE_DEPRECATED #include #define GTK_DISABLE_DEPRECATED #define WANT_HPANED 1 #ifdef G_OS_WIN32 #include #include #ifndef S_ISDIR #define S_ISDIR(mode) ((mode)&_S_IFDIR) #endif #endif /* G_OS_WIN32 */ #ifdef G_WITH_CYGWIN #include /* For cygwin_conv_to_posix_path */ #endif #define DIR_LIST_WIDTH 180 #define DIR_LIST_HEIGHT 180 #define FILE_LIST_WIDTH 180 #define FILE_LIST_HEIGHT 180 /* The Hurd doesn't define either PATH_MAX or MAXPATHLEN, so we put this * in here, since the rest of the code in the file does require some * fixed maximum. */ #ifndef MAXPATHLEN # ifdef PATH_MAX # define MAXPATHLEN PATH_MAX # else # define MAXPATHLEN 2048 # endif #endif /* I've put this here so it doesn't get confused with the * file completion interface */ typedef struct _HistoryCallbackArg HistoryCallbackArg; struct _HistoryCallbackArg { gchar *directory; GtkWidget *menu_item; }; typedef struct _CompletionState CompletionState; typedef struct _CompletionDir CompletionDir; typedef struct _CompletionDirSent CompletionDirSent; typedef struct _CompletionDirEntry CompletionDirEntry; typedef struct _CompletionUserDir CompletionUserDir; typedef struct _PossibleCompletion PossibleCompletion; /* Non-external file completion decls and structures */ /* A contant telling PRCS how many directories to cache. Its actually * kept in a list, so the geometry isn't important. */ #define CMPL_DIRECTORY_CACHE_SIZE 10 /* A constant used to determine whether a substring was an exact * match by first_diff_index() */ #define PATTERN_MATCH -1 #define CMPL_ERRNO_TOO_LONG ((1<<16)-1) #define CMPL_ERRNO_DID_NOT_CONVERT ((1<<16)-2) /* This structure contains all the useful information about a directory * for the purposes of filename completion. These structures are cached * in the CompletionState struct. CompletionDir's are reference counted. */ struct _CompletionDirSent { #ifndef G_PLATFORM_WIN32 ino_t inode; time_t mtime; dev_t device; #endif gint entry_count; struct _CompletionDirEntry *entries; }; struct _CompletionDir { CompletionDirSent *sent; gchar *fullname; gint fullname_len; struct _CompletionDir *cmpl_parent; gint cmpl_index; gchar *cmpl_text; }; /* This structure contains pairs of directory entry names with a flag saying * whether or not they are a valid directory. NOTE: This information is used * to provide the caller with information about whether to update its completions * or try to open a file. Since directories are cached by the directory mtime, * a symlink which points to an invalid file (which will not be a directory), * will not be reevaluated if that file is created, unless the containing * directory is touched. I consider this case to be worth ignoring (josh). */ struct _CompletionDirEntry { gboolean is_dir; gchar *entry_name; gchar *sort_key; }; struct _CompletionUserDir { gchar *login; gchar *homedir; }; struct _PossibleCompletion { /* accessible fields, all are accessed externally by functions * declared above */ gchar *text; gint is_a_completion; gboolean is_directory; /* Private fields */ gint text_alloc; }; struct _CompletionState { gint last_valid_char; gchar *updated_text; gint updated_text_len; gint updated_text_alloc; gboolean re_complete; gchar *user_dir_name_buffer; gint user_directories_len; gchar *last_completion_text; gint user_completion_index; /* if >= 0, currently completing ~user */ struct _CompletionDir *completion_dir; /* directory completing from */ struct _CompletionDir *active_completion_dir; struct _PossibleCompletion the_completion; struct _CompletionDir *reference_dir; /* initial directory */ GList* directory_storage; GList* directory_sent_storage; struct _CompletionUserDir *user_directories; }; enum { PROP_0, PROP_SHOW_FILEOPS, PROP_FILENAME, PROP_SELECT_MULTIPLE }; enum { DIR_COLUMN }; enum { FILE_COLUMN }; /* File completion functions which would be external, were they used * outside of this file. */ static CompletionState* cmpl_init_state (void); static void cmpl_free_state (CompletionState *cmpl_state); static gint cmpl_state_okay (CompletionState* cmpl_state); static const gchar* cmpl_strerror (gint); static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, gchar **remaining_text, CompletionState *cmpl_state); /* Returns a name for consideration, possibly a completion, this name * will be invalid after the next call to cmpl_next_completion. */ static char* cmpl_this_completion (PossibleCompletion*); /* True if this completion matches the given text. Otherwise, this * output can be used to have a list of non-completions. */ static gint cmpl_is_a_completion (PossibleCompletion*); /* True if the completion is a directory */ static gboolean cmpl_is_directory (PossibleCompletion*); /* Obtains the next completion, or NULL */ static PossibleCompletion* cmpl_next_completion (CompletionState*); /* Updating completions: the return value of cmpl_updated_text() will * be text_to_complete completed as much as possible after the most * recent call to cmpl_completion_matches. For the present * application, this is the suggested replacement for the user's input * string. You must CALL THIS AFTER ALL cmpl_text_completions have * been received. */ static gchar* cmpl_updated_text (CompletionState* cmpl_state); /* After updating, to see if the completion was a directory, call * this. If it was, you should consider re-calling completion_matches. */ static gboolean cmpl_updated_dir (CompletionState* cmpl_state); /* Current location: if using file completion, return the current * directory, from which file completion begins. More specifically, * the cwd concatenated with all exact completions up to the last * directory delimiter('/'). */ static gchar* cmpl_reference_position (CompletionState* cmpl_state); /* backing up: if cmpl_completion_matches returns NULL, you may query * the index of the last completable character into cmpl_updated_text. */ static gint cmpl_last_valid_char (CompletionState* cmpl_state); /* When the user selects a non-directory, call cmpl_completion_fullname * to get the full name of the selected file. */ static const gchar* cmpl_completion_fullname (const gchar*, CompletionState* cmpl_state); /* Directory operations. */ static CompletionDir* open_ref_dir (gchar* text_to_complete, gchar** remaining_text, CompletionState* cmpl_state); #ifndef G_PLATFORM_WIN32 static gboolean check_dir (gchar *dir_name, struct stat *result, gboolean *stat_subdirs); #endif static CompletionDir* open_dir (gchar* dir_name, CompletionState* cmpl_state); #ifdef HAVE_PWD_H static CompletionDir* open_user_dir (const gchar* text_to_complete, CompletionState *cmpl_state); #endif static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, CompletionState *cmpl_state); static CompletionDirSent* open_new_dir (gchar* dir_name, struct stat* sbuf, gboolean stat_subdirs); static gint correct_dir_fullname (CompletionDir* cmpl_dir); static gint correct_parent (CompletionDir* cmpl_dir, struct stat *sbuf); #ifndef G_PLATFORM_WIN32 static gchar* find_parent_dir_fullname (gchar* dirname); #endif static CompletionDir* attach_dir (CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state); static void free_dir_sent (CompletionDirSent* sent); static void free_dir (CompletionDir *dir); static void prune_memory_usage(CompletionState *cmpl_state); /* Completion operations */ #ifdef HAVE_PWD_H static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, CompletionState *cmpl_state); #endif static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state); static CompletionDir* find_completion_dir(gchar* text_to_complete, gchar** remaining_text, CompletionState* cmpl_state); static PossibleCompletion* append_completion_text(gchar* text, CompletionState* cmpl_state); #ifdef HAVE_PWD_H static gint get_pwdb(CompletionState* cmpl_state); static gint compare_user_dir(const void* a, const void* b); #endif static gint first_diff_index(gchar* pat, gchar* text); static gint compare_cmpl_dir(const void* a, const void* b); static void update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state); static void amitk_xif_selection_class_init (AmitkXifSelectionClass *klass); static void amitk_xif_selection_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void amitk_xif_selection_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void amitk_xif_selection_init (AmitkXifSelection *filesel); static void amitk_xif_selection_finalize (GObject *object); static void amitk_xif_selection_destroy (GtkObject *object); static void amitk_xif_selection_map (GtkWidget *widget); static gint amitk_xif_selection_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data); static gint amitk_xif_selection_insert_text (GtkWidget *widget, const gchar *new_text, gint new_text_length, gint *position, gpointer user_data); static void amitk_xif_selection_update_fileops (AmitkXifSelection *filesel); static void amitk_xif_selection_file_activate (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data); static void amitk_xif_selection_file_changed (GtkTreeSelection *selection, gpointer user_data); static void amitk_xif_selection_dir_activate (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data); static void amitk_xif_selection_populate (AmitkXifSelection *fs, gchar *rel_path, gboolean try_complete, gboolean reset_entry); static void amitk_xif_selection_abort (AmitkXifSelection *fs); static void amitk_xif_selection_update_history_menu (AmitkXifSelection *fs, gchar *current_dir); static void amitk_xif_selection_create_dir (GtkWidget *widget, gpointer data); static void amitk_xif_selection_delete_file (GtkWidget *widget, gpointer data); static void amitk_xif_selection_rename_file (GtkWidget *widget, gpointer data); static void free_selected_names (GPtrArray *names); static gboolean _amitk_fnmatch (const char *pattern, const char *string); #ifndef G_PLATFORM_WIN32 #define compare_utf8_filenames(a, b) strcmp(a, b) #define compare_sys_filenames(a, b) strcmp(a, b) #else static gint compare_utf8_filenames (const gchar *a, const gchar *b) { gchar *a_folded, *b_folded; gint retval; a_folded = g_utf8_strdown (a, -1); b_folded = g_utf8_strdown (b, -1); retval = strcmp (a_folded, b_folded); g_free (a_folded); g_free (b_folded); return retval; } static gint compare_sys_filenames (const gchar *a, const gchar *b) { gchar *a_utf8, *b_utf8; gint retval; a_utf8 = g_filename_to_utf8 (a, -1, NULL, NULL, NULL); b_utf8 = g_filename_to_utf8 (b, -1, NULL, NULL, NULL); retval = compare_utf8_filenames (a_utf8, b_utf8); g_free (a_utf8); g_free (b_utf8); return retval; } #endif static GtkWindowClass *parent_class = NULL; /* Saves errno when something cmpl does fails. */ static gint cmpl_errno; #ifdef G_WITH_CYGWIN /* * Take the path currently in the file selection * entry field and translate as necessary from * a WIN32 style to Cygwin style path. For * instance translate: * x:\somepath\file.jpg * to: * /cygdrive/x/somepath/file.jpg * * Replace the path in the selection text field. * Return a boolean value concerning whether a * translation had to be made. */ static int translate_win32_path (AmitkXifSelection *filesel) { int updated = 0; const gchar *path; gchar newPath[MAX_PATH]; /* * Retrieve the current path */ path = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); cygwin_conv_to_posix_path (path, newPath); updated = (strcmp (path, newPath) != 0); if (updated) gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), newPath); return updated; } #endif GType amitk_xif_selection_get_type (void) { static GType file_selection_type = 0; if (!file_selection_type) { static const GTypeInfo filesel_info = { sizeof (AmitkXifSelectionClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) amitk_xif_selection_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (AmitkXifSelection), 0, /* n_preallocs */ (GInstanceInitFunc) amitk_xif_selection_init, NULL /* value table */ }; file_selection_type = g_type_register_static (GTK_TYPE_DIALOG, "AmitkXifSelection", &filesel_info, 0); } return file_selection_type; } static void amitk_xif_selection_class_init (AmitkXifSelectionClass *class) { GObjectClass *gobject_class; GtkObjectClass *object_class; GtkWidgetClass *widget_class; gobject_class = (GObjectClass*) class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; parent_class = g_type_class_peek_parent (class); gobject_class->finalize = amitk_xif_selection_finalize; gobject_class->set_property = amitk_xif_selection_set_property; gobject_class->get_property = amitk_xif_selection_get_property; g_object_class_install_property (gobject_class, PROP_FILENAME, g_param_spec_string ("filename", _("Filename"), _("The currently selected filename"), NULL, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_SHOW_FILEOPS, g_param_spec_boolean ("show_fileops", _("Show file operations"), _("Whether buttons for creating/manipulating files should be displayed"), FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_SELECT_MULTIPLE, g_param_spec_boolean ("select_multiple", _("Select multiple"), _("Whether to allow multiple files to be selected"), FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE)); object_class->destroy = amitk_xif_selection_destroy; widget_class->map = amitk_xif_selection_map; } static void amitk_xif_selection_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { AmitkXifSelection *filesel; filesel = AMITK_XIF_SELECTION (object); switch (prop_id) { case PROP_FILENAME: amitk_xif_selection_set_filename (filesel, g_value_get_string (value)); break; case PROP_SHOW_FILEOPS: if (g_value_get_boolean (value)) amitk_xif_selection_show_fileop_buttons (filesel); else amitk_xif_selection_hide_fileop_buttons (filesel); break; case PROP_SELECT_MULTIPLE: amitk_xif_selection_set_select_multiple (filesel, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void amitk_xif_selection_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { AmitkXifSelection *filesel; filesel = AMITK_XIF_SELECTION (object); switch (prop_id) { case PROP_FILENAME: g_value_set_string (value, amitk_xif_selection_get_filename(filesel)); break; case PROP_SHOW_FILEOPS: /* This is a little bit hacky, but doing otherwise would require * adding a field to the object. */ g_value_set_boolean (value, (filesel->fileop_c_dir && filesel->fileop_del_file && filesel->fileop_ren_file)); break; case PROP_SELECT_MULTIPLE: g_value_set_boolean (value, amitk_xif_selection_get_select_multiple (filesel)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean grab_default (GtkWidget *widget) { gtk_widget_grab_default (widget); return FALSE; } static void amitk_xif_selection_init (AmitkXifSelection *filesel) { GtkWidget *entry_vbox; GtkWidget *label; GtkWidget *list_hbox, *list_container; GtkWidget *confirm_area; GtkWidget *pulldown_hbox; GtkWidget *scrolled_win; GtkWidget *eventbox; GtkWidget *spacer; GtkDialog *dialog; GtkListStore *model; GtkTreeViewColumn *column; gtk_widget_push_composite_child (); dialog = GTK_DIALOG (filesel); filesel->cmpl_state = cmpl_init_state (); /* The dialog-sized vertical box */ filesel->main_vbox = dialog->vbox; gtk_container_set_border_width (GTK_CONTAINER (filesel), 10); /* The horizontal box containing create, rename etc. buttons */ filesel->button_area = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (filesel->button_area), GTK_BUTTONBOX_START); gtk_box_set_spacing (GTK_BOX (filesel->button_area), 0); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->button_area, FALSE, FALSE, 0); gtk_widget_show (filesel->button_area); amitk_xif_selection_show_fileop_buttons (filesel); /* hbox for pulldown menu */ pulldown_hbox = gtk_hbox_new (TRUE, 5); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), pulldown_hbox, FALSE, FALSE, 0); gtk_widget_show (pulldown_hbox); /* Pulldown menu */ filesel->history_pulldown = gtk_option_menu_new(); gtk_widget_show (filesel->history_pulldown); gtk_box_pack_start (GTK_BOX (pulldown_hbox), filesel->history_pulldown, FALSE, FALSE, 0); /* The horizontal box containing the directory and file listboxes */ spacer = gtk_hbox_new (FALSE, 0); gtk_widget_set_size_request (spacer, -1, 5); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), spacer, FALSE, FALSE, 0); gtk_widget_show (spacer); list_hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), list_hbox, TRUE, TRUE, 0); gtk_widget_show (list_hbox); if (WANT_HPANED) list_container = g_object_new (GTK_TYPE_HPANED, "visible", TRUE, "parent", list_hbox, "border_width", 0, NULL); else list_container = list_hbox; spacer = gtk_hbox_new (FALSE, 0); gtk_widget_set_size_request (spacer, -1, 5); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), spacer, FALSE, FALSE, 0); gtk_widget_show (spacer); /* The directories list */ model = gtk_list_store_new (1, G_TYPE_STRING); filesel->dir_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); g_object_unref (model); column = gtk_tree_view_column_new_with_attributes (_("Folders"), gtk_cell_renderer_text_new (), "text", DIR_COLUMN, NULL); label = gtk_label_new_with_mnemonic (_("Fol_ders")); gtk_label_set_mnemonic_widget (GTK_LABEL (label), filesel->dir_list); gtk_widget_show (label); gtk_tree_view_column_set_widget (column, label); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column (GTK_TREE_VIEW (filesel->dir_list), column); gtk_widget_set_size_request(filesel->dir_list, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); g_signal_connect (G_OBJECT(filesel->dir_list), "row_activated", G_CALLBACK (amitk_xif_selection_dir_activate), filesel); /* gtk_clist_column_titles_passive (GTK_CLIST (filesel->dir_list)); */ scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->dir_list); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_container_set_border_width (GTK_CONTAINER (scrolled_win), 0); if (GTK_IS_PANED (list_container)) gtk_paned_pack1 (GTK_PANED (list_container), scrolled_win, TRUE, TRUE); else gtk_container_add (GTK_CONTAINER (list_container), scrolled_win); gtk_widget_show (filesel->dir_list); gtk_widget_show (scrolled_win); /* The files list */ model = gtk_list_store_new (1, G_TYPE_STRING); filesel->file_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); g_object_unref (model); column = gtk_tree_view_column_new_with_attributes (_("XIF Files"), gtk_cell_renderer_text_new (), "text", FILE_COLUMN, NULL); label = gtk_label_new_with_mnemonic (_("XIF _Files")); gtk_label_set_mnemonic_widget (GTK_LABEL (label), filesel->file_list); gtk_widget_show (label); gtk_tree_view_column_set_widget (column, label); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column (GTK_TREE_VIEW (filesel->file_list), column); gtk_widget_set_size_request (filesel->file_list, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); g_signal_connect (G_OBJECT(filesel->file_list), "row_activated", G_CALLBACK (amitk_xif_selection_file_activate), filesel); g_signal_connect (G_OBJECT(gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list))), "changed", G_CALLBACK (amitk_xif_selection_file_changed), filesel); /* gtk_clist_column_titles_passive (GTK_CLIST (filesel->file_list)); */ scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->file_list); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_container_set_border_width (GTK_CONTAINER (scrolled_win), 0); gtk_container_add (GTK_CONTAINER (list_container), scrolled_win); gtk_widget_show (filesel->file_list); gtk_widget_show (scrolled_win); /* action area for packing buttons into. */ filesel->action_area = gtk_hbox_new (TRUE, 0); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->action_area, FALSE, FALSE, 0); gtk_widget_show (filesel->action_area); /* The OK/Cancel button area */ confirm_area = dialog->action_area; /* The Cancel button */ filesel->cancel_button = gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); /* The OK button */ filesel->ok_button = gtk_dialog_add_button (dialog, GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_widget_grab_default (filesel->ok_button); /* The selection entry widget */ entry_vbox = gtk_vbox_new (FALSE, 2); gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 2); gtk_widget_show (entry_vbox); eventbox = gtk_event_box_new (); filesel->selection_text = label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (eventbox), label); gtk_box_pack_start (GTK_BOX (entry_vbox), eventbox, FALSE, FALSE, 0); gtk_widget_show (label); gtk_widget_show (eventbox); filesel->selection_entry = gtk_entry_new (); g_signal_connect(G_OBJECT (filesel->selection_entry), "key_press_event", G_CALLBACK(amitk_xif_selection_key_press), filesel); g_signal_connect(G_OBJECT (filesel->selection_entry), "insert_text", G_CALLBACK(amitk_xif_selection_insert_text), NULL); g_signal_connect_swapped (G_OBJECT(filesel->selection_entry), "changed", G_CALLBACK (amitk_xif_selection_update_fileops), filesel); g_signal_connect_swapped (G_OBJECT (filesel->selection_entry), "focus_in_event", G_CALLBACK(grab_default), G_OBJECT (filesel->ok_button)); g_signal_connect_swapped (G_OBJECT (filesel->selection_entry), "activate", G_CALLBACK(gtk_button_clicked), G_OBJECT (filesel->ok_button)); gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_entry, TRUE, TRUE, 0); gtk_widget_show (filesel->selection_entry); gtk_label_set_mnemonic_widget (GTK_LABEL (filesel->selection_text), filesel->selection_entry); if (!cmpl_state_okay (filesel->cmpl_state)) { gchar err_buf[256]; g_snprintf (err_buf, sizeof (err_buf), _("Folder unreadable: %s"), cmpl_strerror (cmpl_errno)); gtk_label_set_text (GTK_LABEL (filesel->selection_text), err_buf); } else { amitk_xif_selection_populate (filesel, "", FALSE, TRUE); } gtk_widget_grab_focus (filesel->selection_entry); gtk_widget_pop_composite_child (); } static gchar * uri_list_extract_first_uri (const gchar* uri_list) { const gchar *p, *q; g_return_val_if_fail (uri_list != NULL, NULL); p = uri_list; /* We don't actually try to validate the URI according to RFC * 2396, or even check for allowed characters - we just ignore * comments and trim whitespace off the ends. We also * allow LF delimination as well as the specified CRLF. * * We do allow comments like specified in RFC 2483. */ while (p) { if (*p != '#') { while (g_ascii_isspace(*p)) p++; q = p; while (*q && (*q != '\n') && (*q != '\r')) q++; if (q > p) { q--; while (q > p && g_ascii_isspace (*q)) q--; if (q > p) return g_strndup (p, q - p + 1); } } p = strchr (p, '\n'); if (p) p++; } return NULL; } static void dnd_really_drop (GtkWidget *dialog, gint response_id, AmitkXifSelection *fs) { gchar *filename; if (response_id == GTK_RESPONSE_YES) { filename = g_object_get_data (G_OBJECT (dialog), "gtk-fs-dnd-filename"); amitk_xif_selection_set_filename (fs, filename); } gtk_widget_destroy (dialog); } static void filenames_dropped (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time) { char *uri = NULL; char *filename = NULL; char *hostname; char this_hostname[257]; int res; GError *error = NULL; if (!selection_data->data) return; uri = uri_list_extract_first_uri ((char *)selection_data->data); if (!uri) return; filename = g_filename_from_uri (uri, &hostname, &error); g_free (uri); if (!filename) { g_warning (_("Error getting dropped filename: %s\n"), error->message); g_error_free (error); return; } res = gethostname (this_hostname, 256); this_hostname[256] = 0; if ((hostname == NULL) || (res == 0 && strcmp (hostname, this_hostname) == 0) || (strcmp (hostname, "localhost") == 0)) amitk_xif_selection_set_filename (AMITK_XIF_SELECTION (widget), filename); else { GtkWidget *dialog; gchar *filename_utf8; /* Conversion back to UTF-8 should always succeed for the result * of g_filename_from_uri() */ filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); g_assert (filename_utf8); dialog = gtk_message_dialog_new (GTK_WINDOW (widget), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("The file \"%s\" resides on another machine (called %s) and may not be available to this program.\n" "Are you sure that you want to select it?"), filename_utf8, hostname); g_free (filename_utf8); g_object_set_data_full (G_OBJECT (dialog), "gtk-fs-dnd-filename", g_strdup (filename), g_free); g_signal_connect_data (G_OBJECT(dialog), "response", (GCallback) dnd_really_drop, widget, NULL, 0); gtk_widget_show (dialog); } g_free (hostname); g_free (filename); } enum { TARGET_URILIST, TARGET_UTF8_STRING, TARGET_STRING, TARGET_TEXT, TARGET_COMPOUND_TEXT }; static void filenames_drag_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, AmitkXifSelection *filesel) { const gchar *file; gchar *uri_list; char hostname[256]; int res; GError *error=NULL; file = amitk_xif_selection_get_filename (filesel); if (file) { if (info == TARGET_URILIST) { res = gethostname (hostname, 256); error = NULL; uri_list = g_filename_to_uri (file, (!res)?hostname:NULL, &error); if (!uri_list) { g_warning (_("Error getting filename: %s\n"), error->message); g_error_free (error); return; } gtk_selection_data_set (selection_data, selection_data->target, 8, (void *)uri_list, strlen((char *)uri_list)); g_free (uri_list); } else { gchar *filename_utf8 = g_filename_to_utf8 (file, -1, NULL, NULL, NULL); g_assert (filename_utf8); gtk_selection_data_set_text (selection_data, filename_utf8, -1); g_free (filename_utf8); } } } static void file_selection_setup_dnd (AmitkXifSelection *filesel) { GtkWidget *eventbox; static const GtkTargetEntry drop_types[] = { { "text/uri-list", 0, TARGET_URILIST} }; static gint n_drop_types = sizeof(drop_types)/sizeof(drop_types[0]); static const GtkTargetEntry drag_types[] = { { "text/uri-list", 0, TARGET_URILIST}, { "UTF8_STRING", 0, TARGET_UTF8_STRING }, { "STRING", 0, 0 }, { "TEXT", 0, 0 }, { "COMPOUND_TEXT", 0, 0 } }; static gint n_drag_types = sizeof(drag_types)/sizeof(drag_types[0]); gtk_drag_dest_set (GTK_WIDGET (filesel), GTK_DEST_DEFAULT_ALL, drop_types, n_drop_types, GDK_ACTION_COPY); g_signal_connect (G_OBJECT(filesel), "drag_data_received", G_CALLBACK(filenames_dropped), NULL); eventbox = gtk_widget_get_parent (filesel->selection_text); gtk_drag_source_set (eventbox, GDK_BUTTON1_MASK, drag_types, n_drag_types, GDK_ACTION_COPY); g_signal_connect (G_OBJECT (eventbox),"drag_data_get", G_CALLBACK(filenames_drag_get), filesel); } GtkWidget* amitk_xif_selection_new (const gchar *title) { AmitkXifSelection *filesel; filesel = g_object_new (AMITK_TYPE_XIF_SELECTION, NULL); gtk_window_set_title (GTK_WINDOW (filesel), title); gtk_dialog_set_has_separator (GTK_DIALOG (filesel), FALSE); file_selection_setup_dnd (filesel); return GTK_WIDGET (filesel); } void amitk_xif_selection_show_fileop_buttons (AmitkXifSelection *filesel) { g_return_if_fail (AMITK_IS_XIF_SELECTION (filesel)); /* delete, create directory, and rename */ if (!filesel->fileop_c_dir) { filesel->fileop_c_dir = gtk_button_new_with_mnemonic (_("_New Folder")); g_signal_connect (G_OBJECT (filesel->fileop_c_dir), "clicked", G_CALLBACK(amitk_xif_selection_create_dir), filesel); gtk_box_pack_start (GTK_BOX (filesel->button_area), filesel->fileop_c_dir, TRUE, TRUE, 0); gtk_widget_show (filesel->fileop_c_dir); } if (!filesel->fileop_del_file) { filesel->fileop_del_file = gtk_button_new_with_mnemonic (_("De_lete File")); g_signal_connect (G_OBJECT (filesel->fileop_del_file), "clicked", G_CALLBACK(amitk_xif_selection_delete_file), filesel); gtk_box_pack_start (GTK_BOX (filesel->button_area), filesel->fileop_del_file, TRUE, TRUE, 0); gtk_widget_show (filesel->fileop_del_file); } if (!filesel->fileop_ren_file) { filesel->fileop_ren_file = gtk_button_new_with_mnemonic (_("_Rename File")); g_signal_connect (G_OBJECT (filesel->fileop_ren_file), "clicked", G_CALLBACK(amitk_xif_selection_rename_file), filesel); gtk_box_pack_start (GTK_BOX (filesel->button_area), filesel->fileop_ren_file, TRUE, TRUE, 0); gtk_widget_show (filesel->fileop_ren_file); } amitk_xif_selection_update_fileops (filesel); g_object_notify (G_OBJECT (filesel), "show_fileops"); } void amitk_xif_selection_hide_fileop_buttons (AmitkXifSelection *filesel) { g_return_if_fail (AMITK_IS_XIF_SELECTION (filesel)); if (filesel->fileop_ren_file) { gtk_widget_destroy (filesel->fileop_ren_file); filesel->fileop_ren_file = NULL; } if (filesel->fileop_del_file) { gtk_widget_destroy (filesel->fileop_del_file); filesel->fileop_del_file = NULL; } if (filesel->fileop_c_dir) { gtk_widget_destroy (filesel->fileop_c_dir); filesel->fileop_c_dir = NULL; } g_object_notify (G_OBJECT (filesel), "show_fileops"); } /** * amitk_file_selection_set_filename: * @xifsel: a #AmitkFileSelection. * @dirname: a string to set as the default directory name. * * Sets a default path for the file requestor. If dirname includes a * directory path, then the requestor will open with that path as its * current working directory. * * The encoding of @dirname is the on-disk encoding, which * may not be UTF-8. See g_filename_from_utf8(). **/ void amitk_xif_selection_set_filename (AmitkXifSelection *filesel, const gchar *filename) { gchar *buf; const char *name, *last_slash; char *filename_utf8; g_return_if_fail (AMITK_IS_XIF_SELECTION (filesel)); g_return_if_fail (filename != NULL); filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); g_return_if_fail (filename_utf8 != NULL); last_slash = strrchr (filename_utf8, G_DIR_SEPARATOR); if (!last_slash) { buf = g_strdup (""); name = filename_utf8; } else { buf = g_strdup (filename_utf8); buf[last_slash - filename_utf8 + 1] = 0; name = last_slash + 1; } amitk_xif_selection_populate (filesel, buf, FALSE, TRUE); if (filesel->selection_entry) gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); g_free (buf); g_object_notify (G_OBJECT (filesel), "filename"); g_free (filename_utf8); } /** * amitk_xif_selection_get_filename: * @filesel: a #AmitkXifSelection * * This function returns the selected filename in the on-disk encoding * (see g_filename_from_utf8()), which may or may not be the same as that * used by GTK+ (UTF-8). To convert to UTF-8, call g_filename_to_utf8(). * The returned string points to a statically allocated buffer and * should be copied if you plan to keep it around. * * If no file is selected then the selected directory path is returned. * * Return value: currently-selected filename in the on-disk encoding. **/ G_CONST_RETURN gchar* amitk_xif_selection_get_filename (AmitkXifSelection *filesel) { static const gchar nothing[2] = ""; static gchar something[MAXPATHLEN*2]; char *sys_filename; const char *text; g_return_val_if_fail (AMITK_IS_XIF_SELECTION (filesel), nothing); #ifdef G_WITH_CYGWIN translate_win32_path (filesel); #endif text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); if (text) { sys_filename = g_filename_from_utf8 (cmpl_completion_fullname (text, filesel->cmpl_state), -1, NULL, NULL, NULL); if (!sys_filename) return nothing; strncpy (something, sys_filename, sizeof (something)); g_free (sys_filename); return something; } return nothing; } void amitk_xif_selection_complete (AmitkXifSelection *filesel, const gchar *pattern) { g_return_if_fail (AMITK_IS_XIF_SELECTION (filesel)); g_return_if_fail (pattern != NULL); if (filesel->selection_entry) gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), pattern); amitk_xif_selection_populate (filesel, (gchar*) pattern, TRUE, TRUE); } static void amitk_xif_selection_destroy (GtkObject *object) { AmitkXifSelection *filesel; GList *list; HistoryCallbackArg *callback_arg; g_return_if_fail (AMITK_IS_XIF_SELECTION (object)); filesel = AMITK_XIF_SELECTION (object); if (filesel->fileop_dialog) { gtk_widget_destroy (filesel->fileop_dialog); filesel->fileop_dialog = NULL; } if (filesel->history_list) { list = filesel->history_list; while (list) { callback_arg = list->data; g_free (callback_arg->directory); g_free (callback_arg); list = list->next; } g_list_free (filesel->history_list); filesel->history_list = NULL; } if (filesel->cmpl_state) { cmpl_free_state (filesel->cmpl_state); filesel->cmpl_state = NULL; } if (filesel->selected_names) { free_selected_names (filesel->selected_names); filesel->selected_names = NULL; } if (filesel->last_selected) { g_free (filesel->last_selected); filesel->last_selected = NULL; } GTK_OBJECT_CLASS (parent_class)->destroy (object); } static void amitk_xif_selection_map (GtkWidget *widget) { AmitkXifSelection *filesel = AMITK_XIF_SELECTION (widget); /* Refresh the contents */ amitk_xif_selection_populate (filesel, "", FALSE, FALSE); GTK_WIDGET_CLASS (parent_class)->map (widget); } static void amitk_xif_selection_finalize (GObject *object) { AmitkXifSelection *filesel = AMITK_XIF_SELECTION (object); g_free (filesel->fileop_file); G_OBJECT_CLASS (parent_class)->finalize (object); } /* Begin file operations callbacks */ static void amitk_xif_selection_fileop_error (AmitkXifSelection *fs, gchar *error_message) { GtkWidget *dialog; g_return_if_fail (error_message != NULL); /* main dialog */ dialog = gtk_message_dialog_new (GTK_WINDOW (fs), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", error_message); /* yes, we free it */ g_free (error_message); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); g_signal_connect_swapped (G_OBJECT (dialog), "response", G_CALLBACK(gtk_widget_destroy), dialog); gtk_widget_show (dialog); } static void amitk_xif_selection_fileop_destroy (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); fs->fileop_dialog = NULL; } static gboolean entry_is_empty (GtkEntry *entry) { const gchar *text = gtk_entry_get_text (entry); return *text == '\0'; } static void amitk_xif_selection_fileop_entry_changed (GtkEntry *entry, GtkWidget *button) { gtk_widget_set_sensitive (button, !entry_is_empty (entry)); } static void amitk_xif_selection_create_dir_confirmed (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; const gchar *dirname; gchar *path; gchar *full_path; gchar *sys_full_path; gchar *buf; GError *error = NULL; CompletionState *cmpl_state; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); dirname = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); cmpl_state = (CompletionState*) fs->cmpl_state; path = cmpl_reference_position (cmpl_state); full_path = g_strconcat (path, G_DIR_SEPARATOR_S, dirname, NULL); sys_full_path = g_filename_from_utf8 (full_path, -1, NULL, NULL, &error); if (error) { if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) buf = g_strdup_printf (_("The folder name \"%s\" contains symbols that are not allowed in filenames"), dirname); else buf = g_strdup_printf (_("Error creating folder \"%s\": %s\n%s"), dirname, error->message, _("You probably used symbols not allowed in filenames.")); amitk_xif_selection_fileop_error (fs, buf); g_error_free (error); goto out; } if (g_mkdir (sys_full_path, 0755) < 0) { buf = g_strdup_printf (_("Error creating folder \"%s\": %s\n"), dirname, g_strerror (errno)); amitk_xif_selection_fileop_error (fs, buf); } out: g_free (full_path); g_free (sys_full_path); gtk_widget_destroy (fs->fileop_dialog); amitk_xif_selection_populate (fs, "", FALSE, FALSE); } static void amitk_xif_selection_create_dir (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; GtkWidget *label; GtkWidget *dialog; GtkWidget *vbox; GtkWidget *button; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); if (fs->fileop_dialog) return; /* main dialog */ dialog = gtk_dialog_new (); fs->fileop_dialog = dialog; g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK(amitk_xif_selection_fileop_destroy), fs); gtk_window_set_title (GTK_WINDOW (dialog), _("New Folder")); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fs)); /* If file dialog is grabbed, grab option dialog */ /* When option dialog is closed, file dialog will be grabbed again */ if (GTK_WINDOW (fs)->modal) gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); vbox = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, FALSE, FALSE, 0); gtk_widget_show( vbox); label = gtk_label_new_with_mnemonic (_("_Folder name:")); gtk_misc_set_alignment(GTK_MISC (label), 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5); gtk_widget_show (label); /* The directory entry widget */ fs->fileop_entry = gtk_entry_new (); gtk_label_set_mnemonic_widget (GTK_LABEL (label), fs->fileop_entry); gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, TRUE, TRUE, 5); GTK_WIDGET_SET_FLAGS (fs->fileop_entry, GTK_CAN_DEFAULT); gtk_widget_show (fs->fileop_entry); /* buttons */ button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK(gtk_widget_destroy), dialog); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); gtk_widget_show (button); gtk_widget_grab_focus (fs->fileop_entry); button = gtk_button_new_with_mnemonic (_("C_reate")); gtk_widget_set_sensitive (button, FALSE); g_signal_connect (button, "clicked", G_CALLBACK (amitk_xif_selection_create_dir_confirmed), fs); g_signal_connect (fs->fileop_entry, "changed", G_CALLBACK (amitk_xif_selection_fileop_entry_changed), button); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_show (button); gtk_widget_show (dialog); } static void amitk_xif_selection_delete_file_response (GtkDialog *dialog, gint response_id, gpointer data) { AmitkXifSelection *fs = data; CompletionState *cmpl_state; gchar *path; gchar *full_path; gchar *sys_full_path; GError *error = NULL; gchar *buf; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); if (response_id != GTK_RESPONSE_OK) { gtk_widget_destroy (GTK_WIDGET (dialog)); return; } cmpl_state = (CompletionState*) fs->cmpl_state; path = cmpl_reference_position (cmpl_state); full_path = g_strconcat (path, G_DIR_SEPARATOR_S, fs->fileop_file, NULL); sys_full_path = g_filename_from_utf8 (full_path, -1, NULL, NULL, &error); if (error) { if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) buf = g_strdup_printf (_("The filename \"%s\" contains symbols that are not allowed in filenames"), fs->fileop_file); else buf = g_strdup_printf (_("Error deleting file \"%s\": %s\n%s"), fs->fileop_file, error->message, _("It probably contains symbols not allowed in filenames.")); amitk_xif_selection_fileop_error (fs, buf); g_error_free (error); goto out; } if (unlink (sys_full_path) < 0) { buf = g_strdup_printf (_("Error deleting file \"%s\": %s"), fs->fileop_file, g_strerror (errno)); amitk_xif_selection_fileop_error (fs, buf); } out: g_free (full_path); g_free (sys_full_path); gtk_widget_destroy (fs->fileop_dialog); amitk_xif_selection_populate (fs, "", FALSE, TRUE); } static void amitk_xif_selection_delete_file (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; GtkWidget *dialog; const gchar *filename; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); if (fs->fileop_dialog) return; #ifdef G_WITH_CYGWIN translate_win32_path (fs); #endif filename = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); if (strlen (filename) < 1) return; g_free (fs->fileop_file); fs->fileop_file = g_strdup (filename); /* main dialog */ fs->fileop_dialog = dialog = gtk_message_dialog_new (GTK_WINDOW (fs), GTK_WINDOW (fs)->modal ? GTK_DIALOG_MODAL : 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Really delete file \"%s\" ?"), filename); g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK(amitk_xif_selection_fileop_destroy), fs); gtk_window_set_title (GTK_WINDOW (dialog), _("Delete File")); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); /* buttons */ gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_DELETE, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (amitk_xif_selection_delete_file_response), fs); gtk_widget_show (dialog); } static void amitk_xif_selection_rename_file_confirmed (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; gchar *buf; const gchar *file; gchar *path; gchar *new_filename; gchar *old_filename; gchar *sys_new_filename; gchar *sys_old_filename; CompletionState *cmpl_state; GError *error = NULL; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); cmpl_state = (CompletionState*) fs->cmpl_state; path = cmpl_reference_position (cmpl_state); new_filename = g_strconcat (path, G_DIR_SEPARATOR_S, file, NULL); old_filename = g_strconcat (path, G_DIR_SEPARATOR_S, fs->fileop_file, NULL); sys_new_filename = g_filename_from_utf8 (new_filename, -1, NULL, NULL, &error); if (error) { if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) buf = g_strdup_printf (_("The file name \"%s\" contains symbols that are not allowed in filenames"), new_filename); else buf = g_strdup_printf (_("Error renaming file to \"%s\": %s\n%s"), new_filename, error->message, _("You probably used symbols not allowed in filenames.")); amitk_xif_selection_fileop_error (fs, buf); g_error_free (error); goto out1; } sys_old_filename = g_filename_from_utf8 (old_filename, -1, NULL, NULL, &error); if (error) { if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) buf = g_strdup_printf (_("The file name \"%s\" contains symbols that are not allowed in filenames"), old_filename); else buf = g_strdup_printf (_("Error renaming file \"%s\": %s\n%s"), old_filename, error->message, _("It probably contains symbols not allowed in filenames.")); amitk_xif_selection_fileop_error (fs, buf); g_error_free (error); goto out2; } if (rename (sys_old_filename, sys_new_filename) < 0) { buf = g_strdup_printf (_("Error renaming file \"%s\" to \"%s\": %s"), sys_old_filename, sys_new_filename, g_strerror (errno)); amitk_xif_selection_fileop_error (fs, buf); goto out2; } amitk_xif_selection_populate (fs, "", FALSE, FALSE); gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), file); out2: g_free (sys_old_filename); out1: g_free (new_filename); g_free (old_filename); g_free (sys_new_filename); gtk_widget_destroy (fs->fileop_dialog); } static void amitk_xif_selection_rename_file (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; GtkWidget *label; GtkWidget *dialog; GtkWidget *vbox; GtkWidget *button; gchar *buf; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); if (fs->fileop_dialog) return; g_free (fs->fileop_file); fs->fileop_file = g_strdup (gtk_entry_get_text (GTK_ENTRY (fs->selection_entry))); if (strlen (fs->fileop_file) < 1) return; /* main dialog */ fs->fileop_dialog = dialog = gtk_dialog_new (); g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK(amitk_xif_selection_fileop_destroy), fs); gtk_window_set_title (GTK_WINDOW (dialog), _("Rename File")); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (fs)); /* If file dialog is grabbed, grab option dialog */ /* When option dialog closed, file dialog will be grabbed again */ if (GTK_WINDOW (fs)->modal) gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); vbox = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, FALSE, FALSE, 0); gtk_widget_show(vbox); buf = g_strdup_printf (_("Rename file \"%s\" to:"), fs->fileop_file); label = gtk_label_new (buf); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5); gtk_widget_show (label); g_free (buf); /* New filename entry */ fs->fileop_entry = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, TRUE, TRUE, 5); GTK_WIDGET_SET_FLAGS (fs->fileop_entry, GTK_CAN_DEFAULT); gtk_widget_show (fs->fileop_entry); gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file); gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry), 0, strlen (fs->fileop_file)); /* buttons */ button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK(gtk_widget_destroy), dialog); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); gtk_widget_show (button); gtk_widget_grab_focus (fs->fileop_entry); button = gtk_button_new_with_mnemonic (_("_Rename")); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK(amitk_xif_selection_rename_file_confirmed), fs); g_signal_connect (fs->fileop_entry, "changed", G_CALLBACK (amitk_xif_selection_fileop_entry_changed), button); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), button, TRUE, TRUE, 0); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_show (button); gtk_widget_show (dialog); } static gint amitk_xif_selection_insert_text (GtkWidget *widget, const gchar *new_text, gint new_text_length, gint *position, gpointer user_data) { gchar *filename; filename = g_filename_from_utf8 (new_text, new_text_length, NULL, NULL, NULL); if (!filename) { // requires gtk+ > 2.2 gdk_display_beep (gtk_widget_get_display (widget)); g_signal_stop_emission_by_name (widget, "insert_text"); return FALSE; } g_free (filename); return TRUE; } static void amitk_xif_selection_update_fileops (AmitkXifSelection *fs) { gboolean sensitive; if (!fs->selection_entry) return; sensitive = !entry_is_empty (GTK_ENTRY (fs->selection_entry)); if (fs->fileop_del_file) gtk_widget_set_sensitive (fs->fileop_del_file, sensitive); if (fs->fileop_ren_file) gtk_widget_set_sensitive (fs->fileop_ren_file, sensitive); } static gint amitk_xif_selection_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { AmitkXifSelection *fs; char *text; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (event != NULL, FALSE); if ((event->keyval == GDK_Tab || event->keyval == GDK_KP_Tab) && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0) { fs = AMITK_XIF_SELECTION (user_data); #ifdef G_WITH_CYGWIN translate_win32_path (fs); #endif text = g_strdup (gtk_entry_get_text (GTK_ENTRY (fs->selection_entry))); amitk_xif_selection_populate (fs, text, TRUE, TRUE); g_free (text); return TRUE; } return FALSE; } static void amitk_xif_selection_history_callback (GtkWidget *widget, gpointer data) { AmitkXifSelection *fs = data; HistoryCallbackArg *callback_arg; GList *list; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); list = fs->history_list; while (list) { callback_arg = list->data; if (callback_arg->menu_item == widget) { amitk_xif_selection_populate (fs, callback_arg->directory, FALSE, FALSE); break; } list = list->next; } } static void amitk_xif_selection_update_history_menu (AmitkXifSelection *fs, gchar *current_directory) { HistoryCallbackArg *callback_arg; GtkWidget *menu_item; GList *list; gchar *current_dir; gint dir_len; gint i; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); g_return_if_fail (current_directory != NULL); list = fs->history_list; if (fs->history_menu) { while (list) { callback_arg = list->data; g_free (callback_arg->directory); g_free (callback_arg); list = list->next; } g_list_free (fs->history_list); fs->history_list = NULL; gtk_widget_destroy (fs->history_menu); } fs->history_menu = gtk_menu_new (); current_dir = g_strdup (current_directory); dir_len = strlen (current_dir); for (i = dir_len; i >= 0; i--) { /* the i == dir_len is to catch the full path for the first * entry. */ if ( (current_dir[i] == G_DIR_SEPARATOR) || (i == dir_len)) { /* another small hack to catch the full path */ if (i != dir_len) current_dir[i + 1] = '\0'; #ifdef G_WITH_CYGWIN if (!strcmp (current_dir, "//")) continue; #endif menu_item = gtk_menu_item_new_with_label (current_dir); callback_arg = g_new (HistoryCallbackArg, 1); callback_arg->menu_item = menu_item; /* since the autocompletion gets confused if you don't * supply a trailing '/' on a dir entry, set the full * (current) path to "" which just refreshes the filesel */ if (dir_len == i) { callback_arg->directory = g_strdup (""); } else { callback_arg->directory = g_strdup (current_dir); } fs->history_list = g_list_append (fs->history_list, callback_arg); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK( amitk_xif_selection_history_callback), (gpointer) fs); gtk_menu_shell_append (GTK_MENU_SHELL (fs->history_menu), menu_item); gtk_widget_show (menu_item); } } gtk_option_menu_set_menu (GTK_OPTION_MENU (fs->history_pulldown), fs->history_menu); g_free (current_dir); } static gchar * get_real_filename (gchar *filename, gboolean free_old) { #ifdef G_WITH_CYGWIN /* Check to see if the selection was a drive selector */ if (isalpha (filename[0]) && (filename[1] == ':')) { gchar temp_filename[MAX_PATH]; int len; cygwin_conv_to_posix_path (filename, temp_filename); /* we need trailing '/'. */ len = strlen (temp_filename); if (len > 0 && temp_filename[len-1] != '/') { temp_filename[len] = '/'; temp_filename[len+1] = '\0'; } if (free_old) g_free (filename); return g_strdup (temp_filename); } #endif /* G_WITH_CYGWIN */ return filename; } static void amitk_xif_selection_file_activate (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { AmitkXifSelection *fs = AMITK_XIF_SELECTION (user_data); GtkTreeModel *model = gtk_tree_view_get_model (tree_view); GtkTreeIter iter; gchar *filename; gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, FILE_COLUMN, &filename, -1); filename = get_real_filename (filename, TRUE); gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); gtk_button_clicked (GTK_BUTTON (fs->ok_button)); g_free (filename); } static void amitk_xif_selection_dir_activate (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) { AmitkXifSelection *fs = AMITK_XIF_SELECTION (user_data); GtkTreeModel *model = gtk_tree_view_get_model (tree_view); GtkTreeIter iter; gchar *filename; gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, DIR_COLUMN, &filename, -1); filename = get_real_filename (filename, TRUE); amitk_xif_selection_populate (fs, filename, FALSE, FALSE); g_free (filename); } #ifdef G_PLATFORM_WIN32 static void win32_gtk_add_drives_to_dir_list (GtkListStore *model) { gchar *textPtr; gchar buffer[128]; char formatBuffer[128]; GtkTreeIter iter; /* Get the drives string */ GetLogicalDriveStrings (sizeof (buffer), buffer); /* Add the drives as necessary */ textPtr = buffer; while (*textPtr != '\0') { /* Ignore floppies (?) */ if ((tolower (textPtr[0]) != 'a') && (tolower (textPtr[0]) != 'b')) { /* Build the actual displayable string */ g_snprintf (formatBuffer, sizeof (formatBuffer), "%c:\\", toupper (textPtr[0])); /* Add to the list */ gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, DIR_COLUMN, formatBuffer, -1); } textPtr += (strlen (textPtr) + 1); } } #endif static gchar * escape_underscores (const gchar *str) { GString *result = g_string_new (NULL); while (*str) { if (*str == '_') g_string_append_c (result, '_'); g_string_append_c (result, *str); str++; } return g_string_free (result, FALSE); } static void amitk_xif_selection_populate (AmitkXifSelection *fs, gchar *rel_path, gboolean try_complete, gboolean reset_entry) { CompletionState *cmpl_state; PossibleCompletion* poss; GtkTreeIter iter; GtkListStore *dir_model; GtkListStore *file_model; gchar* filename; const gchar* fullname; gchar* rem_path = rel_path; gchar* sel_text; gint did_recurse = FALSE; gint possible_count = 0; gint selection_index = -1; g_return_if_fail (AMITK_IS_XIF_SELECTION (fs)); cmpl_state = (CompletionState*) fs->cmpl_state; poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state); if (!cmpl_state_okay (cmpl_state)) { /* Something went wrong. */ amitk_xif_selection_abort (fs); return; } g_assert (cmpl_state->reference_dir); dir_model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fs->dir_list))); file_model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fs->file_list))); gtk_list_store_clear (dir_model); gtk_list_store_clear (file_model); /* Set the dir list to include ./ and ../ */ gtk_list_store_append (dir_model, &iter); gtk_list_store_set (dir_model, &iter, DIR_COLUMN, "." G_DIR_SEPARATOR_S, -1); gtk_list_store_append (dir_model, &iter); gtk_list_store_set (dir_model, &iter, DIR_COLUMN, ".." G_DIR_SEPARATOR_S, -1); while (poss) { if (cmpl_is_a_completion (poss)) { possible_count += 1; filename = cmpl_this_completion (poss); fullname = cmpl_completion_fullname(filename, cmpl_state); if (strcmp (filename, "." G_DIR_SEPARATOR_S) != 0 && strcmp (filename, ".." G_DIR_SEPARATOR_S) != 0) { if ( amitk_is_xif_flat_file(fullname, NULL, NULL) || amitk_is_xif_directory(fullname, NULL, NULL)) { gchar *xifname; gint length; /* remove any trailing directory characters */ length = strlen(filename); if ((length >= 1) && (strcmp(filename+length-1, G_DIR_SEPARATOR_S) == 0)) length--; xifname = g_strndup(filename, length); gtk_list_store_append (file_model, &iter); gtk_list_store_set (file_model, &iter, DIR_COLUMN, xifname, -1); g_free(xifname); } else if (cmpl_is_directory (poss)) { gtk_list_store_append (dir_model, &iter); gtk_list_store_set (dir_model, &iter, DIR_COLUMN, filename, -1); } } } poss = cmpl_next_completion (cmpl_state); } #ifdef G_PLATFORM_WIN32 /* For Windows, add drives as potential selections */ win32_gtk_add_drives_to_dir_list (dir_model); #endif /* File lists are set. */ g_assert (cmpl_state->reference_dir); if (try_complete) { /* User is trying to complete filenames, so advance the user's input * string to the updated_text, which is the common leading substring * of all possible completions, and if its a directory attempt * attempt completions in it. */ if (cmpl_updated_text (cmpl_state)[0]) { if (cmpl_updated_dir (cmpl_state)) { gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state)); did_recurse = TRUE; amitk_xif_selection_populate (fs, dir_name, TRUE, TRUE); g_free (dir_name); } else { if (fs->selection_entry) gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), cmpl_updated_text (cmpl_state)); } } else { selection_index = cmpl_last_valid_char (cmpl_state) - (strlen (rel_path) - strlen (rem_path)); if (fs->selection_entry) gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path); } } else if (reset_entry) { if (fs->selection_entry) gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), ""); } if (!did_recurse) { if (fs->selection_entry) gtk_editable_set_position (GTK_EDITABLE (fs->selection_entry), selection_index); if (fs->selection_entry) { char *escaped = escape_underscores (cmpl_reference_position (cmpl_state)); sel_text = g_strconcat (_("_Selection: "), escaped, NULL); g_free (escaped); gtk_label_set_text_with_mnemonic (GTK_LABEL (fs->selection_text), sel_text); g_free (sel_text); } if (fs->history_pulldown) { amitk_xif_selection_update_history_menu (fs, cmpl_reference_position (cmpl_state)); } } } static void amitk_xif_selection_abort (AmitkXifSelection *fs) { gchar err_buf[256]; g_snprintf (err_buf, sizeof (err_buf), _("Folder unreadable: %s"), cmpl_strerror (cmpl_errno)); /* BEEP gdk_beep(); */ if (fs->selection_entry) gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf); } /** * amitk_xif_selection_set_select_multiple: * @filesel: a #AmitkXifSelection * @select_multiple: whether or not the user is allowed to select multiple * files in the file list. * * Sets whether the user is allowed to select multiple files in the file list. * Use amitk_xif_selection_get_selections () to get the list of selected files. **/ void amitk_xif_selection_set_select_multiple (AmitkXifSelection *filesel, gboolean select_multiple) { GtkTreeSelection *sel; GtkSelectionMode mode; g_return_if_fail (AMITK_IS_XIF_SELECTION (filesel)); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list)); mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE; if (mode != gtk_tree_selection_get_mode (sel)) { gtk_tree_selection_set_mode (sel, mode); g_object_notify (G_OBJECT (filesel), "select-multiple"); } } /** * amitk_xif_selection_get_select_multiple: * @filesel: a #AmitkXifSelection * * Determines whether or not the user is allowed to select multiple files in * the file list. See amitk_xif_selection_set_select_multiple(). * * Return value: %TRUE if the user is allowed to select multiple files in the * file list **/ gboolean amitk_xif_selection_get_select_multiple (AmitkXifSelection *filesel) { GtkTreeSelection *sel; g_return_val_if_fail (AMITK_IS_XIF_SELECTION (filesel), FALSE); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list)); return (gtk_tree_selection_get_mode (sel) == GTK_SELECTION_MULTIPLE); } static void multiple_changed_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GPtrArray *names = data; gchar *filename; gtk_tree_model_get (model, iter, FILE_COLUMN, &filename, -1); g_ptr_array_add (names, filename); } static void free_selected_names (GPtrArray *names) { gint i; for (i = 0; i < names->len; i++) g_free (g_ptr_array_index (names, i)); g_ptr_array_free (names, TRUE); } static void amitk_xif_selection_file_changed (GtkTreeSelection *selection, gpointer user_data) { AmitkXifSelection *fs = AMITK_XIF_SELECTION (user_data); GPtrArray *new_names; gchar *filename; const gchar *entry; gint index = -1; new_names = g_ptr_array_sized_new (8); gtk_tree_selection_selected_foreach (selection, multiple_changed_foreach, new_names); /* nothing selected */ if (new_names->len == 0) { g_ptr_array_free (new_names, TRUE); if (fs->selected_names != NULL) { free_selected_names (fs->selected_names); fs->selected_names = NULL; } goto maybe_clear_entry; } if (new_names->len != 1) { GPtrArray *old_names = fs->selected_names; if (old_names != NULL) { /* A common case is selecting a range of files from top to bottom, * so quickly check for that to avoid looping over the entire list */ if (compare_utf8_filenames (g_ptr_array_index (old_names, old_names->len - 1), g_ptr_array_index (new_names, new_names->len - 1)) != 0) index = new_names->len - 1; else { gint i = 0, j = 0, cmp; /* do a quick diff, stopping at the first file not in the * old list */ while (i < old_names->len && j < new_names->len) { cmp = compare_utf8_filenames (g_ptr_array_index (old_names, i), g_ptr_array_index (new_names, j)); if (cmp < 0) { i++; } else if (cmp == 0) { i++; j++; } else if (cmp > 0) { index = j; break; } } /* we ran off the end of the old list */ if (index == -1 && i < new_names->len) index = j; } } else { /* A phantom anchor still exists at the point where the last item * was selected, which is used for subsequent range selections. * So search up from there. */ if (fs->last_selected && compare_utf8_filenames (fs->last_selected, g_ptr_array_index (new_names, 0)) == 0) index = new_names->len - 1; else index = 0; } } else index = 0; if (fs->selected_names != NULL) free_selected_names (fs->selected_names); fs->selected_names = new_names; if (index != -1) { if (fs->last_selected != NULL) g_free (fs->last_selected); fs->last_selected = g_strdup (g_ptr_array_index (new_names, index)); filename = get_real_filename (fs->last_selected, FALSE); gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); if (filename != fs->last_selected) g_free (filename); return; } maybe_clear_entry: entry = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); if ((entry != NULL) && (fs->last_selected != NULL) && (compare_utf8_filenames (entry, fs->last_selected) == 0)) gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), ""); } /** * amitk_xif_selection_get_selections: * @filesel: a #AmitkXifSelection * * Retrieves the list of file selections the user has made in the dialog box. * This function is intended for use when the user can select multiple files * in the file list. The first file in the list is equivalent to what * amitk_xif_selection_get_filename() would return. * * The filenames are in the encoding of g_filename_from_utf8(), which may or * may not be the same as that used by GTK+ (UTF-8). To convert to UTF-8, call * The filenames are in the encoding of g_filename_from_utf8, which may or may * not be the same as that used by GTK+ (UTF-8). To convert to UTF-8, call * g_filename_to_utf8() on each string. * * Return value: a newly-allocated %NULL-terminated array of strings. Use * g_strfreev() to free it. **/ gchar ** amitk_xif_selection_get_selections (AmitkXifSelection *filesel) { GPtrArray *names; gchar **selections; gchar *filename, *dirname; gchar *current, *buf; gint i, count; gboolean unselected_entry; g_return_val_if_fail (AMITK_IS_XIF_SELECTION (filesel), NULL); filename = g_strdup (amitk_xif_selection_get_filename (filesel)); if (strlen (filename) == 0) { g_free (filename); return NULL; } names = filesel->selected_names; if (names != NULL) selections = g_new (gchar *, names->len + 2); else selections = g_new (gchar *, 2); count = 0; unselected_entry = TRUE; if (names != NULL) { dirname = g_path_get_dirname (filename); for (i = 0; i < names->len; i++) { buf = g_filename_from_utf8 (g_ptr_array_index (names, i), -1, NULL, NULL, NULL); current = g_build_filename (dirname, buf, NULL); g_free (buf); selections[count++] = current; if (unselected_entry && compare_sys_filenames (current, filename) == 0) unselected_entry = FALSE; } g_free (dirname); } if (unselected_entry) selections[count++] = filename; else g_free (filename); selections[count] = NULL; return selections; } /**********************************************************************/ /* External Interface */ /**********************************************************************/ /* The four completion state selectors */ static gchar* cmpl_updated_text (CompletionState *cmpl_state) { return cmpl_state->updated_text; } static gboolean cmpl_updated_dir (CompletionState *cmpl_state) { return cmpl_state->re_complete; } static gchar* cmpl_reference_position (CompletionState *cmpl_state) { return cmpl_state->reference_dir->fullname; } static gint cmpl_last_valid_char (CompletionState *cmpl_state) { return cmpl_state->last_valid_char; } static const gchar* cmpl_completion_fullname (const gchar *text, CompletionState *cmpl_state) { static const char nothing[2] = ""; if (!cmpl_state_okay (cmpl_state)) { return nothing; } else if (g_path_is_absolute (text)) { strcpy (cmpl_state->updated_text, text); } #ifdef HAVE_PWD_H else if (text[0] == '~') { CompletionDir* dir; char* slash; dir = open_user_dir (text, cmpl_state); if (!dir) { /* spencer says just return ~something, so * for now just do it. */ strcpy (cmpl_state->updated_text, text); } else { strcpy (cmpl_state->updated_text, dir->fullname); slash = strchr (text, G_DIR_SEPARATOR); if (slash) strcat (cmpl_state->updated_text, slash); } } #endif else { strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); if (cmpl_state->updated_text[strlen (cmpl_state->updated_text) - 1] != G_DIR_SEPARATOR) strcat (cmpl_state->updated_text, G_DIR_SEPARATOR_S); strcat (cmpl_state->updated_text, text); } return cmpl_state->updated_text; } /* The three completion selectors */ static gchar* cmpl_this_completion (PossibleCompletion* pc) { return pc->text; } static gboolean cmpl_is_directory (PossibleCompletion* pc) { return pc->is_directory; } static gint cmpl_is_a_completion (PossibleCompletion* pc) { return pc->is_a_completion; } /**********************************************************************/ /* Construction, deletion */ /**********************************************************************/ static CompletionState* cmpl_init_state (void) { gchar *sys_getcwd_buf; gchar *utf8_cwd; CompletionState *new_state; new_state = g_new (CompletionState, 1); /* g_get_current_dir() returns a string in the "system" charset */ sys_getcwd_buf = g_get_current_dir (); utf8_cwd = g_filename_to_utf8 (sys_getcwd_buf, -1, NULL, NULL, NULL); g_free (sys_getcwd_buf); tryagain: new_state->reference_dir = NULL; new_state->completion_dir = NULL; new_state->active_completion_dir = NULL; new_state->directory_storage = NULL; new_state->directory_sent_storage = NULL; new_state->last_valid_char = 0; new_state->updated_text = g_new (gchar, MAXPATHLEN); new_state->updated_text_alloc = MAXPATHLEN; new_state->the_completion.text = g_new (gchar, MAXPATHLEN); new_state->the_completion.text_alloc = MAXPATHLEN; new_state->user_dir_name_buffer = NULL; new_state->user_directories = NULL; new_state->reference_dir = open_dir (utf8_cwd, new_state); if (!new_state->reference_dir) { /* Directories changing from underneath us, grumble */ strcpy (utf8_cwd, G_DIR_SEPARATOR_S); goto tryagain; } g_free (utf8_cwd); return new_state; } static void cmpl_free_dir_list (GList* dp0) { GList *dp = dp0; while (dp) { free_dir (dp->data); dp = dp->next; } g_list_free (dp0); } static void cmpl_free_dir_sent_list (GList* dp0) { GList *dp = dp0; while (dp) { free_dir_sent (dp->data); dp = dp->next; } g_list_free (dp0); } static void cmpl_free_state (CompletionState* cmpl_state) { g_return_if_fail (cmpl_state != NULL); cmpl_free_dir_list (cmpl_state->directory_storage); cmpl_free_dir_sent_list (cmpl_state->directory_sent_storage); if (cmpl_state->user_dir_name_buffer) g_free (cmpl_state->user_dir_name_buffer); if (cmpl_state->user_directories) g_free (cmpl_state->user_directories); if (cmpl_state->the_completion.text) g_free (cmpl_state->the_completion.text); if (cmpl_state->updated_text) g_free (cmpl_state->updated_text); g_free (cmpl_state); } static void free_dir (CompletionDir* dir) { g_free (dir->cmpl_text); g_free (dir->fullname); g_free (dir); } static void free_dir_sent (CompletionDirSent* sent) { gint i; for (i = 0; i < sent->entry_count; i++) { g_free (sent->entries[i].entry_name); g_free (sent->entries[i].sort_key); } g_free (sent->entries); g_free (sent); } static void prune_memory_usage (CompletionState *cmpl_state) { GList* cdsl = cmpl_state->directory_sent_storage; GList* cdl = cmpl_state->directory_storage; GList* cdl0 = cdl; gint len = 0; for (; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1) cdsl = cdsl->next; if (cdsl) { cmpl_free_dir_sent_list (cdsl->next); cdsl->next = NULL; } cmpl_state->directory_storage = NULL; while (cdl) { if (cdl->data == cmpl_state->reference_dir) cmpl_state->directory_storage = g_list_prepend (NULL, cdl->data); else free_dir (cdl->data); cdl = cdl->next; } g_list_free (cdl0); } /**********************************************************************/ /* The main entrances. */ /**********************************************************************/ static PossibleCompletion* cmpl_completion_matches (gchar *text_to_complete, gchar **remaining_text, CompletionState *cmpl_state) { #ifdef HAVE_PWD_H gchar* first_slash; #endif PossibleCompletion *poss; prune_memory_usage (cmpl_state); g_assert (text_to_complete != NULL); cmpl_state->user_completion_index = -1; cmpl_state->last_completion_text = text_to_complete; cmpl_state->the_completion.text[0] = 0; cmpl_state->last_valid_char = 0; cmpl_state->updated_text_len = -1; cmpl_state->updated_text[0] = 0; cmpl_state->re_complete = FALSE; #ifdef HAVE_PWD_H first_slash = strchr (text_to_complete, G_DIR_SEPARATOR); if (text_to_complete[0] == '~' && !first_slash) { /* Text starts with ~ and there is no slash, show all the * home directory completions. */ poss = attempt_homedir_completion (text_to_complete, cmpl_state); update_cmpl (poss, cmpl_state); return poss; } #endif cmpl_state->reference_dir = open_ref_dir (text_to_complete, remaining_text, cmpl_state); if (!cmpl_state->reference_dir) return NULL; cmpl_state->completion_dir = find_completion_dir (*remaining_text, remaining_text, cmpl_state); cmpl_state->last_valid_char = *remaining_text - text_to_complete; if (!cmpl_state->completion_dir) return NULL; cmpl_state->completion_dir->cmpl_index = -1; cmpl_state->completion_dir->cmpl_parent = NULL; cmpl_state->completion_dir->cmpl_text = g_strdup (*remaining_text); cmpl_state->active_completion_dir = cmpl_state->completion_dir; cmpl_state->reference_dir = cmpl_state->completion_dir; poss = attempt_file_completion (cmpl_state); update_cmpl (poss, cmpl_state); return poss; } static PossibleCompletion* cmpl_next_completion (CompletionState* cmpl_state) { PossibleCompletion* poss = NULL; cmpl_state->the_completion.text[0] = 0; #ifdef HAVE_PWD_H if (cmpl_state->user_completion_index >= 0) poss = attempt_homedir_completion (cmpl_state->last_completion_text, cmpl_state); else poss = attempt_file_completion (cmpl_state); #else poss = attempt_file_completion (cmpl_state); #endif update_cmpl (poss, cmpl_state); return poss; } /**********************************************************************/ /* Directory Operations */ /**********************************************************************/ /* Open the directory where completion will begin from, if possible. */ static CompletionDir* open_ref_dir (gchar *text_to_complete, gchar **remaining_text, CompletionState *cmpl_state) { gchar* first_slash; CompletionDir *new_dir; first_slash = strchr (text_to_complete, G_DIR_SEPARATOR); #ifdef G_WITH_CYGWIN if (text_to_complete[0] == '/' && text_to_complete[1] == '/') { char root_dir[5]; g_snprintf (root_dir, sizeof (root_dir), "//%c", text_to_complete[2]); new_dir = open_dir (root_dir, cmpl_state); if (new_dir) { *remaining_text = text_to_complete + 4; } } #else if (FALSE) ; #endif #ifdef HAVE_PWD_H else if (text_to_complete[0] == '~') { new_dir = open_user_dir (text_to_complete, cmpl_state); if (new_dir) { if (first_slash) *remaining_text = first_slash + 1; else *remaining_text = text_to_complete + strlen (text_to_complete); } else { return NULL; } } #endif else if (g_path_is_absolute (text_to_complete) || !cmpl_state->reference_dir) { gchar *tmp = g_strdup (text_to_complete); gchar *p; p = tmp; while (*p && *p != '*' && *p != '?') p++; *p = '\0'; p = strrchr (tmp, G_DIR_SEPARATOR); if (p) { if (p + 1 == g_path_skip_root (tmp)) p++; *p = '\0'; new_dir = open_dir (tmp, cmpl_state); if (new_dir) *remaining_text = text_to_complete + ((p == g_path_skip_root (tmp)) ? (p - tmp) : (p + 1 - tmp)); } else { /* If no possible candidates, use the cwd */ gchar *sys_curdir = g_get_current_dir (); gchar *utf8_curdir = g_filename_to_utf8 (sys_curdir, -1, NULL, NULL, NULL); g_free (sys_curdir); new_dir = open_dir (utf8_curdir, cmpl_state); if (new_dir) *remaining_text = text_to_complete; g_free (utf8_curdir); } g_free (tmp); } else { *remaining_text = text_to_complete; new_dir = open_dir (cmpl_state->reference_dir->fullname, cmpl_state); } if (new_dir) { new_dir->cmpl_index = -1; new_dir->cmpl_parent = NULL; } return new_dir; } #ifdef HAVE_PWD_H /* open a directory by user name */ static CompletionDir* open_user_dir (const gchar *text_to_complete, CompletionState *cmpl_state) { CompletionDir *result; gchar *first_slash; gint cmp_len; g_assert (text_to_complete && text_to_complete[0] == '~'); first_slash = strchr (text_to_complete, G_DIR_SEPARATOR); if (first_slash) cmp_len = first_slash - text_to_complete - 1; else cmp_len = strlen (text_to_complete + 1); if (!cmp_len) { /* ~/ */ const gchar *homedir = g_get_home_dir (); gchar *utf8_homedir = g_filename_to_utf8 (homedir, -1, NULL, NULL, NULL); if (utf8_homedir) result = open_dir (utf8_homedir, cmpl_state); else result = NULL; g_free (utf8_homedir); } else { /* ~user/ */ gchar* copy = g_new (char, cmp_len + 1); gchar *utf8_dir; struct passwd *pwd; strncpy (copy, text_to_complete + 1, cmp_len); copy[cmp_len] = 0; pwd = getpwnam (copy); g_free (copy); if (!pwd) { cmpl_errno = errno; return NULL; } utf8_dir = g_filename_to_utf8 (pwd->pw_dir, -1, NULL, NULL, NULL); result = open_dir (utf8_dir, cmpl_state); g_free (utf8_dir); } return result; } #endif /* open a directory relative the the current relative directory */ static CompletionDir* open_relative_dir (gchar *dir_name, CompletionDir *dir, CompletionState *cmpl_state) { CompletionDir *result; GString *path; path = g_string_sized_new (dir->fullname_len + strlen (dir_name) + 10); g_string_assign (path, dir->fullname); if (dir->fullname_len > 1 && path->str[dir->fullname_len - 1] != G_DIR_SEPARATOR) g_string_append_c (path, G_DIR_SEPARATOR); g_string_append (path, dir_name); result = open_dir (path->str, cmpl_state); g_string_free (path, TRUE); return result; } /* after the cache lookup fails, really open a new directory */ static CompletionDirSent* open_new_dir (gchar *dir_name, struct stat *sbuf, gboolean stat_subdirs) { CompletionDirSent *sent; GDir *directory; const char *dirent; GError *error = NULL; gint entry_count = 0; gint n_entries = 0; gint i; struct stat ent_sbuf; GString *path; gchar *sys_dir_name; sent = g_new (CompletionDirSent, 1); #ifndef G_PLATFORM_WIN32 sent->mtime = sbuf->st_mtime; sent->inode = sbuf->st_ino; sent->device = sbuf->st_dev; #endif path = g_string_sized_new (2*MAXPATHLEN + 10); sys_dir_name = g_filename_from_utf8 (dir_name, -1, NULL, NULL, NULL); if (!sys_dir_name) { cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT; return NULL; } directory = g_dir_open (sys_dir_name, 0, &error); if (!directory) { cmpl_errno = error->code; /* ??? */ g_free (sys_dir_name); return NULL; } while ((dirent = g_dir_read_name (directory)) != NULL) entry_count++; entry_count += 2; /* For ".",".." */ sent->entries = g_new (CompletionDirEntry, entry_count); sent->entry_count = entry_count; g_dir_rewind (directory); for (i = 0; i < entry_count; i += 1) { GError *error = NULL; if (i == 0) dirent = "."; else if (i == 1) dirent = ".."; else { dirent = g_dir_read_name (directory); if (!dirent) /* Directory changed */ break; } sent->entries[n_entries].entry_name = g_filename_to_utf8 (dirent, -1, NULL, NULL, &error); if (sent->entries[n_entries].entry_name == NULL || !g_utf8_validate (sent->entries[n_entries].entry_name, -1, NULL)) { gchar *escaped_str = g_strescape (dirent, NULL); g_message (_("The filename \"%s\" couldn't be converted to UTF-8 " "(try setting the environment variable G_BROKEN_FILENAMES): %s"), escaped_str, error->message ? error->message : _("Invalid Utf-8")); g_free (escaped_str); g_clear_error (&error); continue; } g_clear_error (&error); sent->entries[n_entries].sort_key = g_utf8_collate_key (sent->entries[n_entries].entry_name, -1); g_string_assign (path, sys_dir_name); if (path->str[path->len-1] != G_DIR_SEPARATOR) { g_string_append_c (path, G_DIR_SEPARATOR); } g_string_append (path, dirent); if (stat_subdirs) { /* Here we know path->str is a "system charset" string */ if (stat (path->str, &ent_sbuf) >= 0 && S_ISDIR (ent_sbuf.st_mode)) sent->entries[n_entries].is_dir = TRUE; else /* stat may fail, and we don't mind, since it could be a * dangling symlink. */ sent->entries[n_entries].is_dir = FALSE; } else sent->entries[n_entries].is_dir = 1; n_entries++; } sent->entry_count = n_entries; g_free (sys_dir_name); g_string_free (path, TRUE); qsort (sent->entries, sent->entry_count, sizeof (CompletionDirEntry), compare_cmpl_dir); g_dir_close (directory); return sent; } #ifndef G_PLATFORM_WIN32 static gboolean check_dir (gchar *dir_name, struct stat *result, gboolean *stat_subdirs) { /* A list of directories that we know only contain other directories. * Trying to stat every file in these directories would be very * expensive. */ static struct { gchar *name; gboolean present; struct stat statbuf; } no_stat_dirs[] = { { "/afs", FALSE, { 0 } }, { "/net", FALSE, { 0 } } }; static const gint n_no_stat_dirs = G_N_ELEMENTS (no_stat_dirs); static gboolean initialized = FALSE; gchar *sys_dir_name; gint i; if (!initialized) { initialized = TRUE; for (i = 0; i < n_no_stat_dirs; i++) { if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0) no_stat_dirs[i].present = TRUE; } } sys_dir_name = g_filename_from_utf8 (dir_name, -1, NULL, NULL, NULL); if (!sys_dir_name) { cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT; return FALSE; } if (stat (sys_dir_name, result) < 0) { g_free (sys_dir_name); cmpl_errno = errno; return FALSE; } g_free (sys_dir_name); *stat_subdirs = TRUE; for (i = 0; i < n_no_stat_dirs; i++) { if (no_stat_dirs[i].present && (no_stat_dirs[i].statbuf.st_dev == result->st_dev) && (no_stat_dirs[i].statbuf.st_ino == result->st_ino)) { *stat_subdirs = FALSE; break; } } return TRUE; } #endif /* open a directory by absolute pathname */ static CompletionDir* open_dir (gchar *dir_name, CompletionState *cmpl_state) { #ifndef G_PLATFORM_WIN32 struct stat sbuf; gboolean stat_subdirs; GList* cdsl; #endif CompletionDirSent *sent; #ifndef G_PLATFORM_WIN32 if (!check_dir (dir_name, &sbuf, &stat_subdirs)) return NULL; cdsl = cmpl_state->directory_sent_storage; while (cdsl) { sent = cdsl->data; if (sent->inode == sbuf.st_ino && sent->mtime == sbuf.st_mtime && sent->device == sbuf.st_dev) return attach_dir (sent, dir_name, cmpl_state); cdsl = cdsl->next; } sent = open_new_dir (dir_name, &sbuf, stat_subdirs); #else sent = open_new_dir (dir_name, NULL, TRUE); #endif if (sent) { cmpl_state->directory_sent_storage = g_list_prepend (cmpl_state->directory_sent_storage, sent); return attach_dir (sent, dir_name, cmpl_state); } return NULL; } static CompletionDir* attach_dir (CompletionDirSent *sent, gchar *dir_name, CompletionState *cmpl_state) { CompletionDir* new_dir; new_dir = g_new (CompletionDir, 1); cmpl_state->directory_storage = g_list_prepend (cmpl_state->directory_storage, new_dir); new_dir->sent = sent; new_dir->fullname = g_strdup (dir_name); new_dir->fullname_len = strlen (dir_name); new_dir->cmpl_text = NULL; return new_dir; } static gint correct_dir_fullname (CompletionDir* cmpl_dir) { gint length = strlen (cmpl_dir->fullname); gchar *first_slash = strchr (cmpl_dir->fullname, G_DIR_SEPARATOR); gchar *sys_filename; struct stat sbuf; /* Does it end with /. (\.) ? */ if (length >= 2 && strcmp (cmpl_dir->fullname + length - 2, G_DIR_SEPARATOR_S ".") == 0) { /* Is it just the root directory (on a drive) ? */ if (cmpl_dir->fullname + length - 2 == first_slash) { cmpl_dir->fullname[length - 1] = 0; cmpl_dir->fullname_len = length - 1; return TRUE; } else { cmpl_dir->fullname[length - 2] = 0; } } /* Ends with /./ (\.\)? */ else if (length >= 3 && strcmp (cmpl_dir->fullname + length - 3, G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S) == 0) cmpl_dir->fullname[length - 2] = 0; /* Ends with /.. (\..) ? */ else if (length >= 3 && strcmp (cmpl_dir->fullname + length - 3, G_DIR_SEPARATOR_S "..") == 0) { /* Is it just /.. (X:\..)? */ if (cmpl_dir->fullname + length - 3 == first_slash) { cmpl_dir->fullname[length - 2] = 0; cmpl_dir->fullname_len = length - 2; return TRUE; } sys_filename = g_filename_from_utf8 (cmpl_dir->fullname, -1, NULL, NULL, NULL); if (!sys_filename) { cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT; return FALSE; } if (stat (sys_filename, &sbuf) < 0) { g_free (sys_filename); cmpl_errno = errno; return FALSE; } g_free (sys_filename); cmpl_dir->fullname[length - 3] = 0; if (!correct_parent (cmpl_dir, &sbuf)) return FALSE; } /* Ends with /../ (\..\)? */ else if (length >= 4 && strcmp (cmpl_dir->fullname + length - 4, G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S) == 0) { /* Is it just /../ (X:\..\)? */ if (cmpl_dir->fullname + length - 4 == first_slash) { cmpl_dir->fullname[length - 3] = 0; cmpl_dir->fullname_len = length - 3; return TRUE; } sys_filename = g_filename_from_utf8 (cmpl_dir->fullname, -1, NULL, NULL, NULL); if (!sys_filename) { cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT; return FALSE; } if (stat (sys_filename, &sbuf) < 0) { g_free (sys_filename); cmpl_errno = errno; return FALSE; } g_free (sys_filename); cmpl_dir->fullname[length - 4] = 0; if (!correct_parent (cmpl_dir, &sbuf)) return FALSE; } cmpl_dir->fullname_len = strlen (cmpl_dir->fullname); return TRUE; } static gint correct_parent (CompletionDir *cmpl_dir, struct stat *sbuf) { struct stat parbuf; gchar *last_slash; gchar *first_slash; #ifndef G_PLATFORM_WIN32 gchar *new_name; #endif gchar *sys_filename; gchar c = 0; last_slash = strrchr (cmpl_dir->fullname, G_DIR_SEPARATOR); g_assert (last_slash); first_slash = strchr (cmpl_dir->fullname, G_DIR_SEPARATOR); /* Clever (?) way to check for top-level directory that works also on * Win32, where there is a drive letter and colon prefixed... */ if (last_slash != first_slash) { last_slash[0] = 0; } else { c = last_slash[1]; last_slash[1] = 0; } sys_filename = g_filename_from_utf8 (cmpl_dir->fullname, -1, NULL, NULL, NULL); if (!sys_filename) { cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT; if (!c) last_slash[0] = G_DIR_SEPARATOR; return FALSE; } if (stat (sys_filename, &parbuf) < 0) { g_free (sys_filename); cmpl_errno = errno; if (!c) last_slash[0] = G_DIR_SEPARATOR; return FALSE; } g_free (sys_filename); #ifndef G_PLATFORM_WIN32 /* No inode numbers on Win32 */ if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) /* it wasn't a link */ return TRUE; if (c) last_slash[1] = c; else last_slash[0] = G_DIR_SEPARATOR; /* it was a link, have to figure it out the hard way */ new_name = find_parent_dir_fullname (cmpl_dir->fullname); if (!new_name) return FALSE; g_free (cmpl_dir->fullname); cmpl_dir->fullname = new_name; #endif return TRUE; } #ifndef G_PLATFORM_WIN32 static gchar* find_parent_dir_fullname (gchar* dirname) { gchar *sys_orig_dir; gchar *result; gchar *sys_cwd; gchar *sys_dirname; sys_orig_dir = g_get_current_dir (); sys_dirname = g_filename_from_utf8 (dirname, -1, NULL, NULL, NULL); if (!sys_dirname) { g_free (sys_orig_dir); cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT; return NULL; } if (chdir (sys_dirname) != 0 || chdir ("..") != 0) { cmpl_errno = errno; chdir (sys_orig_dir); g_free (sys_dirname); g_free (sys_orig_dir); return NULL; } g_free (sys_dirname); sys_cwd = g_get_current_dir (); result = g_filename_to_utf8 (sys_cwd, -1, NULL, NULL, NULL); g_free (sys_cwd); if (chdir (sys_orig_dir) != 0) { cmpl_errno = errno; g_free (sys_orig_dir); return NULL; } g_free (sys_orig_dir); return result; } #endif /**********************************************************************/ /* Completion Operations */ /**********************************************************************/ #ifdef HAVE_PWD_H static PossibleCompletion* attempt_homedir_completion (gchar *text_to_complete, CompletionState *cmpl_state) { gint index, length; if (!cmpl_state->user_dir_name_buffer && !get_pwdb (cmpl_state)) return NULL; length = strlen (text_to_complete) - 1; cmpl_state->user_completion_index += 1; while (cmpl_state->user_completion_index < cmpl_state->user_directories_len) { index = first_diff_index (text_to_complete + 1, cmpl_state->user_directories [cmpl_state->user_completion_index].login); switch (index) { case PATTERN_MATCH: break; default: if (cmpl_state->last_valid_char < (index + 1)) cmpl_state->last_valid_char = index + 1; cmpl_state->user_completion_index += 1; continue; } cmpl_state->the_completion.is_a_completion = 1; cmpl_state->the_completion.is_directory = TRUE; append_completion_text ("~", cmpl_state); append_completion_text (cmpl_state-> user_directories[cmpl_state->user_completion_index].login, cmpl_state); return append_completion_text (G_DIR_SEPARATOR_S, cmpl_state); } if (text_to_complete[1] || cmpl_state->user_completion_index > cmpl_state->user_directories_len) { cmpl_state->user_completion_index = -1; return NULL; } else { cmpl_state->user_completion_index += 1; cmpl_state->the_completion.is_a_completion = 1; cmpl_state->the_completion.is_directory = TRUE; return append_completion_text ("~" G_DIR_SEPARATOR_S, cmpl_state); } } #endif #ifdef G_PLATFORM_WIN32 /* FIXME: determine whether we should casefold all Unicode letters * here, too (and in in first_diff_index() walk through the strings with * g_utf8_next_char()), or if this folding isn't actually needed at * all. */ #define FOLD(c) (tolower(c)) #else #define FOLD(c) (c) #endif /* returns the index (>= 0) of the first differing character, * PATTERN_MATCH if the completion matches */ static gint first_diff_index (gchar *pat, gchar *text) { gint diff = 0; while (*pat && *text && FOLD (*text) == FOLD (*pat)) { pat += 1; text += 1; diff += 1; } if (*pat) return diff; return PATTERN_MATCH; } static PossibleCompletion* append_completion_text (gchar *text, CompletionState *cmpl_state) { gint len, i = 1; if (!cmpl_state->the_completion.text) return NULL; len = strlen (text) + strlen (cmpl_state->the_completion.text) + 1; if (cmpl_state->the_completion.text_alloc > len) { strcat (cmpl_state->the_completion.text, text); return &cmpl_state->the_completion; } while (i < len) i <<= 1; cmpl_state->the_completion.text_alloc = i; cmpl_state->the_completion.text = (gchar*) g_realloc (cmpl_state->the_completion.text, i); if (!cmpl_state->the_completion.text) return NULL; else { strcat (cmpl_state->the_completion.text, text); return &cmpl_state->the_completion; } } static CompletionDir* find_completion_dir (gchar *text_to_complete, gchar **remaining_text, CompletionState *cmpl_state) { gchar* first_slash = strchr (text_to_complete, G_DIR_SEPARATOR); CompletionDir* dir = cmpl_state->reference_dir; CompletionDir* next; *remaining_text = text_to_complete; while (first_slash) { gint len = first_slash - *remaining_text; gint found = 0; gchar *found_name = NULL; /* Quiet gcc */ gint i; gchar* pat_buf = g_new (gchar, len + 1); strncpy (pat_buf, *remaining_text, len); pat_buf[len] = 0; for (i = 0; i < dir->sent->entry_count; i += 1) { if (dir->sent->entries[i].is_dir && _amitk_fnmatch (pat_buf, dir->sent->entries[i].entry_name)) { if (found) { g_free (pat_buf); return dir; } else { found = 1; found_name = dir->sent->entries[i].entry_name; } } } if (!found) { /* Perhaps we are trying to open an automount directory */ found_name = pat_buf; } next = open_relative_dir (found_name, dir, cmpl_state); if (!next) { g_free (pat_buf); return NULL; } next->cmpl_parent = dir; dir = next; if (!correct_dir_fullname (dir)) { g_free (pat_buf); return NULL; } *remaining_text = first_slash + 1; first_slash = strchr (*remaining_text, G_DIR_SEPARATOR); g_free (pat_buf); } return dir; } static void update_cmpl (PossibleCompletion *poss, CompletionState *cmpl_state) { gint cmpl_len; if (!poss || !cmpl_is_a_completion (poss)) return; cmpl_len = strlen (cmpl_this_completion (poss)); if (cmpl_state->updated_text_alloc < cmpl_len + 1) { cmpl_state->updated_text = (gchar*)g_realloc (cmpl_state->updated_text, cmpl_state->updated_text_alloc); cmpl_state->updated_text_alloc = 2*cmpl_len; } if (cmpl_state->updated_text_len < 0) { strcpy (cmpl_state->updated_text, cmpl_this_completion (poss)); cmpl_state->updated_text_len = cmpl_len; cmpl_state->re_complete = cmpl_is_directory (poss); } else if (cmpl_state->updated_text_len == 0) { cmpl_state->re_complete = FALSE; } else { gint first_diff = first_diff_index (cmpl_state->updated_text, cmpl_this_completion (poss)); cmpl_state->re_complete = FALSE; if (first_diff == PATTERN_MATCH) return; if (first_diff > cmpl_state->updated_text_len) strcpy (cmpl_state->updated_text, cmpl_this_completion (poss)); cmpl_state->updated_text_len = first_diff; cmpl_state->updated_text[first_diff] = 0; } } static PossibleCompletion* attempt_file_completion (CompletionState *cmpl_state) { gchar *pat_buf, *first_slash; CompletionDir *dir = cmpl_state->active_completion_dir; dir->cmpl_index += 1; if (dir->cmpl_index == dir->sent->entry_count) { if (dir->cmpl_parent == NULL) { cmpl_state->active_completion_dir = NULL; return NULL; } else { cmpl_state->active_completion_dir = dir->cmpl_parent; return attempt_file_completion (cmpl_state); } } g_assert (dir->cmpl_text); first_slash = strchr (dir->cmpl_text, G_DIR_SEPARATOR); if (first_slash) { gint len = first_slash - dir->cmpl_text; pat_buf = g_new (gchar, len + 1); strncpy (pat_buf, dir->cmpl_text, len); pat_buf[len] = 0; } else { gint len = strlen (dir->cmpl_text); pat_buf = g_new (gchar, len + 2); strcpy (pat_buf, dir->cmpl_text); /* Don't append a * if the user entered one herself. * This way one can complete *.h and don't get matches * on any .help files, for instance. */ if (strchr (pat_buf, '*') == NULL) strcpy (pat_buf + len, "*"); } if (first_slash) { if (dir->sent->entries[dir->cmpl_index].is_dir) { if (_amitk_fnmatch (pat_buf, dir->sent->entries[dir->cmpl_index].entry_name)) { CompletionDir* new_dir; new_dir = open_relative_dir (dir->sent->entries[dir->cmpl_index].entry_name, dir, cmpl_state); if (!new_dir) { g_free (pat_buf); return NULL; } new_dir->cmpl_parent = dir; new_dir->cmpl_index = -1; new_dir->cmpl_text = g_strdup (first_slash + 1); cmpl_state->active_completion_dir = new_dir; g_free (pat_buf); return attempt_file_completion (cmpl_state); } else { g_free (pat_buf); return attempt_file_completion (cmpl_state); } } else { g_free (pat_buf); return attempt_file_completion (cmpl_state); } } else { if (dir->cmpl_parent != NULL) { append_completion_text (dir->fullname + strlen (cmpl_state->completion_dir->fullname) + 1, cmpl_state); append_completion_text (G_DIR_SEPARATOR_S, cmpl_state); } append_completion_text (dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); cmpl_state->the_completion.is_a_completion = _amitk_fnmatch (pat_buf, dir->sent->entries[dir->cmpl_index].entry_name); cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; if (dir->sent->entries[dir->cmpl_index].is_dir) append_completion_text (G_DIR_SEPARATOR_S, cmpl_state); g_free (pat_buf); return &cmpl_state->the_completion; } } #ifdef HAVE_PWD_H static gint get_pwdb (CompletionState* cmpl_state) { struct passwd *pwd_ptr; gchar* buf_ptr; gchar *utf8; gint len = 0, i, count = 0; if (cmpl_state->user_dir_name_buffer) return TRUE; setpwent (); while ((pwd_ptr = getpwent ()) != NULL) { utf8 = g_filename_to_utf8 (pwd_ptr->pw_name, -1, NULL, NULL, NULL); len += strlen (utf8); g_free (utf8); utf8 = g_filename_to_utf8 (pwd_ptr->pw_dir, -1, NULL, NULL, NULL); len += strlen (utf8); g_free (utf8); len += 2; count += 1; } setpwent (); cmpl_state->user_dir_name_buffer = g_new (gchar, len); cmpl_state->user_directories = g_new (CompletionUserDir, count); cmpl_state->user_directories_len = count; buf_ptr = cmpl_state->user_dir_name_buffer; for (i = 0; i < count; i += 1) { pwd_ptr = getpwent (); if (!pwd_ptr) { cmpl_errno = errno; goto error; } utf8 = g_filename_to_utf8 (pwd_ptr->pw_name, -1, NULL, NULL, NULL); strcpy (buf_ptr, utf8); g_free (utf8); cmpl_state->user_directories[i].login = buf_ptr; buf_ptr += strlen (buf_ptr); buf_ptr += 1; utf8 = g_filename_to_utf8 (pwd_ptr->pw_dir, -1, NULL, NULL, NULL); strcpy (buf_ptr, utf8); g_free (utf8); cmpl_state->user_directories[i].homedir = buf_ptr; buf_ptr += strlen (buf_ptr); buf_ptr += 1; } qsort (cmpl_state->user_directories, cmpl_state->user_directories_len, sizeof (CompletionUserDir), compare_user_dir); endpwent (); return TRUE; error: if (cmpl_state->user_dir_name_buffer) g_free (cmpl_state->user_dir_name_buffer); if (cmpl_state->user_directories) g_free (cmpl_state->user_directories); cmpl_state->user_dir_name_buffer = NULL; cmpl_state->user_directories = NULL; return FALSE; } static gint compare_user_dir (const void *a, const void *b) { return strcmp ((((CompletionUserDir*)a))->login, (((CompletionUserDir*)b))->login); } #endif static gint compare_cmpl_dir (const void *a, const void *b) { return strcmp (((CompletionDirEntry*)a)->sort_key, (((CompletionDirEntry*)b))->sort_key); } static gint cmpl_state_okay (CompletionState* cmpl_state) { return cmpl_state && cmpl_state->reference_dir; } static const gchar* cmpl_strerror (gint err) { if (err == CMPL_ERRNO_TOO_LONG) return _("Name too long"); else if (err == CMPL_ERRNO_DID_NOT_CONVERT) return _("Couldn't convert filename"); else return g_strerror (err); } /* stolen from fnmatch.c from gtk */ /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ /* * Stripped down, converted to UTF-8 and test cases added * * Owen Taylor, 13 December 2002; */ /* We need to make sure that all constants are defined * to properly compile this file */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif static gunichar get_char (const char **str) { gunichar c = g_utf8_get_char (*str); *str = g_utf8_next_char (*str); #ifdef G_PLATFORM_WIN32 c = g_unichar_tolower (c); #endif return c; } #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) #define DO_ESCAPE 0 #else #define DO_ESCAPE 1 #endif static gunichar get_unescaped_char (const char **str, gboolean *was_escaped) { gunichar c = get_char (str); *was_escaped = DO_ESCAPE && c == '\\'; if (*was_escaped) c = get_char (str); return c; } /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ static gboolean amitk_fnmatch_intern (const char *pattern, const char *string, gboolean component_start) { const char *p = pattern, *n = string; while (*p) { const char *last_n = n; gunichar c = get_char (&p); gunichar nc = get_char (&n); switch (c) { case '?': if (nc == '\0') return FALSE; else if (nc == G_DIR_SEPARATOR) return FALSE; else if (nc == '.' && component_start) return FALSE; break; case '\\': if (DO_ESCAPE) c = get_char (&p); if (nc != c) return FALSE; break; case '*': if (nc == '.' && component_start) return FALSE; { const char *last_p = p; for (last_p = p, c = get_char (&p); c == '?' || c == '*'; last_p = p, c = get_char (&p)) { if (c == '?') { if (nc == '\0') return FALSE; else if (nc == G_DIR_SEPARATOR) return FALSE; else { last_n = n; nc = get_char (&n); } } } /* If the pattern ends with wildcards, we have a * guaranteed match unless there is a dir separator * in the remainder of the string. */ if (c == '\0') { if (strchr (last_n, G_DIR_SEPARATOR) != NULL) return FALSE; else return TRUE; } if (DO_ESCAPE && c == '\\') c = get_char (&p); for (p = last_p; nc != '\0';) { if ((c == '[' || nc == c) && amitk_fnmatch_intern (p, last_n, component_start)) return TRUE; component_start = (nc == G_DIR_SEPARATOR); last_n = n; nc = get_char (&n); } return FALSE; } case '[': { /* Nonzero if the sense of the character class is inverted. */ gboolean not; gboolean was_escaped; if (nc == '\0' || nc == G_DIR_SEPARATOR) return FALSE; if (nc == '.' && component_start) return FALSE; not = (*p == '!' || *p == '^'); if (not) ++p; c = get_unescaped_char (&p, &was_escaped); for (;;) { register gunichar cstart = c, cend = c; if (c == '\0') /* [ (unterminated) loses. */ return FALSE; c = get_unescaped_char (&p, &was_escaped); if (!was_escaped && c == '-' && *p != ']') { cend = get_unescaped_char (&p, &was_escaped); if (cend == '\0') return FALSE; c = get_char (&p); } if (nc >= cstart && nc <= cend) goto matched; if (!was_escaped && c == ']') break; } if (!not) return FALSE; break; matched:; /* Skip the rest of the [...] that already matched. */ /* XXX 1003.2d11 is unclear if was_escaped is right. */ while (was_escaped || c != ']') { if (c == '\0') /* [... (unterminated) loses. */ return FALSE; c = get_unescaped_char (&p, &was_escaped); } if (not) return FALSE; } break; default: if (c != nc) return FALSE; } component_start = (nc == G_DIR_SEPARATOR); } if (*n == '\0') return TRUE; return FALSE; } /* Match STRING against the filename pattern PATTERN, returning zero if * it matches, nonzero if not. * * GTK+ used to use a old version of GNU fnmatch() that was buggy * in various ways and didn't handle UTF-8. The following is * converted to UTF-8. To simplify the process of making it * correct, this is special-cased to the combinations of flags * that gtkfilesel.c uses. * * FNM_FILE_NAME - always set * FNM_LEADING_DIR - never set * FNM_PERIOD - always set * FNM_NOESCAPE - set only on windows * FNM_CASEFOLD - set only on windows */ static gboolean _amitk_fnmatch (const char *pattern, const char *string) { return amitk_fnmatch_intern (pattern, string, TRUE); } #if 0 /* the rest of this function runs the file selection dialog box */ file_chooser = gtk_file_chooser_dialog_new(_("Export to File"), GTK_WINDOW(main_dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, AMITK_RESPONSE_EXECUTE, /* intercept the save signal */ NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_dialog_set_default_response (GTK_DIALOG (file_chooser), AMITK_RESPONSE_EXECUTE); /* notes from failed attempt */ #ifdef AMIDE_LIBDCMDATA_SUPPORT gboolean check_if_dicom_dir(gchar * path) { gchar * test_path; gboolean result; test_path = g_strdup_printf("%s%s%s",path, G_DIR_SEPARATOR_S, "DICOMDIR"); result = dcmtk_test_dicom(test_path); g_print("dicom test %d\n", result); g_free(test_path); return result; } static void fc_response_cb(GObject * file_chooser, gint response_id, gpointer data) { gchar * current_folder; gboolean is_dicom_dir=FALSE; gchar * filename; g_print("response id %d\n", response_id); /* intercept the AMITK_RESPONSE_ACCEPT, and resend a GTK_RESPONSE_ACCEPT to get normal GtkFileChooserDialog functionality unless this a DCMTK directory */ if (response_id == AMITK_RESPONSE_EXECUTE) { g_signal_stop_emission_by_name (GTK_DIALOG(file_chooser), "response"); /* kill this emission */ /* see if we've got a folder containing a DICOMDIR file */ current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(file_chooser)); is_dicom_dir = check_if_dicom_dir(current_folder); #if 0 /* shove the DICOMDIR filename into the dialog box */ if (is_dicom_dir) { filename = g_strdup_printf("%s%s%s",current_folder, G_DIR_SEPARATOR_S, "DICOMDIR"); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser), filename); g_free(filename); } #endif if (current_folder != NULL) g_free(current_folder); /* and go down the usual pathway */ if (!is_dicom_dir) gtk_dialog_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT); } return; } static void fc_file_activated(GObject * file_chooser, gpointer data) { g_print("activated\n"); gtk_dialog_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT); return; } static gboolean avoid_first_signal=TRUE; /* when we change to a folder that has a DICOMDIR file in it, we just go ahead and send the AMITK_RESPONSE_EXECUTE response signal to the dialog */ static void fc_folder_changed(GObject * file_chooser, gpointer data) { gchar * current_folder; gboolean is_dicom_dir; /* this prevents automatically exporting the DICOM file if we've started in a DICOMDIR containing directory */ if (avoid_first_signal) { avoid_first_signal=FALSE; return; } g_print("folder change\n"); current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(file_chooser)); is_dicom_dir = check_if_dicom_dir(current_folder); if (current_folder != NULL) g_free(current_folder); if (is_dicom_dir) { g_signal_stop_emission_by_name(G_OBJECT(file_chooser), "current_folder_changed"); gtk_dialog_response(GTK_DIALOG(file_chooser), AMITK_RESPONSE_EXECUTE); } return; } #endif #ifdef AMIDE_LIBDCMDATA_SUPPORT /* for DCMTK dicom directories, we might be selecting a preexisting folder */ if (method == AMITK_EXPORT_METHOD_DCMTK) { g_signal_connect(file_chooser, "response", G_CALLBACK (fc_response_cb), NULL); /* this next one is needed as we're using AMITK_RESPONSE_EXECUTE for the save button */ g_signal_connect(GTK_FILE_CHOOSER(file_chooser), "file_activated", G_CALLBACK(fc_file_activated), NULL); /* and this next one monitors if we double click on a DICOMDIR containing folder */ g_signal_connect(GTK_FILE_CHOOSER(file_chooser), "current_folder_changed", G_CALLBACK(fc_folder_changed), NULL); } #endif #endif amide-1.0.6/amide-current/attic/amitk_xif_sel.h000066400000000000000000000104011423227705100214260ustar00rootroot00000000000000/* amitk_xif_sel.h - this is gtkfilesel, but slightly modified so that it lists .xif files in the file list, and compiles cleanly under AMIDE */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #ifndef __AMITK_XIF_SEL_H__ #define __AMITK_XIF_SEL_H__ #include G_BEGIN_DECLS #define AMITK_TYPE_XIF_SELECTION (amitk_xif_selection_get_type ()) #define AMITK_XIF_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_XIF_SELECTION, AmitkXifSelection)) #define AMITK_XIF_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_XIF_SELECTION, AmitkXifSelectionClass)) #define AMITK_IS_XIF_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_XIF_SELECTION)) #define AMITK_IS_XIF_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_XIF_SELECTION)) #define AMITK_XIF_SELECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), AMITK_TYPE_XIF_SELECTION, AmitkXifSelectionClass)) typedef struct _AmitkXifSelection AmitkXifSelection; typedef struct _AmitkXifSelectionClass AmitkXifSelectionClass; struct _AmitkXifSelection { /*< private >*/ GtkDialog parent_instance; /*< public >*/ GtkWidget *dir_list; GtkWidget *file_list; GtkWidget *selection_entry; GtkWidget *selection_text; GtkWidget *main_vbox; GtkWidget *ok_button; GtkWidget *cancel_button; GtkWidget *help_button; GtkWidget *history_pulldown; GtkWidget *history_menu; GList *history_list; GtkWidget *fileop_dialog; GtkWidget *fileop_entry; gchar *fileop_file; gpointer cmpl_state; GtkWidget *fileop_c_dir; GtkWidget *fileop_del_file; GtkWidget *fileop_ren_file; GtkWidget *button_area; GtkWidget *action_area; GPtrArray *selected_names; gchar *last_selected; }; struct _AmitkXifSelectionClass { GtkDialogClass parent_class; /* Padding for future expansion */ void (*_gtk_reserved1) (void); void (*_gtk_reserved2) (void); void (*_gtk_reserved3) (void); void (*_gtk_reserved4) (void); }; GType amitk_xif_selection_get_type (void) G_GNUC_CONST; GtkWidget* amitk_xif_selection_new (const gchar *title); void amitk_xif_selection_set_filename (AmitkXifSelection *filesel, const gchar *filename); /* This function returns the selected filename in the C runtime's * multibyte string encoding, which may or may not be the same as that * used by GDK (UTF-8). To convert to UTF-8, call g_filename_to_utf8(). * The returned string points to a statically allocated buffer and * should be copied away. */ G_CONST_RETURN gchar* amitk_xif_selection_get_filename (AmitkXifSelection *filesel); void amitk_xif_selection_complete (AmitkXifSelection *filesel, const gchar *pattern); void amitk_xif_selection_show_fileop_buttons (AmitkXifSelection *filesel); void amitk_xif_selection_hide_fileop_buttons (AmitkXifSelection *filesel); gchar** amitk_xif_selection_get_selections (AmitkXifSelection *filesel); void amitk_xif_selection_set_select_multiple (AmitkXifSelection *filesel, gboolean select_multiple); gboolean amitk_xif_selection_get_select_multiple (AmitkXifSelection *filesel); G_END_DECLS #endif /* __AMITK_XIF_SEL_H__ */ amide-1.0.6/amide-current/configure.ac000066400000000000000000000413711423227705100176330ustar00rootroot00000000000000gdnl =============================================================================== dnl Configure script for AMIDE dnl =============================================================================== AC_PREREQ(2.59) AC_INIT([amide],[1.0.6],[amide-users@lists.sourceforge.net]) AC_CONFIG_SRCDIR(src/amide.c) AC_CONFIG_HEADERS(amide_config.h) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE AM_MAINTAINER_MODE([enable]) AC_PROG_CC AC_PROG_CXX AC_PROG_LIBTOOL AC_CHECK_HEADERS(unistd.h, AC_DEFINE(HAVE_UNISTD_H)) AC_CHECK_SIZEOF(long,8) AC_CHECK_SIZEOF(long long,8) AC_CHECK_FUNCS(strptime) dnl ================= translation ======================================= AM_GLIB_GNU_GETTEXT GETTEXT_PACKAGE=amide AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Define the gettext package to be used]) ALL_LINGUAS="zh_CN zh_TW" AC_PROG_INTLTOOL dnl m4 required for compiling AC_PATH_PROGS(M4, gnum4 gm4 m4, NOT_FOUND) if test $M4 = "NOT_FOUND"; then echo "Could not find m4 on this system, please install to compile AMIDE." exit 1 fi dnl disabled 2010.02.20, hopefully this is no longer an issue dnl ===================================================================== dnl pick our optimization level, OSX's version of gcc doesn't handle -O6 dnl also, need the -headerpad_max_install_name to allow switching dnl the library paths with strings that have longer lengths dnl case "$host_os" in dnl darwin*) CFLAGS="-g -O2 -Wall" dnl LDFLAGS="-headerpad_max_install_names";; dnl *) CFLAGS="-g -O6 -Wall" dnl CXXFLAGS="-g -O6 -Wall";; dnl esac dnl added 2014.01.24 dnl make sure an optimization level is set. On jhbuild (os x) the CFLAGS gets dnl overwritten, so we're using this to make sure some optimization is on dnl when compiling. This is especially important to speeding up the dnl reslicing algorithm OPTIMIZATION_CFLAGS="-O2" echo "setting optimization level to $OPTIMIZATION_CFLAGS" AC_SUBST(OPTIMIZATION_CFLAGS) dnl 2013.11.02 - remove check for ancient versions of gcc from 13 years ago dnl if test $CC = "gcc"; then dnl echo -n "checking version of gcc... " dnl CC_VERSION=`$CC -dumpversion` dnl if (test $CC_VERSION = "2.96" || test $$CC_VERSION = "2.95.4"); then dnl echo $CC_VERSION dnl echo "******************************************************************" dnl echo "This version of gcc is a beta compiler and often incorrectly" dnl echo "compiles this program. Please upgrade to the current version of" dnl echo "gcc (3.2.1 as of this writing) or downgrade to 2.95.3" dnl echo "******************************************************************" dnl echo -n "continue anyway? (y/n) " dnl read continue_with_bad_gcc dnl if test $continue_with_bad_gcc = "y"; then dnl echo "removing optimizations to reduce potential of compiler error" dnl CFLAGS="-g -O0" dnl else dnl exit 1 dnl fi dnl else dnl echo "$CC_VERSION, good" dnl fi dnl fi ############################################################## ### Checks for optional libraries ############################################################## dnl check for various libraries and programs that we might need AM_PATH_GSL(1.1.1, FOUND_LIBGSL=yes, FOUND_LIBGSL=no) AC_CHECK_LIB(ecat, matrix_open, FOUND_LIBECAT=yes, FOUND_LIBECAT=no, -L/sw/lib) AC_CHECK_LIB(volpack, vpGetErrorString, FOUND_VOLPACK=yes, FOUND_VOLPACK=no, -lm -L/sw/lib -L/usr/local/lib) AM_PATH_XMEDCON(0.10.0, FOUND_XMEDCON=yes, FOUND_XMEDCON=no) PKG_CHECK_MODULES(LIBOPENJP2, libopenjp2 >= 2.1.0, FOUND_OPENJP2=yes, FOUND_OPENJP2=no) PKG_CHECK_MODULES(VISTAIO, libvistaio >= 1.2.17, FOUND_VISTAIO=yes, FOUND_VISTAIO=no) dnl switch to C++ for DCMTK library stuff - also, if pthread is on the platform, probably need that dnl autoconf doesn't have a nice macro for checking for c++ libraries, therefore the below: AC_CHECK_LIB(pthread, pthread_mutex_init, THREAD_LIBS="-lpthread", THREAD_LIBS="") AMIDE_LIBDCMDATA_LIBS="-L/usr/local/dicom/lib -L/usr/lib64/dcmtk -L/usr/lib/dcmtk -ltiff -lpng -ldcmimage -ldcmimgle -ldcmjpeg -lijg8 -lijg12 -lijg16 -ldcmdata -loflog -lofstd -lz $THREAD_LIBS" AMIDE_LIBDCMDATA_CFLAGS="-I/usr/local/dicom/include" saved_libs="${LIBS}" LIBS="${LIBS} ${AMIDE_LIBDCMDATA_LIBS}" saved_cxxflags="${CXXFLAGS}" CXXFLAGS="${CXXFLAGS} ${AMIDE_LIBDCMDATA_CFLAGS} -DHAVE_CONFIG_H" FOUND_DCMDATA=no AC_LANG_CPLUSPLUS AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [DicomDirInterface dcm_dir; dcm_dir.writeDicomDir(); ])], [FOUND_DCMDATA=yes], [AC_MSG_WARN([libdcmdata was not found.])]) LIBS="${saved_libs}" CXXFLAGS="${saved_cxxflags}" dnl trying to phase out libfame use in favor of ffmpeg PKG_CHECK_MODULES(FFMPEG, [ libavcodec >= 51.45.0, libavutil ], FOUND_FFMPEG=yes, FOUND_FFMPEG=no); dnl Let people compile without debugging information AC_ARG_ENABLE( amide_debug, [ --enable-amide-debug Compile with debugging messages and gdb debugging support [default=yes]], enable_amide_debug="$enableval", enable_amide_debug=yes) if test $enable_amide_debug = yes; then echo "compiling with AMIDE debugging messages" AMIDE_DEBUG_CFLAGS="-ggdb -Wall" AC_SUBST(AMIDE_DEBUG_CFLAGS) AC_DEFINE(AMIDE_DEBUG, 1, Define to compile AMIDE with debugging information) else echo "compiling without AMIDE debugging messages" fi dnl compile with warnings for obsolete Glib/GTK stuff AC_ARG_ENABLE( amide_check_obsolete, [ --enable-amide-check-obsolete Compile with checks for old GLib/GTK functions [default=no]], enable_amide_check_obsolete="$enableval", enable_amide_check_obsolete=no) if test $enable_amide_check_obsolete = yes; then echo "compiling with checks for obsolete GLib/GTK functions" AMIDE_CHECK_OBSOLETE_CFLAGS="-DG_DISABLE_DEPRECATED -DGDK_DISABLE_SINGLE_INCLUDES -DGDK_DISABLE_DEPRECATED -DGDK_DISABLE_SINGLE_INCLUDES -DGTK_DISABLE_DEPRECATED -DGTK_DISABLE_SINGLE_INCLUDES" AC_SUBST(AMIDE_CHECK_OBSOLETE_CFLAGS) AC_DEFINE(AMIDE_CHECK_OBSOLETE, 1, Define to compile with checks for obsolete GLib/GTK functions) else echo "compiling without checks for obsolete GLib/GTK functions" fi dnl check if we're building on windows dnl if you need to know OS in .c code, use G_PLATFORM_WIN32 AC_MSG_CHECKING([for native Win32]) case "$host" in *-*-mingw*) native_win32=yes ;; *) native_win32=no ;; esac AC_MSG_RESULT([$native_win32]) AM_CONDITIONAL(AMIDE_OS_WIN32, test "$native_win32" = yes) dnl specify that we're building Mac OS X with native GTK support AC_ARG_ENABLE( native_gtk_osx, [ --enable-native-gtk-osx Compile with native GTK support on Mac OS X [default=no]], enable_native_gtk_osx="$enableval", enable_native_gtk_osx=no) case "$host" in *-apple-*) on_a_macintosh=yes ;; *) on_a_macintosh=no ;; esac if (test $enable_native_gtk_osx = yes) && (test $on_a_macintosh = yes); then echo "compiling with native GTK support on Mac OS X" AC_DEFINE(AMIDE_NATIVE_GTK_OSX, 1, Define to compile with native GTK support on Mac OS X) fi if (test $enable_native_gtk_osx = no) && (test $on_a_macintosh = yes); then echo "compiling with X11 GTK support (non-native) on Mac OS X" fi if (test $enable_native_gtk_osx = yes) && (test $on_a_macintosh = no); then echo "ignoring --enable-native-gtk-osx option, as OS other than Mac OS X" fi dnl let people compile without the GNU Scientific Library AC_ARG_ENABLE( libgsl, [ --enable-libgsl Compile with the GNU Scientific Library [default=yes]], enable_libgsl="$enableval", enable_libgsl=yes) if (test $enable_libgsl = yes) && (test $FOUND_LIBGSL = yes); then echo "compiling with GNU Scientific Library support" AC_DEFINE(AMIDE_LIBGSL_SUPPORT, 1, Define to compile with the GNU Scientific Library) else echo "compiling without the GNU Scientific Library" fi dnl Let people compile without having libecat (z_matrix_70) AC_ARG_ENABLE( libecat, [ --enable-libecat Compile with the libecat/CTI library [default=yes]], enable_libecat="$enableval", enable_libecat=yes) if (test $enable_libecat = yes) && (test $FOUND_LIBECAT = yes); then echo "compiling with libecat/CTI file support" AMIDE_LIBECAT_LIBS="-lecat" AC_SUBST(AMIDE_LIBECAT_LIBS) AC_DEFINE(AMIDE_LIBECAT_SUPPORT, 1, Define to compile with libecat) else echo "compiling without libecat/CTI file support" fi dnl Let people compile without having libvistaio AC_ARG_ENABLE( vistaio, [ --enable-vistaio, Compile with the vistaio library [default=yes]], enable_vistaio="$enableval", enable_vistaio=yes) if (test $enable_vistaio = yes) && (test $FOUND_VISTAIO = yes); then echo "compiling with vistaio support" AC_SUBST(VISTAIO_LIBS) AC_SUBST(VISTAIO_CFLAGS) AC_DEFINE(AMIDE_VISTAIO_SUPPORT, 1, Define to compile with vistaio) else echo "compiling without vistaio file support" fi dnl Let people compile without having libmdc AC_ARG_ENABLE( libmdc, [ --enable-libmdc Compile with the xmedcon/libmdc library [default=yes]], enable_libmdc="$enableval", enable_libmdc=yes) if (test $enable_libmdc = yes) && (test $FOUND_XMEDCON = yes); then echo "compiling with xmedcon/libmdc file support" AC_DEFINE(AMIDE_LIBMDC_SUPPORT, 1, Define to compile with (X)MedCon) dnl 2007.10.28 - new xmedcon's should be using glib2/gtk2, dont' have to overwrite XMEDCON_LIBS dnl XMEDCON_LIBS="-L/usr/local/lib -L/usr/local/xmedcon/lib -lmdc" AC_SUBST(XMEDCON_LIBS) else echo "compiling without xmedcon/libmdc file support" fi dnl Let people compile without rendering/libvolpack AC_ARG_ENABLE( libvolpack, [ --enable-libvolpack Compile with libvolpack rendering support [default=yes]], enable_libvolpack="$enableval", enable_libvolpack=yes) if (test $enable_libvolpack = yes) && (test $FOUND_VOLPACK = yes); then echo "compiling with libvolpack rendering support " AMIDE_LIBVOLPACK_LIBS="-lvolpack" AC_SUBST(AMIDE_LIBVOLPACK_LIBS) AC_DEFINE(AMIDE_LIBVOLPACK_SUPPORT, 1, Define to compile with VolPack) else echo "compiling without libvolpack rendering support" fi dnl Let people compile without mpeg movie generation/ffmpeg AC_ARG_ENABLE( ffmpeg, [ --enable-ffmpeg Compile with ffmpeg (libavcodec) mpeg encoding support [default=yes]], enable_ffmpeg="$enableval", enable_ffmpeg=yes) if (test $enable_ffmpeg = yes) && (test $FOUND_FFMPEG = yes); then echo "compiling with ffmpeg (libavcodec) mpeg encoding support " AC_DEFINE(AMIDE_FFMPEG_SUPPORT, 1, Define to compile with ffmpeg) AC_SUBST(FFMPEG_LIBS) AC_SUBST(FFMPEG_CFLAGS) else echo "compiling without ffmpeg (libavcodec) mpeg encoding support" dnl Let people compile with libfame mpeg movie generation if not using ffmpeg AM_PATH_LIBFAME(0.9.1, FOUND_LIBFAME=yes, FOUND_LIBFAME=no) dnl AC_CHECK_LIB(libfame, fame_init, FOUND_LIBFAME=yes, FOUND_LIBFAME=no) AC_ARG_ENABLE( libfame, [ --enable-libfame Compile with libfame mpeg encoding support if not using ffmpeg [default=no]], enable_libfame="$enableval", enable_libfame=no) if (test $enable_libfame = yes) && (test $FOUND_LIBFAME = yes); then echo "compiling with libfame mpeg encoding support " AC_DEFINE(AMIDE_LIBFAME_SUPPORT, 1, Define to compile with Libfame) else echo "compiling without libfame mpeg encoding support" fi fi dnl Let people compile without the DCMTK library AC_ARG_ENABLE( libdcmdata, [ --enable-libdcmdata Compile with DCMTK support for DICOM files [default=yes]], enable_libdcmdata="$enableval", enable_libdcmdata=yes) if (test $enable_libdcmdata = yes) && (test $FOUND_DCMDATA = yes); then echo "compiling with DCMTK support for DICOM files" AC_SUBST(AMIDE_LIBDCMDATA_LIBS) AC_SUBST(AMIDE_LIBDCMDATA_CFLAGS) AC_DEFINE(AMIDE_LIBDCMDATA_SUPPORT, 1, Define to compile with DCMTK) else echo "compiling without DCMTK support for DICOM files" fi dnl Let people compile without jpeg2000 library AC_ARG_ENABLE( libopenjp2, [ --enable-libopenjp2 Compile with jpeg2000 support [default=yes]], enable_libopenjp2="$enableval", enable_libopenjp2=yes) if (test $enable_libopenjp2 = yes) && (test $FOUND_OPENJP2 = yes); then echo "compiling with JPEG 2000 support " AC_SUBST(LIBOPENJP2_CFLAGS) AC_SUBST(LIBOPENJP2_LIBS) AC_DEFINE(AMIDE_LIBOPENJP2_SUPPORT, 1, Define to compile with openjp2) else echo "compiling without JPEG 2000 support" fi ############################### # Check for gtk/gnome stuff ############################## PKG_CHECK_MODULES(AMIDE_GTK,[ glib-2.0 >= 2.16.0 gobject-2.0 >= 2.16.0 gtk+-2.0 >= 2.16.0 libxml-2.0 >= 2.4.12 libgnomecanvas-2.0 >= 2.0.0 ]) ## add in gconf if not on win32 or macos x ## gconf stuff is encapsulated in amide_gconf.c if (test $native_win32 = no) && (test $enable_native_gtk_osx = no); then AC_ARG_ENABLE( gconf, [ --enable-gconf Compile with gconf support [default=yes]], enable_gconf="$enableval", enable_gconf=yes) if test "x$enable_gconf" = "xyes" ; then PKG_CHECK_MODULES(AMIDE_GTK_EXTRA_GCONF,[ gconf-2.0 >= 2.14.0 ], [AC_DEFINE(AMIDE_USE_GCONF, 1, Use gconf for storing configutation) AMIDE_GTK_LIBS="$AMIDE_GTK_LIBS $AMIDE_GTK_EXTRA_GCONF_LIBS" AMIDE_GTK_CFLAGS="$AMIDE_GTK_CFLAGS $AMIDE_GTK_EXTRA_GCONF_CFLAGS" ]) else echo "Don't use gconf" fi fi ## add in gnome-vfs if not on win32 or gtk-osx ## gnome-vfs is only used by amide_gnome.c and only on unix if (test $native_win32 = no) && (test $enable_native_gtk_osx = no); then AC_ARG_ENABLE(gnome-vfs, [ --enable-gnome-vfs Compile with gnome-vfs support [default=yes]], enable_gnome_vfs="$enableval", enable_gnome_vfs=yes) if test "x$enable_gnome_vfs" = "xyes"; then PKG_CHECK_MODULES(AMIDE_GTK_EXTRA_GVFS,[ gnome-vfs-2.0 >= 2.16.0 ], [AC_DEFINE(AMIDE_USE_GNOME_VFS, 1, Use gnome-vfs for spawning help process) AMIDE_GTK_LIBS="$AMIDE_GTK_LIBS $AMIDE_GTK_EXTRA_GVFS_LIBS" AMIDE_GTK_CFLAGS="$AMIDE_GTK_CFLAGS $AMIDE_GTK_EXTRA_GVFS_CFLAGS" ]) else echo "Don't use gnome-vfs" fi fi AC_SUBST(AMIDE_GTK_LIBS) AC_SUBST(AMIDE_GTK_CFLAGS) dnl glib-genmarshal AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) dnl This is installed from GTK+ 2.0's gdk-pixbuf AC_PATH_PROG(GDK_PIXBUF_CSOURCE, gdk-pixbuf-csource) test -z "$GDK_PIXBUF_CSOURCE" && AC_MSG_ERROR([ *** You need the gdk-pixbuf-csource tool which is installed *** from GTK+ 2's gdk-pixbuf. *** *** Either the location where you installed your GTK+ 2 is *** not in your PATH or something is screwed up with your *** GTK+ 2 installation ]) dnl libgnomecanvas anti-aliasing has been buggy in the past. I originally thought dnl this never would be fixed. Was unclear if the issues were in libgnomecanvas dnl or libart. In any case, as of libgnomecanvas 2.30.3 things seem stable, dnl so I'm re-enabling support for now dnl dnl record if our version of libgnomecanvas can handle anti-aliasing PKG_CHECK_MODULES(libgnomecanvas_greater_than_230, [libgnomecanvas-2.0 >= 2.3.0], enable_antialiasing=yes, enable_antialiasing=no) if test $enable_antialiasing = yes; then echo "compiling with libgnomecanvas antialiasing support" AC_DEFINE(AMIDE_LIBGNOMECANVAS_AA, 1, Define to compile AMIDE with an antialiased canvas) else echo "compiling without libgnomecanvas antialiasing support" AC_DEFINE(AMIDE_LIBGNOMECANVAS_AA, 0, Define to compile AMIDE with an antialiased canvas) fi ################################################################ # Checks for gtk-doc and docbook-tools, from gtk's configure.in ################################################################ dnl if we define --enable-gtk-doc, we build the library documentation GTK_DOC_CHECK([1.10]) dnl the following is for the application documentation AC_ARG_ENABLE(doc, [ --disable-doc Do not build documentation.],,) if test "x${enable_doc}" = "x" ; then enable_doc=yes fi AC_MSG_CHECKING(whether documentation should be built) if test ${enable_doc} = no; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi AM_CONDITIONAL(DISABLE_DOC, test ${enable_doc} = no) if test ${enable_doc} = yes; then dnl building documentatin GNOME_DOC_INIT else dnl not building documentation ENABLE_SK_TRUE="#" ENABLE_SK_FALSE="" HAVE_GNOME_DOC_UTILS_TRUE="#" HAVE_GNOME_DOC_UTILS_FALSE="" fi AC_CHECK_PROG(DB2HTML, db2html, true, false) AM_CONDITIONAL(HAVE_DOCBOOK, $DB2HTML) AC_SUBST(CPPFLAGS) AC_SUBST(LDFLAGS) AC_CONFIG_FILES([ Makefile pixmaps/Makefile src/Makefile win32/Makefile macosx/Makefile macosx/amide.plist doc/Makefile doc/reference/Makefile doc/reference/version.xml help/Makefile etc/Makefile etc/amide-$VERSION-1.info:etc/amide.info.in etc/amide-$VERSION-1.iss:etc/amide.iss.in etc/amide.spec man/Makefile po/Makefile.in]) AC_OUTPUT dnl help/C/Makefile dnl help/es/Makefile dnl Move the spec file so it won't get eaten by make distclean if [ test -f etc/amide.spec ]; then echo "Moving SPEC file to base directory" mv etc/amide.spec ./ fi amide-1.0.6/amide-current/doc/000077500000000000000000000000001423227705100161045ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/Makefile.am000066400000000000000000000001511423227705100201350ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. SUBDIRS = \ reference DISTCLEANFILES = *~ amide-1.0.6/amide-current/doc/README000066400000000000000000000010051423227705100167600ustar00rootroot00000000000000 In the doc/reference directory is a Makefile and supporting files to generate basic API documentation for the "toolkit" portion of AMIDE. Currently, this toolkit is not distributed as an independent library, so this documentation is of limited utility and is only regenerated intermittently. The API documentation generation is based on that used for gtk. It can be enabled with the --enable-gtk-doc configuration switch. As of 2012.01.10, it does not build correctly if libdcmdata support is also configured in. amide-1.0.6/amide-current/doc/reference/000077500000000000000000000000001423227705100200425ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/Makefile.am000066400000000000000000000065101423227705100221000ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in # The name of the module. DOC_MODULE=amitk # The top-level SGML file. DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml # Extra options to supply to gtkdoc-scan #SCAN_OPTIONS=--deprecated-guards="GTK_ENABLE_BROKEN|GTK_DISABLE_DEPRECATED" # The directory containing the source code. Relative to $(srcdir) DOC_SOURCE_DIR=../../src # Extra options to pass to gtkdoc-scangobj # SCANGOBJ_OPTIONS=--type-init-func="gtk_type_init(0)" SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-mkdb #MKDB_OPTIONS=--main-sgml-file=$(DOC_MAIN_SGML_FILE) --sgml-mode --output-format=xml MKDB_OPTIONS=--sgml-mode --output-format=xml # Extra options to supply to gtkdoc-mktmpl # e.g. MKTMPL_OPTIONS=--only-section-tmpl MKTMPL_OPTIONS= # Extra options to supply to gtkdoc-fixref #FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html FIXREF_OPTIONS= # Used for dependencies HFILE_GLOB=$(top_srcdir)/src/*.h CFILE_GLOB=$(top_srcdir)/src/*.c # Header files to ignore when scanning IGNORE_HFILES= \ alignment_mutal_information.h \ alignment_procrustes.h \ amide_intl.h \ amitk_dial.h \ analysis.h \ dcmtk_interface.h \ fads.h \ image.h \ legacy.h \ libecat_interface.h \ libmdc_interface.h \ mpeg_encode.h \ pixmaps.h \ raw_data_import.h \ render.h \ tb_alignment.h \ tb_crop.h \ tb_fads.h \ tb_filter.h \ tb_fly_through.h \ tb_math.h \ tb_profile.h \ tb_roi_analysis.h \ ui_common.h \ ui_gate_dialog.h \ ui_preferences_dialog.h \ ui_render.h \ ui_render_dialog.h \ ui_render_movie.h \ ui_series.h \ ui_study.h \ ui_study_cb.h \ ui_study_menus.h \ ui_time_dialog.h \ xml.h ALL_OBJ_FILES= \ $(shell ls ${top_srcdir}/src/*.o) IGNORE_OBJ_FILES= \ ${top_srcdir}/src/amide.o OBJ_FILES= $(filter-out $(IGNORE_OBJ_FILES),$(ALL_OBJ_FILES)) # Images to copy into HTML directory HTML_IMAGES = # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE) content_files = \ version.xml \ theory.sgml # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget # signals and properties. GTKDOC_CFLAGS= \ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ -I$(top_srcdir) \ -I$(top_builddir) \ $(GSL_CFLAGS) \ $(LIBFAME_CFLAGS) \ $(AMIDE_GTK_CFLAGS) \ $(AMIDE_DEBUG_CFLAGS) \ -I/usr/local/include \ $(XMEDCON_CFLAGS) \ -DG_DISABLE_DEPRECATED \ -UAMIDE_LIBDCMDATA_SUPPORT GTKDOC_LIBS= \ $(GSL_LIBS) \ $(LIBFAME_LIBS) \ $(AMIDE_LIBECAT_LIBS) \ $(AMIDE_LIBVOLPACK_LIBS) \ $(AMIDE_GTK_LIBS) \ $(XMEDCON_LIBS) \ $(FFMPEG_LIBS) \ $(AMIDE_LIBDCMDATA_LIBS) \ $(AMIDE_LDADD_WIN32) \ $(OBJ_FILES) # CFLAGS and LDFLAGS for compiling scan program. Only needed # if $(DOC_MODULE).types is non-empty. AM_CPPFLAGS = \ @CFLAGS@ \ -I$(top_srcdir) \ -I$(top_builddir) \ -DAMIDE_LIBECAT_SUPPORT \ -DAMIDE_LIBMDC_SUPPORT # Extra options to supply to gtkdoc-fixref # FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html EXTRA_DIST= include $(top_srcdir)/gtk-doc.make # Other files to distribute EXTRA_DIST += version.xml.in CLEANFILES = \ tmpl/* \ xml/* DISTCLEANFILES = \ *~ \ amitk-sections.txt \ amitk-undocumented.txt \ amitk-decl.txt \ amitk-decl-list.txt \ amitk-scan.c \ amitk-scan.o \ amitk.types amide-1.0.6/amide-current/doc/reference/amitk-docs.sgml000066400000000000000000000112011423227705100227540ustar00rootroot00000000000000 ]> AMITK Reference Manual Andy Loening
loening at alum dot mit dot edu
2000-2013 Andy Loening Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to:
The Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Many of the names used by companies to distinguish their products and services are claimed as trademarks. Where those names appear in any GNOME documentation, and those trademarks are made aware to the members of the GNOME Documentation Project, the names have been printed in caps or initial caps.
AMITK+ Overview AMITK is an extension of the GTK library designed for handling objects of a medical imaging nature. AMITK is released under the GNU General Public License (GNU GPL). AMITK has a C-based object-oriented architecture that allows for maximum flexibility and the creation of bindings for other languages. &amitk-Theory; AMITK Core Objects &AmitkColorTable; &AmitkCommon; &AmitkFilter; &AmitkLineProfile; &AmitkObject; &AmitkPreferences; &AmitkPoint; &AmitkRawData; &AmitkSpace; &AmitkType; &AmitkVolume; AMITK Objects AMITK Object Hierarchy &index-Object-Tree; Medical Image Objects &AmitkDataSet; &AmitkFiducialMark; &AmitkRoi; &AmitkStudy; Amitk Widgets &AmitkCanvas; &AmitkCanvasObject; &AmitkColorTableMenu; &AmitkObjectDialog; &AmitkProgressDialog; &AmitkSpaceEdit; &AmitkThreshold; &AmitkTreeView; &AmitkWindowEdit;
amide-1.0.6/amide-current/doc/reference/amitk-overrides.txt000066400000000000000000000000001423227705100236760ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/amitk.args000066400000000000000000000000001423227705100220130ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/amitk.hierarchy000066400000000000000000000043501423227705100230510ustar00rootroot00000000000000GObject GInitiallyUnowned GtkObject GtkWidget GtkContainer GtkBox GtkVBox AmitkCanvas AmitkSpaceEdit AmitkThreshold AmitkWindowEdit GtkBin GtkComboBox AmitkColorTableMenu GtkWindow GtkDialog AmitkObjectDialog AmitkProgressDialog AmitkThresholdDialog AmitkThresholdsDialog GtkTreeView AmitkTreeView GtkAdjustment GtkTreeViewColumn AmitkSpace AmitkObject AmitkVolume AmitkDataSet AmitkRoi AmitkFiducialMark AmitkStudy AmitkLineProfile AmitkPreferences AmitkRawData GtkStyle GdkDrawable GdkWindow GdkDragContext GtkTooltip GdkScreen GdkPixbuf GInterface GTypePlugin AtkImplementorIface GtkBuildable GtkOrientable GtkCellLayout GtkCellEditable GtkTreeModel GIcon GBoxed GValueArray AmitkAxes AmitkCanvasPoint AmitkCorners AmitkPixel AmitkPoint AmitkVoxel GtkRequisition GdkRectangle GdkEvent GtkSelectionData GdkColor GtkBorder GtkTreePath GtkTreeIter GStrv GEnum AmitkAxis AmitkCanvasTargetAction AmitkCanvasType AmitkColorTable AmitkConversion AmitkCylinderUnit AmitkDim AmitkDoseUnit AmitkFilter AmitkFormat AmitkFuseType AmitkHelpInfo AmitkInterpolation AmitkLayout AmitkLengthUnit AmitkLimit AmitkModality AmitkObjectType AmitkOperation AmitkPanelLayout AmitkRawFormat AmitkRoiIsocontourRange AmitkRoiType AmitkScalingType AmitkSelection AmitkSubjectOrientation AmitkSubjectSex AmitkThresholdArrow AmitkThresholdEntry AmitkThresholdLayout AmitkThresholdLine AmitkThresholdScale AmitkThresholdStyle AmitkThresholding AmitkTreeViewMode AmitkView AmitkViewMode AmitkWeightUnit AmitkWhichDefaultDirectory AmitkWindow GdkExtensionMode GtkStateType GtkTextDirection GtkDirectionType GtkDragResult GtkWidgetHelpType GtkResizeMode GtkOrientation GtkPackType GtkScrollType GtkSensitivityType GtkShadowType GtkWindowType GtkWindowPosition GdkWindowTypeHint GdkGravity GtkTreeViewGridLines GtkMovementStep amide-1.0.6/amide-current/doc/reference/amitk.interfaces000066400000000000000000000021061423227705100232130ustar00rootroot00000000000000GtkWidget AtkImplementorIface GtkBuildable GtkContainer AtkImplementorIface GtkBuildable GtkBox AtkImplementorIface GtkBuildable GtkOrientable GtkVBox AtkImplementorIface GtkBuildable GtkOrientable AmitkCanvas AtkImplementorIface GtkBuildable GtkOrientable AmitkSpaceEdit AtkImplementorIface GtkBuildable GtkOrientable AmitkThreshold AtkImplementorIface GtkBuildable GtkOrientable AmitkWindowEdit AtkImplementorIface GtkBuildable GtkOrientable GtkBin AtkImplementorIface GtkBuildable GtkComboBox AtkImplementorIface GtkBuildable GtkCellLayout GtkCellEditable AmitkColorTableMenu AtkImplementorIface GtkBuildable GtkCellLayout GtkCellEditable GtkWindow AtkImplementorIface GtkBuildable GtkDialog AtkImplementorIface GtkBuildable AmitkObjectDialog AtkImplementorIface GtkBuildable AmitkProgressDialog AtkImplementorIface GtkBuildable AmitkThresholdDialog AtkImplementorIface GtkBuildable AmitkThresholdsDialog AtkImplementorIface GtkBuildable GtkTreeView AtkImplementorIface GtkBuildable AmitkTreeView AtkImplementorIface GtkBuildable GtkTreeViewColumn GtkCellLayout GtkBuildable GdkPixbuf GIcon amide-1.0.6/amide-current/doc/reference/amitk.prerequisites000066400000000000000000000001761423227705100240010ustar00rootroot00000000000000GtkBuildable GObject GtkOrientable GObject GtkCellLayout GObject GtkCellEditable GtkWidget GtkTreeModel GObject GIcon GObject amide-1.0.6/amide-current/doc/reference/amitk.signals000066400000000000000000000225541423227705100225410ustar00rootroot00000000000000 AmitkCanvas::erase-volume void l AmitkCanvas *amitkcanvas AmitkRoi *arg1 gboolean arg2 AmitkCanvas::help-event void l AmitkCanvas *amitkcanvas AmitkHelpInfo arg1 AmitkPoint *arg2 gdouble arg3 AmitkCanvas::new-object void l AmitkCanvas *amitkcanvas AmitkObject *arg1 AmitkObjectType arg2 AmitkPoint *arg3 AmitkCanvas::view-changed void l AmitkCanvas *amitkcanvas AmitkPoint *arg1 gdouble arg2 AmitkCanvas::view-changing void l AmitkCanvas *amitkcanvas AmitkPoint *arg1 gdouble arg2 AmitkDataSet::color-table-changed void l AmitkDataSet *amitkdataset AmitkViewMode arg1 AmitkDataSet::color-table-independent-changed void l AmitkDataSet *amitkdataset AmitkViewMode arg1 AmitkDataSet::conversion-changed void l AmitkDataSet *amitkdataset AmitkDataSet::data-set-changed void l AmitkDataSet *amitkdataset AmitkDataSet::interpolation-changed void l AmitkDataSet *amitkdataset AmitkDataSet::invalidate-slice-cache void l AmitkDataSet *amitkdataset AmitkDataSet::modality-changed void l AmitkDataSet *amitkdataset AmitkDataSet::scale-factor-changed void l AmitkDataSet *amitkdataset AmitkDataSet::subject-orientation-changed void l AmitkDataSet *amitkdataset AmitkDataSet::subject-sex-changed void l AmitkDataSet *amitkdataset AmitkDataSet::threshold-style-changed void l AmitkDataSet *amitkdataset AmitkDataSet::thresholding-changed void l AmitkDataSet *amitkdataset AmitkDataSet::thresholds-changed void l AmitkDataSet *amitkdataset AmitkDataSet::time-changed void l AmitkDataSet *amitkdataset AmitkDataSet::view-gates-changed void l AmitkDataSet *amitkdataset AmitkDataSet::voxel-size-changed void l AmitkDataSet *amitkdataset AmitkDataSet::windows-changed void l AmitkDataSet *amitkdataset AmitkLineProfile::line-profile-changed void l AmitkLineProfile *amitklineprofile AmitkObject::object-add-child void f AmitkObject *amitkobject AmitkObject *arg1 AmitkObject::object-child-selection-changed void l AmitkObject *amitkobject AmitkObject::object-copy AmitkObject* l AmitkObject *amitkobject AmitkObject::object-copy-in-place void l AmitkObject *amitkobject AmitkObject *arg1 AmitkObject::object-name-changed void l AmitkObject *amitkobject AmitkObject::object-read-xml gpointer l AmitkObject *amitkobject gpointer arg1 gpointer arg2 gpointer arg3 AmitkObject::object-remove-child void f AmitkObject *amitkobject AmitkObject *arg1 AmitkObject::object-selection-changed void l AmitkObject *amitkobject AmitkObject::object-write-xml void l AmitkObject *amitkobject gpointer arg1 gpointer arg2 AmitkPreferences::data-set-preferences-changed void l AmitkPreferences *amitkpreferences AmitkPreferences::misc-preferences-changed void l AmitkPreferences *amitkpreferences AmitkPreferences::study-preferences-changed void l AmitkPreferences *amitkpreferences AmitkRoi::roi-changed void l AmitkRoi *amitkroi AmitkRoi::roi-type-changed void l AmitkRoi *amitkroi AmitkSpace::space-changed void l AmitkSpace *amitkspace AmitkSpace::space-invert void l AmitkSpace *amitkspace AmitkAxis arg1 AmitkPoint *arg2 AmitkSpace::space-rotate void l AmitkSpace *amitkspace AmitkPoint *arg1 gdouble arg2 AmitkPoint *arg3 AmitkSpace::space-scale void l AmitkSpace *amitkspace AmitkPoint *arg1 AmitkPoint *arg2 AmitkSpace::space-shift void l AmitkSpace *amitkspace AmitkPoint *arg1 AmitkSpace::space-transform void l AmitkSpace *amitkspace AmitkSpace *arg1 AmitkSpace::space-transform-axes void l AmitkSpace *amitkspace AmitkAxes *arg1 AmitkPoint *arg2 AmitkStudy::canvas-general-preference-changed void l AmitkStudy *amitkstudy AmitkStudy::canvas-layout-preference-changed void l AmitkStudy *amitkstudy AmitkStudy::canvas-roi-preference-changed void l AmitkStudy *amitkstudy AmitkStudy::canvas-target-changed void l AmitkStudy *amitkstudy AmitkStudy::canvas-target-preference-changed void l AmitkStudy *amitkstudy AmitkStudy::canvas-visible-changed void l AmitkStudy *amitkstudy AmitkStudy::filename-changed void l AmitkStudy *amitkstudy AmitkStudy::fov-changed void l AmitkStudy *amitkstudy AmitkStudy::fuse-type-changed void l AmitkStudy *amitkstudy AmitkStudy::panel-layout-preference-changed void l AmitkStudy *amitkstudy AmitkStudy::thickness-changed void l AmitkStudy *amitkstudy AmitkStudy::time-changed void l AmitkStudy *amitkstudy AmitkStudy::view-center-changed void l AmitkStudy *amitkstudy AmitkStudy::view-mode-changed void l AmitkStudy *amitkstudy AmitkStudy::voxel-dim-or-zoom-changed void l AmitkStudy *amitkstudy AmitkTreeView::activate-object void l AmitkTreeView *amitktreeview AmitkObject *arg1 AmitkTreeView::add-object void l AmitkTreeView *amitktreeview AmitkObject *arg1 AmitkObjectType arg2 AmitkRoiType arg3 AmitkTreeView::delete-object void l AmitkTreeView *amitktreeview AmitkObject *arg1 AmitkTreeView::help-event void l AmitkTreeView *amitktreeview AmitkHelpInfo arg1 AmitkTreeView::popup-object void l AmitkTreeView *amitktreeview AmitkObject *arg1 AmitkVolume::volume-changed void l AmitkVolume *amitkvolume AmitkVolume::volume-corner-changed void l AmitkVolume *amitkvolume AmitkPoint *arg1 AmitkVolume::volume-get-center void l AmitkVolume *amitkvolume gpointer arg1 amide-1.0.6/amide-current/doc/reference/html-build.stamp000066400000000000000000000000001423227705100231370ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/html.stamp000066400000000000000000000000121423227705100220450ustar00rootroot00000000000000timestamp amide-1.0.6/amide-current/doc/reference/scan-build.stamp000066400000000000000000000000001423227705100231170ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/setup-build.stamp000066400000000000000000000000001423227705100233330ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/sgml-build.stamp000066400000000000000000000000001423227705100231350ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/sgml.stamp000066400000000000000000000000111423227705100220420ustar00rootroot00000000000000timestampamide-1.0.6/amide-current/doc/reference/theory.sgml000066400000000000000000000011301423227705100222330ustar00rootroot00000000000000 Theory behind the AMITK Library 1 AMITK Library Theory behind the AMITK Library Mathematical underpinnings of the AMITK Library Basics nothing written yet amide-1.0.6/amide-current/doc/reference/tmpl-build.stamp000066400000000000000000000000001423227705100231470ustar00rootroot00000000000000amide-1.0.6/amide-current/doc/reference/tmpl.stamp000066400000000000000000000000111423227705100220540ustar00rootroot00000000000000timestampamide-1.0.6/amide-current/doc/reference/version.xml.in000066400000000000000000000000221423227705100226500ustar00rootroot00000000000000@PACKAGE_VERSION@ amide-1.0.6/amide-current/etc/000077500000000000000000000000001423227705100161125ustar00rootroot00000000000000amide-1.0.6/amide-current/etc/Makefile.am000066400000000000000000000005351423227705100201510ustar00rootroot00000000000000EXTRA_DIST = \ amide.spec.in \ amide.spec \ amide-$(VERSION)-1.info \ amide.desktop.in Applicationsdir = $(datadir)/applications/ Applications_in_files = amide.desktop.in Applications_DATA = $(Applications_in_files:.desktop.in=.desktop) @INTLTOOL_DESKTOP_RULE@ DISTCLEANFILES = \ $(Applications_DATA) \ *~ \ amide-*.info \ amide-*.iss amide-1.0.6/amide-current/etc/amide.desktop.in000066400000000000000000000004101423227705100211640ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 _GenericName=Medical Image Examiner _Name=Amide _Comment=analysis tool for medical images Exec=amide Icon=amide_logo Terminal=false Type=Application Categories=Graphics;Education;Science;MedicalSoftware; MimeType=application/dicom; amide-1.0.6/amide-current/etc/amide.info.in000066400000000000000000000017171423227705100204610ustar00rootroot00000000000000Package: amide Version: @VERSION@ Revision: 1 Source: http://osdn.dl.sourceforge.net/sourceforge/amide/%n-%v.tgz Source-MD5: Depends: volpack, xmedcon (>= 0.10.5), libavcodec1-shlibs, libxml2-shlibs, gsl-shlibs, libgnomecanvas2, atk1-shlibs, linc1-shlibs, yelp, dcmtk (>= 3.6.0), gnome-vfs2, gtk+2-shlibs (>= 2.16) BuildDepends: gtk-doc, libgnomecanvas2-dev, gconf2-dev, gnome-vfs2-dev, libart2, libjpeg, gsl, linc1, atk1, libxml2, libavcodec1-dev, dcmtk, gnome-vfs2-dev, gtk+2-dev (>=2.16) #Patch: %f.patch InstallScript: make install PREFIX=%p DESTDIR=%d ConfigureParams: --enable-gtk-doc=yes --enable-libecat=no --enable-amide-debug=no PKG_CONFIG_PATH=/sw/lib/pkgconfig #DocFiles: README COPYING AUTHORS Description: program for viewing and analyzing medical image data sets DescDetail: << AMIDE is a tool for viewing and analyzing medical image data sets. << License: GPL Homepage: http://amide.sourceforge.net/ Maintainer: Andy Loening amide-1.0.6/amide-current/etc/amide.iss.in000077500000000000000000000056011423227705100203230ustar00rootroot00000000000000; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! [Setup] AppName=@PACKAGE@ AppVerName=@PACKAGE@-@VERSION@-1 AppPublisher=@PACKAGE_BUGREPORT@ AppPublisherURL=http://amide.sourceforge.net AppCopyright=Copyright (C) 2000-2017 Andreas Loening AppSupportURL=http://amide.sourceforge.net AppUpdatesURL=http://amide.sourceforge.net DefaultDirName={pf}\@PACKAGE@ DefaultGroupName=@PACKAGE@ AllowNoIcons=yes LicenseFile=C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\COPYING OutputBaseFileName=@PACKAGE@-@VERSION@-1_install OutputDir=Inno_Output ChangesAssociations=yes [Tasks] Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:" [Registry] ; This adds the dll's in the bin directory to amide.exe's path Root: HKLM; Subkey: "Software\Microsoft\Windows\CurrentVersion\App Paths\@PACKAGE@.exe"; Flags: uninsdeletekeyifempty Root: HKLM; Subkey: "Software\Microsoft\Windows\CurrentVersion\App Paths\@PACKAGE@.exe"; ValueType: string; ValueData: "{app}\bin\@PACKAGE@.exe"; Flags: uninsdeletevalue Root: HKLM; Subkey: "Software\Microsoft\Windows\CurrentVersion\App Paths\@PACKAGE@.exe"; ValueType: string; ValueName: "Path"; ValueData: "{app};{app}\bin"; Flags: uninsdeletevalue ; This allows .xif files to get sent to AMIDE Root: HKCR; Subkey: ".xif"; ValueType: string; ValueName: ""; ValueData: "AmideXmlImageFormat"; Flags: uninsdeletevalue Root: HKCR; Subkey: "AmideXmlImageFormat"; ValueType: string; ValueName: ""; ValueData: "amide"; Flags: uninsdeletekey Root: HKCR; Subkey: "AmideXmlImageFormat\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\AMIDE.EXE,1" Root: HKCR; Subkey: "AmideXmlImageFormat\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\AMIDE.EXE"" ""%1""" [Files] Source: "C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion ; Source: "C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\help\*"; DestDir: "{app}\help\"; Flags: ignoreversion recursesubdirs Source: "C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\etc\*"; DestDir: "{app}\etc"; Flags: ignoreversion recursesubdirs Source: "C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs ; Source: "C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\man\*"; DestDir: "{app}\man"; Flags: ignoreversion recursesubdirs Source: "C:\Documents and Settings\loening\Desktop\@PACKAGE@-@VERSION@\share\*"; DestDir: "{app}\share"; Flags: ignoreversion recursesubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\amide"; Filename: "{app}\bin\amide.exe"; Name: "{userdesktop}\amide"; Filename: "{app}\bin\amide.exe"; Tasks: desktopicon amide-1.0.6/amide-current/etc/amide.spec.in000066400000000000000000000047651423227705100204660ustar00rootroot00000000000000Name: amide Version: @VERSION@ Release: 2%{?dist} Summary: Program for viewing and analyzing medical image data sets License: GPLv2+ Group: Applications/Engineering URL: http://amide.sourceforge.net Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) Packager: Andy Loening Requires: xmedcon >= 0.10.0 Requires: gsl Requires: volpack Requires: ffmpeg-libs >= 0.4.9 Requires: dcmtk >= 3.6.0 Requires: gtk2 >= 2.16 Requires: gnome-vfs2 Requires: libgnomecanvas BuildRequires: xmedcon-devel BuildRequires: volpack-devel BuildRequires: libxml2-devel BuildRequires: gnome-doc-utils BuildRequires: libgnomecanvas-devel BuildRequires: ffmpeg-devel >= 0.4.9 BuildRequires: gsl-devel BuildRequires: dcmtk-devel BuildRequires: perl-XML-Parser BuildRequires: glib2-devel BuildRequires: gtk2-devel >= 2.10 BuildRequires: gnome-vfs2-devel %description AMIDE is a tool for viewing and analyzing medical image data sets. It's capabilities include the simultaneous handling of multiple data sets imported from a variety of file formats, image fusion, 3D region of interest drawing and analysis, volume rendering, and rigid body alignments. %prep %setup -q %build %configure \ --enable-libecat=no \ --enable-vistaio=no \ --enable-amide-debug=no \ --disable-scrollkeeper make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT desktop-file-install --vendor gnome --delete-original \ --dir $RPM_BUILD_ROOT%{_datadir}/applications \ --add-category X-Red-Hat-Extra \ $RPM_BUILD_ROOT%{_datadir}/applications/* %clean rm -rf $RPM_BUILD_ROOT %post update-desktop-database %{_datadir}/applications %postun update-desktop-database %{_datadir}/applications %files %defattr(-, root, root) %doc AUTHORS COPYING ChangeLog NEWS README todo %{_bindir}/* %{_datadir}/pixmaps %{_datadir}/gnome %{_datadir}/omf %{_datadir}/applications %{_datadir}/locale %{_mandir}/* %changelog * Fri Feb 24 2011 Andy Loening - cutout gtk-doc building and scrollkeeper * Sun Dec 16 2007 Andy Loening - small tweak for new gnome-doc help files * Tue Nov 05 2002 Andy Loening - get it to work with scrollkeeper * Sun Dec 19 2000 Andy Loening - wrote this fool thing amide-1.0.6/amide-current/help/000077500000000000000000000000001423227705100162675ustar00rootroot00000000000000amide-1.0.6/amide-current/help/C/000077500000000000000000000000001423227705100164515ustar00rootroot00000000000000amide-1.0.6/amide-current/help/C/amide.xml000066400000000000000000002304261423227705100202610ustar00rootroot00000000000000 ]>
The <application>&app;</application> User's Manual V&manrevision; AMIDE stands for Amide's a Medical Image Data Examiner. This program is a tool for viewing and analyzing volumetric medical imaging data sets, and has been designed from the ground up with support for multi-modality imaging. 2000-2017 Andy Loening Andy Loening
loening at alum dot mit dot edu
Pablo Sau CDMEDICS PACS WEB (http://cdmedicpacsweb.sourceforge.net)
pablosau at users dot sourceforge dot net
Spanish translation
This is release &manrevision; of the &app; User's Manual. AMIDE Manual V0.3 2003-06-09 Andy Loening
&app; Introduction Licensing AMIDE is released under the terms of the GNU General Public Library (GPL). The text of the license is fairly verbose. A quick summary follows: You are free to run the program, for any purpose. Please note that, although the GPL makes no restrictions on use of the program, your government probably does. For instance, in the United States, AMIDE is not FDA approved and cannot be used clinically. You are free to study the source code of the program, and adapt it to your needs. You are free to redistribute the program. You are free to release modified versions of the program, as long as you also redistribute the source code to the modified program, and you label your modified version of the program appropriately. Availability of Source Code The source code for AMIDE is readily available from the AMIDE web site. Supported Platforms In addition to source code, binary versions of AMIDE along with installation instructions can be found for several systems on the AMIDE web site. The currently supported systems are Linux/i386, Microsoft Windows, and Macintosh OS X (achieved through the use of the fink add-on packages). Contact Information Questions and bug reports can be addressed to the AMIDE users list amide-users@lists.sourceforge.net. Information on joining the list and/or viewing archived messages can be found here. AMIDE Basics As the use of AMIDE is bound to be completely intuitive only to the one who wrote the program (i.e. me), this section provides a brief overview of operating within the program. It assumes you already have a data set loaded in. For instructions on getting a data set into AMIDE, see A Quick Theory of Operations AMIDE Objects AMIDE can work with and display a large number of objects simultaneous (limited only be available memory). The object types current implemented in AMIDE are as follows: Data Set A data set object contains the raw information from a medical imaging study, along with the corresponding parameters needed for interpreting that information (thresholds, colormaps, etc.). ROI A region of interest object defines a volume of space over which statistics can be calculated. All ROI's in AMIDE are volumetric. Currently, AMIDE implements ellipsoid, cylinderical, rectangular, and isocontour based ROI geometries. Fiducial Mark A very simple object, fiducial marks encode only the location of a reference point in space, and are used for rigid body alignment. Study Each AMIDE session has a single study object, which is used for grouping together a number of related data sets, ROI's, and fiducial marks. Object Tree
Study Tree An example of a study's tree structure within AMIDE. The two data sets (FDG PET and microCT) and 1 ROI (bladder) are children of the study object (m2862). The remaining ROI's are children of the data sets.
In order to facilitate working with a large number of objects simultaneously, AMIDE conceptually groups all objects into a tree hierarchy, with the study object as the root of the tree (see ). Data set objects will generally be primary branches off of the study object, while ROI's can be branches off of the study object or off of individual data sets. Why is this important? Because the structure of the tree determines how movements are mapped within the program. If a data set is moved relative to the rest of the study, the ROI's that are branches from that data set object will be correspondingly moved, so that they will maintain the correct orientation and position with respect to the data set that is their parent.
Real World Units An important thing to realize when working with AMIDE is that the program will try to abstract away the underlying digital format of the data as much as possible. When you listen to digital audio, the CD player automatically converts the series of 0's and 1's encoded on the compact disc into an analog format so that you don't have to worry about the underlying digital format. Similarly, AMIDE presents the digital data to you in analog form. When ever possible, units are given in terms of real world units (e.g. mm's, seconds), and most operations are not constrained by the discrete nature of the underlying data. For example, data in AMIDE is viewed in terms of "slices", not fixed image planes. These slices can be taken from the data set at arbitary angles, and can be of any thickness (they are not constrained to be integer multiples of the underlying voxel size). You may be used to looking at medical images in terms of voxels and integers, but remember that the object or subject scanned is an item in the real world, and AMIDE tries to recreate this "analog signal" for you. The only place the abstraction starts to break down is when dealing with dynamic data sets. Einstein understood time to be a "special" dimension, and AMIDE agrees. The reason for this, is that trying to represent dynamic data as anything but separate frames of data becomes overly complex from a computational standpoint, primarily because dynamic data is generally not equally spaced. While moving 1 voxel in the x, y, or z directions will always move you a constant unit of measurement (say 0.4 mm) in the appropriate direction, moving 1 voxel in the t direction may move you 30 seconds or 30 minutes in time, depending on what frame you're looking at. Because of this, AMIDE deals with dynamic data in terms of frames, although it should always tell you the time that those frames correspond to.
Components of the Display
AMIDE Main Window A diagram pointing out the salient features of the main window
Context Sensitive Help Located in the lower left corner of the window, the context sensitive help window shows what different mouse buttons and key strokes can accomplish given the current cursor position. Note that mouse buttons are labelled in UNIX fashion. Buttons 1, 2, and 3 correspond to the left, middle, and right mouse buttons, respectively. Under Macintosh OS X, the middle and right buttons are emulated by pressing the option key or the open apple key, respectively, while pressing the mouse button. Tree View of Study Data Located on the left side of the window is a tree listing of all the objects in the study. The tree structure shows how movements will be propogated to other objects in the study. For instance, if a data set is rotated, all of its children will be correspondingly rotated. Objects in the tree can be selected for display by left clicking on the name of the object. Middle clicking on a data set will make that data set the "active" data set. The "active" data set is designated by being highlights, and when a function is chosen that can logically apply to only one data set (e.g. filtering), the active data set is the one chosen. Object modification dialog boxes can be brought up by right clicking on the corresponding object. ROI's can be added by right clicking on the blank area of the tree, or shift-right clicking on one of the objects. These functions are further described in and . Orthogonal Views Most of the main window display consists of the orthogonal views used for visually displaying the data sets being studied. Data is usually presented as three orthogonal slices taken from the data sets, but the user can choose to display fewer of these views if desired by using the view selector (described below in ). The three views shown are the transverse, coronal, and sagittal planes. Note that the views may be incorrectly labeled for you. This could be because the data in the file you imported was not in the order that AMIDE expected it to be in. It could also be because you want to use the transverse/coronal/sagittal terminology differently then the program does (e.g. a coronal section of a rat brain is not the same as a coronal section of a rat). Below the views are sliders for adjusting where in the data set the slices are being taken from. The location can also be changed by directly clicking on any of the canvases. The appropriate mouse clicks are as follows Left Mouse Button Changes the location in the data set that the slices are taken from, without changing the thickness of the slices. Middle Mouse Button Change the location in the data set that the slices are taken from, along with setting the thickness of the slices to the minimum reasonable. Right Mouse Button Clicking an dragging with this button changes the thickness of the slices without changing the location. The thickness of the viewed slices can also be altered by adjusting the slice thickness setting spin button (see ). Other Additional functionality of the mouse buttons for manipulating data sets and ROI's is explained in and View Selector Which of the three orthogonal views are shown can be selected by using these toggle buttons. By default, all three views are shown. Linked Viewing In addition to the three orthogonal views, AMIDE can display mutiple sets of these orthogonal views, all looking at the same point ("linked") in three dimension space. This is most often used for looking at fusion images of two data sets, with one set of views used for the first data set, the next set of views used for the second data set, and the third set of views used for the fusion of the two data sets. Thresholding Tool This button on the toolbar will pop-up a thresholding and colormap selection dialog for the currently active data set. In the dialog, the maximum and minimum thresholding levels can be changed by either directly typing in the values (in absolute or percentage units), or by using sliders on the color bar. The color scale can be changed using the corresponding drop-down menu. A log normalized histogram is shown to give an idea of the distribution of the data set's value. Finally, the thresholding type can be changed. The thresholding type determines how the maximum and minimum threshold values are applied to the data set, and are: Per Slice The max and min threshold values will be applied in proportion to the max and min values in the current slice of data Per Frame The max and min threshold values will be applied in proportion to the max and min values in the current frame of the data set Interpolate Between Frames This threshold mode only makes sense for dynamic studies. In this mode, two sets of max and min threshold values are specified, along with which frame of data each of these sets corresponds to. For data frames before and including the first reference frame, the first set of threshold values are used. For data frames after and including the second reference frame, the second set of threshold values are used. For data frames between the two reference frames, the max and min threshold values are derived by interpolating (as a function of time) between the two sets of thresholding values. Global The max and min threshold values will be applied in proportion to the max and min values in the entire data set If the data set's modality is set to CT, buttons will be shown for applying bone and soft tissue windows as the thresholds. Zoom Selector This specifies how much to enlarge the views. AMIDE tries to make an educated guess about how large the display of the data should be, by using the smallest voxel dimension from the data set with the largest voxels to correspond to a displayed pixel. Zoom can be used in addition to that guesswork. Slice Thickness Setting Thickness specifies how deep the slices displayed on the views are. The minimum slice thickness is determined by the smallest voxel dimension of any of the data sets in the study. Frame Selector This button pops up a dialog for picking which frames of data to show from a dynamic data set. A frame (i.e. time period) to display can be selected by clicking on a list element. Multiple frames can be selected by holding down the shift key and selecting additional frames. Note, that for each data set selected for view, at least one frame from that data set will be displayed. If the choosen time period does not encompass a frame from that data set, the closest appropriate frame will be choosen. Gate Selector This button pops up a dialog for picking which gates of data to show from a gated data set. A gate to display can be selected by clicking on a list element. Multiple gates can be selected by holding down the shift key and selecting additional frames. Note that by using the entries, a span of gates can be choosen that loops around (e.g. gates 8, 0, and 1). Target Selector The target cross hairs are generally only displayed when one of the mouse buttons is depressed. With this toggle button, you can tell the program that you want the target cross hairs left on the views. Interpolation Interpolation refers to the method whereby AMIDE extracts data from the original medical imaging data set in order for it to be viewed on the screen. The interpolation selection button lets the user specify what type of interpolation to use when generating slices from the active data set. Nearest neighbor is faster, while tri-linear interpolation produces better looking (smoother) images with the penalty of being ~8x slower. Rendering Three rendering methods are available, MPR (multiplanar reformation), MIP (maximum intensity projection), and MINIP (minimum intensity projection). These rendering algorithms are utilized to combine data in the depth direction of the slice and/or over multiple frames of data. As such, the effects are most noticeable when the view thickness of the slices is increased and/or several frames of data are being combined. For MPR, each displayed pixel corresponds to the weighted average of the underlying data. For MIP and MINIP, each displayed pixel corresponds to the maximum or minimum value of the underlying data, respectively. Fusion/Overlay Selector By default, AMIDE displays multiple data sets as fused images. With the fused/overlay selector, you can tell AMIDE that you want the active data set to simply be overlayed on the other data sets, rather than fused. Preferences Dialog Box Underneath the edit menu is the preferences menu item. This will pop-up a dialog box that allows you to change preferences as to how things in AMIDE are displayed. The preferences will be saved in a configuration file for use by future AMIDE sessions (note: saved preferences are not currently supported on MS Windows). ROI/View Preferences Here are several preferences for changing how ROI's are the view canvas are drawn, more thoroughly described in . Note that these preferences are only used when a new study is created. To change these preferences for an existing study, you need to use the study modification Threshold Windows The window preferences are more throughly described in . Note that these preferences are only used for new data sets. To change the window levels for an existing data set, use the data set modification dialog. Default Colortable Preferences The program uses the specified color tables by default on a newly imported data set. Misc. Preferences The "Send Warning Messages to Console" option does exactly that. This is useful if enough warning messages are popping up that they're becoming annoying. With the "Don't Prompt for 'Save Changes' on Exit" option, you can tell the program to not prompt you to save changes done on the study when exiting an AMIDE session. The "Which Default Directory" controls which directory the file chooser dialog (used for save/import/open operations) will use as it's default location. "None" will cause the file chooser to show a list of recent locations as default. "Specified Directory" will cause the file chooser to utilize the directory specified as the default directory. "Working Directory" will utilize the directory from which the AMIDE program was executed as the default directory - this is most useful if you're often envoking AMIDE from the command line.
Importing Data and Saving Studies Importation of Data Sets AMIDE uses its own format (described below: ) for saving data between session. To get new data into AMIDE, it needs to be imported (located under the file menu). You can either let AMIDE try to guess the file format (which works for most data types) or tell AMIDE explicitly which format the file to be imported is suppose to be in. Importing of all data types except for raw data is done using Erik Nolf's (X)medcon medical imaging conversion library. Raw Data Files AMIDE will generally attempt to load any file ending in ".dat" or ".raw" as a raw data file. The user will be prompted for the dimensions of the study, the offset of the data in the file, and the data format of the data in the file. Both big endian, little endian, and PDP endian files can be loaded (endian refers to the order in which bytes are arranged in memory). The following data formats are supported: 8 bit signed or unsigned integer, 16 bit signed or unsigned integer, 32 bit signed or unsigned integer, 32 bit IEEE floating point, 64 bit IEEE floating point, and ASCII data. ECAT Files Static and dynamic ECAT 6.4 and 7.2 files are supported through (X)MedCon. AMIDE will generally try to load any file ending in ".img" as ECAT 6.4, and any file ending in ".v" as ECAT 7. Please note that ECAT 6.4 files are very difficult to autodetect, so if the file does not end in .img, you will probably have to tell AMIDE explicitly to import the file as ECAT 6.4. Although not compiled in by default, AMIDE can be configured to use the z_matrix_7/libecat library for handling ECAT files instead of (X)MedCon. DICOM Files DICOM 3.0 is supported through (X)MedCon, which actually uses a slightly modified version of Tony Voet's VT-DICOM library. The level of support for DICOM 3.0 is entirely determined by (X)MedCon/VT-DICOM. DICOM data is often distributed as a series of single slice data files. To read these into AMIDE as a single data set, you will need to stack these slices into a single, volumetric file. Notes on how to do this can be found at the (X)medcon website. Concorde microPET files Concorde format files are generated by the Concorde company's series of microPET scanners. It's a two file format (a data file and a header file), with the header in easily read ASCII format. Please note that you will need to tell AMIDE to open the header file (.img.hdr), not the raw data file (.img). Acr/Nema 2.0, Analyze (SPM), InterFile3.3, Gif87a/89a A variety of additional file formats are supported through (X)MedCon, including: Acr/Nema 2.0, Analyze (SPM), InterFile3.3, and Gif87a/89a. For more information, please see the (X)MedCon documentation, or the corresponding webpage (http://xmedcon.sf.net) . XIF Files AMIDE saves studies in an extensible XML based format called XIF (Xml Image Format). This format can be stored as either a single file (flat file format XIF) or as a XIF directory. The flat file format is the default, and simplifies file moving and handling. The directory format on the other hand allows easy access to the raw study data external to the AMIDE program, and will be of interest to developers. The directory format can be utilized via the "Save as XIF Directory" and "Open XIF Directory" menu items under the File menu. In any case, these files or directories will characteristically end with ".xif", and are treated identically within the AMIDE program. Opening Studies From the main window, select "File->Open", and a file selection widget will open up. Select an XIF filename in the right column, and then hit the "OK" button (or double click on the filename). Saving Studies To save a study, from the study window select "File->Save As" and a file selection dialog will appear. Look at the "selection:" line near the bottom of the window, if this is the desired XIF filename, hit "OK" and the file will be saved. If this is not the desired XIF filename, select or enter in the correct XIF study, and hit the "OK" button. Note that the original data set files are no longer needed by AMIDE, as all the information AMIDE needs is saved inside the .XIF file. You should however still archive the original data files, as AMIDE only reads in and stores the information from the header that it needs (which is generally not all the information enclosed within the header). XIF Directory Format Although admittedly annoying from a data transfer standpoint, using a directory structure for saving study information has the decisive advantage of making the saved information easily accessible using standard command-line utilities and text-based tools. Each XIF directory contains a file called "study_*.xml" which contains the basic study parameters. Additional files can also be found in the XIF directory, such as ROI_*.xml files which contain ROI's, and data-set_*.xml files and their corresponding data-set_*_raw-data files, which contain the image data set parameters and the raw data respectively. The raw data file format is arbitrary (double/float/int, 64/32/16/8 bit, little or big endian, per plane/per frame/single scale factor), and is determined by the format of the originally imported data. XIF Flat File Format The flat file format is basically a concatenation of the information enclosed within the directory format. It is not meant to be editable or developer friendly. Instead, it allows easy management of studies for casual users. If you wish to access the information in a XIF flat file external to AMIDE, you'll be much better off resaving the data as in XIF directory format. The format is as follows: The first 64 bytes of the file contain a magic string for format identification. The next 16 bytes contain 2 64bit unsigned little endian integers, the first one being the location of the study xml data within the file, and the second integer being the size of this xml data. Within the study xml data, is encased the information as to where in the file the children's xml data is. And within the children's xml data, is enclosed the location information of the raw data and subchildren. Exporting a View to JPEG/PNG To export one of the views (transverse/coronal/sagittal) to an external image file, select "File->Export View->[view]" from the menu. The saved data format by default is jpeg. If the saved filename ends in ".png", the saved data format will be PNG. Manipulating Medical Data Sets After being loaded in, medical images can be manipulated in a variety of ways with AMIDE. An important point to remember is that AMIDE deals with all data sets as 3 or 4 dimensional data sets. While 2D slices extracted from the the data set are displayed on the computer screen, at no time does AMIDE handle images as anything less than 3 dimensional data. Manipulating Data Sets on Screen Displaying Data Sets When initially loaded into the program, a data set is not displayed on the canvases. Rather, the name of the data set is contained in the study list, and the user needs to select the data set in the study list so that it is displayed on the canvases. Displaying multiple data sets is as simple as importing more than one data set, and then selecting the data sets that you wish to view from the study list. The time period over which the slices are drawn is determined by the time dialog, described in more detail in Pertinent Mouse Actions The following mouse actions can be used when the mouse is hovering over a data set on any of the orthogonal views Shift-Left Mouse Button This combination allows shifting of the active data set in space (usually used for aligning two data sets). While holding the shift key, left click (and release) on the canvas, and you'll grab the active data set. You can now shift the active data around on the canvas. At this point, to enact the shift, click the right button (button 3). Any other mouse button will cancel the shift action. Shift-Right Mouse Button This combination allows rotating of the active data set in space (usually used for aligning two data sets). While holding the shift key, middle click (and release) on the canvas, and you'll grab the active data set. You can now rotate the active data around on the canvas. At this point, to enact the rotation, click the right button (button 3). Any other mouse button will cancel the rotation. Ctrl-Right Mouse Button This combination will place an alignment point at the current cursor location. A dialog will popup for entry of the alignment point's name. Manually Aligning Data Sets What follows is a quick guide to manually aligning data sets in AMIDE First rotate each of the data sets so that they are level with respect to the transverse, coronal, and sagittal views. This is easily done using the shift-2 mouse combination, but can also be done from the data set modification dialog. Choose one of the data sets to be the active data set. The other data set will be the "fixed" data set. Shift the active data set so that the two data sets line up appropriately. This is easily done using the shift-1 mouse combination, but can also be done from the data set modification dialog. If fine tuning adjustments are needed, these are best done from the data set modification dialog. Data Set Modification Dialog To modify parameters of a data set, right click on the name of the data set in the study tree to pop-up the data set modification dialog box. Parameters that can be modified are divided into the following pages. Basic Info On this page are options to alter the data set name, type of modality, subject name, subject id, subject date of birth (DOB), conversion factor, and the interpolation type to use for this data set (described at ). The conversion factor is a parameter that is multiplied to the data set before it is used for viewing or quantitation. Since the data set is in ECAT/MAP/abitrary scale units, the conversion factor can be used in order to analyze the data set in another type of reference unit (e.g. Percent Injected Dose [%ID]). There is also a built in calculator, where parameters such as subject weight and injected dose can be entered, and the conversion factor will be generated. Note that 1 cc is assumed to equal 1 g when generating the %ID/g and SUV. Center The data set can be shifted by respecifing the center of the data set with respect to the origin. The x, y, and z dimensions are in millimeters. Voxel Size The size of the data set's voxels (again, in millimeters) can be altered on this page. The "keep aspect ratio" button specifies that when altering the size of any voxel component (x, y, or z), the relative sizes between the components should be kept the same. Rotate The data set can be rotated around its center in this page. There is one dial for each of the three slice planes. The transverse dial will spin the data set in the transverse plane (i.e. rotate on the z-axis). The coronal dial will spin the data set in the coronal plane (i.e. rotate on the y-axis). And the sagittal dial will spin the data set in the sagittal plane (i.e. rotate on the x-axis). The "reset to default" button allows the data set to be rotated back to the default orientation. On the bottom of this page is a matrix showing the coordinate frame of the data set with respect to the base coordinate frame. Colormap/Threshold This page is analogous to the thresholding tool dialog (described at ) above). Time From this page, the timing information of the data set can be altered. Scan start time can be used for altering the start time of the scan with respect to other data sets. Corrections in the duration of each data frame can also be made on this page. Windowing Preferences The max and min threshold levels used for the bone and soft tissue CT window buttons can be explicitly set here. The "Insert Current Thresholds" button will reset the max and min values with the data set's currently used threshold levels. Immutables This panel lists information about the data set that cannot be altered. The underlying internal data format of the data set and the data set dimensions in voxels are displayed on this page. Using Regions of Interest (ROI's) ROI stands for Region of Interest. An ROI designated a volume in space over which statistics should be calculated. ROI Types The following ROI types are currently supported in AMIDE: Geometric ROI's Ellipsoid An ellipsoid is similar to a sphere, but with a diameter specified for each direction [x,y,z]. In the case of x=y=z, the ellipsoid is a sphere. Elliptic Cylinder An elliptic cylinder is similar to a regular cylinder, except it has an ellipse as its base instead of a circle. Box Exactly what it says, a 3D box. Isocontour ROI's Isocontour ROI's are regions selected from the data set such that the edge values of the ROI are always the same value. There are two types, 2D and 3D isocontours. Additionally, both these ROI types can be defined so that they encompass all neighboring values either above a certain minimum value, below a certain maximum value, or between a minimum and maximum value. After drawing of these ROI's, they can be modified by using manual drawing or erasing operations. 2D Isocontour A 2D isocontour is derived by considering a value on one of the displayed 2D slices. The depth of a 2D isocontour is specified initially by the depth of the viewed slices. 3D Isocontour A 3D isocontour is derived by considering a value on the current frame of the active data set. Freehand ROI's Freehand ROI's are regions of interest that are drawn manually. 2D Freehand A 2D Freehand ROI is similar to a 3D Freehand, except that it is constrained to be only one voxel thick. By default, the depth is the current slice thickness, although this can be changed by the user. 3D Freehand An ROI that can be drawn freely in all 3 dimensions.. Drawing ROI's To draw an ROI, you first need to create a new ROI. You can add a new ROI to either the study, or a particular data set. To add an ROI to the study, you can either select the ROI desired under the "Edit->add ROI:" menu item, or right click on the blank area of the study tree. To add an ROI to a data set, shift-right click on the data set that you'd like to add the ROI to. In both cases, a dialog box will pop-up for you to enter in the new ROI's name. When first added, the new (undrawn) ROI will be selected in the study tree. When an undrawn ROI is selected in the study tree, the program will use the next mouse input on any of the displayed views to begin the process of drawing this ROI. For ellipsoid, elliptic cylinder, and box ROI's, a click with the left button will begin an edge-to-edge drawing, while a click with the middle button will begin a center-out drawing. The x and y dimensions of the ROI are determined by this process. The z dimension (thickness) of the ROI can be specified by the pop-up dialog that will appear on the completion of the mouse movement. For isocontour's, the value of the data set at the clicked upon location will be used to derive the isocontour. For freehand's, the point on the screen that is clicked upon will be included in the ROI. Manipulating ROI's After an ROI is drawn, it can be further manipulated to adjust its size, placement, and orientation. You can directly manipulate the ROI by clicking on it in any of the viewing windows. Mouse button 1 is used to shift ROIs. Mouse button 2 is used for zooming ellipsoid, elliptic cylinder and box ROI, and is used for entering drawing mode for isocontour and freehand ROI's. Mouse button 3 is used to rotate ellipsoid, elliptic cylinder, and box ROIs, and for redefining the isocontour value for isocontour ROI's. For isocontour and freehand ROI's, drawing mode can be entered by using thie middle mouse button (button 2). Once entered, points can be added or removed from the ROI by using the left (button 1) or right (button 3) mouse buttons, respectively. Holding down the shift key while using these buttons increases the size of the action. The middle button (button 2) allows the user to leave drawing mode. You can also edit the ROI size/placement/orientation/name etc. by clicking on mouse button 3 while over the ROI's name in the study item list. This brings up the ROI modification dialog (described at ). Calculating Statistics Statistics on an ROI can be calculated via the "Tools->calulate ROI statistics" menu item. Choosing this will pop-up a dialog that lets you choose which ROI's (selected or all) and which data sets (selected or all) you'd like to calculate statistics over. You will also have three options as to how you what the values to be calculated. Calculate over all voxels. Calculate over highest x percent of voxels. For example, if you choose this and pick 25% as the number, your ROI will be calculated from the 25% of the voxels in the ROI that have the highest values. Calculate for voxels >= % of Max. This method is based on Lee, Madsen, Bushnel, and Menda, Nuc Med Comm 2000, 21:685-690. As an example, if you choose this and pick 50% as the number, the highest valued voxel in the ROI will be found, and then the ROI statistics will be calculated for all voxels that are greater or equal to 50% of the highest valued voxel. Calculate for voxel >= Value. This algorithm only does calculations for voxels in the ROI that have a value greater than the value specified. There's also a check box to enable "more accurate quantitation". The default algorithm (corresponding to unchecked) makes some approximations in deciding which voxel are in our out of the ROI. If this check boxed is checked, the ROI results will be more accurate, but will take much longer to compute. After hitting execute, the program will crank for a while, and then show the calculated values in a new dialog window. Hitting "Save as" button allows saving these values as a tab separated values (TSV) file. This file should be easily imported into most spreadsheet applications (Excel's a little stupid, you may have to explicitly tell it you're importing a TSV file). Pressing the "Copy" button copies the information into the operating systems clipboard, allowing pasting of the results into other programs. The "Save Raw Values" button allows you to export the underlying raw data values for the ROI's in case you wish to do your own statistical analysis. Gotcha's to ROI calculations Variance and Standard Deviation Fallacies Currently, AMIDE generates variance and standard deviation values that may occasionally be of interest to imaging physicists. It is very important to remember, that these numbers represent the noise in the data set, NOT the noise in your experiment. The variance of an experiment can only truly be measured by taking multiple samples (i.e. performing multiple scans) and calculating the variance between these different samples. Changing Calculated Volume Short story: The calculated volume shown by the ROI statistics dialog is correct. Use this value as the volume of the ROI, not the value you might calculate by hand based on the ROI's dimensions. Long story: AMIDE calculates ROI's by translating the ROI's dimensions into the data set's coordinate space. It then computes statistics for all the data set voxels that are in the ROI. For voxels that lie on the edge of the ROI, AMIDE will subdivide the voxel into a finite number of subvoxels, and calculate over the subvoxels. This approach yields correct statistics, but it is important to realize that the computed ROI is a discrete representation of the specified analytical ROI. So while the true volume of an ellipse is pi*r1*r2*r3, the computed volume of the ellipse in AMIDE will depend on the number of voxels and subvoxels that were determined to lie within the ellipse, which in turn can depend on the orientation of the ROI with respect to the data set in question. Since the computed volume given by AMIDE represents the volume in the data set that was used for the ROI calculation, you will want to use that value (not the real ellipse value). Why isn't a "total" statistic calculated for the ROI? AMIDE doesn't present the "total" value in the ROI, as it doesn't necessarily know what the units of the underlying data are. If you're using PET or SPECT data, your voxel values are most likely proportional to activity/volume/time. To calculate the total in your ROI, you should multiple the mean value of the ROI times the ROI volume and the frame duration. If you're using CT data, your values are probably proportional to density, so to calculate the total you would multiple the mean ROI value by the ROI volume. Explanations of ROI Statistical Values Median This is the median value of all the voxels that are enclosed (partially or totally) within the ROI. For an even number of voxels, the median is defined as the average of the center 2 values. Mean The mean value of the voxels in the ROI. Voxels that are partially enclosed within the ROI are appropriately weighted. Variance The variance of the voxels in the ROI. This is a weighted variance calculation so that voxels that are partially enclosed within the ROI are correctly handled. Standard Deviation The square root of the variance. Standard Error The square root of the variance, divided by the square root of the total number of voxels in (totally or partially) the ROI. Minimum/Maximum The minimum and maximum values for all voxels enclosed totally or partially within the ROI. Size The volume of an ROI (mm^3). Details as to its calculation are above in: . Fractional Voxels The is the sum of the voxel weights, and gives an indication of how large the ROI is in voxel space. Voxels This is the total number of voxels used in calculating the ROI, both partial and total. In contrast to the "Fraction Voxels" measure, the "Voxels" measure gives a better indication of the statistical validity of the mean, variance, etc. ROI Modification Dialog To directly modify parameters of an ROI, right click on the name of the ROI in the study tree to pop-up the modification dialog. Parameters that can be modified are divided into the following pages. Basic Info The name and type of ROI can be altered on this page. Center The center of the ROI can be shifted with respect to the origin on this page. The x, y, and z parameters are in millimeters. Dimensions The size of the ROI can be altered from this page. The x', y', and z' dimensions are in millimeters and are orientated with respect to the orientation of the ROI. Rotate The ROI can be rotated around its center in this page. There is one dial for each of the three slice planes. The transverse dial will spin the ROI in the transverse plane (i.e. rotate on the z-axis). The coronal dial will spin the ROI in the coronal plane (i.e. rotate on the y-axis). And the sagittal dial will spin the ROI in the sagittal plane (i.e. rotate on the x-axis). The "reset to default" button allows the ROI to be rotated back to the default orientation. On the bottom of this page is a matrix showing the coordinate frame of the ROI with respect to the base coordinate frame. The Study The "Study object" in AMIDE is used for grouping a set of related data sets and ROI's. Note that the use of the word "Study" here diverges from the traditional nuclear medicine use of the word, in which study generally connotates a single scan (or occasionally multiple but highly coupled scans) done on a single patient. A study in AMIDE is often used to group an entire experiment (several patients, several animals, whatever) into a single file. The study object itself is used mostly for storing parameters that effect all other objects stored in the study. Study Modification Dialog Similarly to the data set and ROI modification dialogs, the study modification dialog can be used to alter parameters relevant to the entire study. Right click on the name of the study in the study tree to pop-up the study modification dialog box. Parameters that can be modified are divided into the following pages. Basic Info On this page are options to alter the name and creation date of the study. View Center From this page, the point that the study is currently viewing can be explicitly changed. The x, y, and z dimensions are in millimeters. Rotate The entire study (including all objects within it) can be rotated around the view center in this page. There is one dial for each of the three slice planes. The transverse dial will spin the study in the transverse plane (i.e. rotate on the z-axis). The coronal dial will spin the study in the coronal plane (i.e. rotate on the y-axis). And the sagittal dial will spin the study in the sagittal plane (i.e. rotate on the x-axis). The "reset to default" button allows the study to be rotated back to the default orientation. On the bottom of this page is a matrix showing the coordinate frame of the study with respect to the base coordinate frame. ROI/View Preferences The width of the line used to draw geometric ROIs can be altered here (1-5 pixels). This parameter is not relevant for isocontour ROI's. For isocontour ROI's, you can choose to have them draw as filled in or hollow. Canvas layout allows you to switch the three views (transverse, coronal, and sagittal) between a linear style layout more commonly seen in PET software, and an orthogonal style layout more commonly seen in MRI software. "Maintain view size constant" allows you to pick if you want the size of the view to remain constant or not. If not checked, the size of the views shown will depend only on the data sets selected. If the checkbox is checked, the size of the views will depend on all the data sets in the study. Finally, "target empty area" is for setting the size of the empty area in the middle of the target (the crosshairs on the views when changing the view location). Immutables This panel lists information about the study that cannot be altered. "Voxel dim" is the preferred voxel dimension, this is what the canvas will use as the "basic" voxel dimension, from which the zoom factor is relative too. Viewing Series of Slices Instead of looking at three orthogonal slices through the data set, a series of slices (all of the same orientation) can also be examined. Select: "View->Series", and a dialog box will come up allowing you to pick which objects you'd like to display on the series viewer, along with if you'd like to display the slices over space, time, or gates. The thickness of the slices are determined at the time the series window is brought up. A slider appears on the top of the window which allows moving through the data set. Note that since slices are cached in memory after being displayed, already displayed slices do not need to be regenerated from the data set and reviewing these slices is significantly faster. Rendering Data Rendering in AMIDE is accomplished using the Volpack volume rendering library. This software library is both portable, and provides for true volume rendering (as opposed to the surface rendering used by many other libraries and hardware accelerators). To start a rendering window, select the "View->Rendering" menu item. A small dialog window will pop-up allowing you to select which objects you'd like rendered, along with some additional options. The first "Set values greater than max threshold to zero" allows you to strip high level voxels out of the rendering process. In general you won't want this, but it might be useful if you have high valued areas in your data set that obscures what you'd like to see. The second option "Accelerate Rendering" tells VolPack to use a faster method for doing the volume rendering. You will in general want to use this option, as it causes a significance performance enhancement (around 10 fold). It does, however, require around 3 fold as much rendering as the non-accelerated option, so if you're running out of memory, you'll want to try to rendering without the acceleration. The third option "Initial opacity functions only density dependent" sets things such that the initial gradient opacity function does not contribute to the rendering. This is useful for data sets (e.g. PET) where one is more interested in having an accurate view of the data, rather than a view where gradients in the data set are highlighted. After hitting "Execute" the program will reslice the data sets and ROI's into a data structure that the volpack library can handle, and then perform some initial renderin gcalculations. For data sets, the interpolation type specified for the data set will be used. This whole process will take some time, so be patient. Please also note that, when converting the data set, the data is scaled between the current minimum and maximum threshold, with all data above the current maximum threshold set to the maximum threshold value (or zero, if specified), and all data below the current minimum threshold set to the minimum threshold value. This scaling can be relative to the data set's "Global" maximum and minimum, to the "Per Frame" maximum and minimum, or can be from maximum and minimum values "Interpolated Between Frames". "Per slice" scaling does not make sense in the context of volume rendering, and is interpreted as "Global" scaling. When all this is completed, the rendering window should pop-up. Its use is described below. Rendering Window Main Rendering Canvas The result of the rendering process is presented on the canvas in the center of the window. This canvas can accept user input to change the orientation of the rendering. Button 1 allows rotating on the x and y axis, and button 2 allows rotating on the z axis. Spin Sliders You should notice two slider type widgets, one on top of the rendered image, and one on the right side. These are both appropriately labeled with the axis around which the rendering will be spun if they are changed. Additionally you should notice a dial widget (labeled 'z'). The dial is for rotating on the z axis (which comes out of the plane of the display). Note that the effect of rotations are cumulative. Reset Axis This button will reset the rendering's orientation back to the default orientation. Toolbar Transfer Function Button This will pop-up a dialog with a panel for each object being rendered. The available options are described below: Return Type This setting determines whether the rendering returns an image which looks more analogous to an x-ray (the "opacity" setting), or returns an image which looks more like a surface (the "grayscale" setting). The "grayscale" setting does this by specifying a light source, material properties, and using depth cueing. Color Table The color table of each rendered object can be changed here. Classification Functions This is the most confusing part of rendering, so hang on here. The classification functions are used to map between the value in each voxel and how much that voxel should be represented in the final rendered image. On the x axis is the possible values of the different voxels. On the y-axis is the opacity that will be given a voxel based on its value. Both classification functions have several buttons on the right side of their graphs. The top button allows the classification function to be drawn as a spline. The second button allows the classification function to be drawn as a series of straight lines. Finally, the last button resets the classification function to a straight line. There are two classification functions: Density Dependent: This function tells you how opaque each voxel will be based on its current value. In a sense, this is analogous to an x-ray, where the amount of the x-rays that are absorbed in a structure is related to the density of that structure. of the display. Gradient Dependent: Instead of relating the density of a voxel to its opacity, this function relates the gradient of a voxel (how much the value changes between this voxel and its neighbors) to its opacity. This has the effect of giving added weight to surfaces. Monoscopic/Stereoscopic Buttons You can choose between generating a single rendered image (monoscopic), or a stereoscopic image pair. A stereoscopic image pair is a pair of images that have been generated at slightly different angles. When viewed correctly, these two images can be interpreted by the viewer's eyes as a single image containing depth information. Zoom Determines the size at which the resultant rendered image will be displayed. Note that changing the zoom will not affect the speed of the rendering, and increasing the zoom past 1 will not increase the resolution of the rendered image. Rendering Menus File->Export Rendering This menu item allows you to export the rendered image to an external image file. The saved data format is jpeg. File->Create Movie This causes the movie generation dialog box to pop up. This dialog box is further described below: . Edit->Rendering Parameters This causes the rendering parameters dialog box to pop up. This dialog box is described below: . Rendering Parameters Dialog Speed versus Quality With this drop-down menu, the user can choose between rendering speed and rendering quality. To increase speed, voxels with values either close to zero or close to unity can be counted as completely translucent or completely opaque, respectively. The highest quality doesn't use this approximation at all, the lowest quality setting uses this approximation big-time. Stereosopic parameters These parameters are used for controlling the results when the "stereoscopic" option has been chosen. Stereo Angle This is the angle offset (in degrees) between a pair of rendered images. Increasing this number will generally give a greater sensation of depth in the image pair. A Reasonable value for this parameter is between 2 and 5 degrees. Note that this parameter will be saved between different sessions of the program (not currently done on MS Windows). Eye Width (mm) Ideally, this should be (roughly) the distance between the two rendered images, and corresponds to the distance between the user's eyes. It is impossible for a person to resolve a stereoscopic pair if the images are farther apart then the person's eyes, since human eyes cannot move independently. While this parameter is specified in millimeters, the actually distance between the pair of images that gets displayed on the monitor depends on the setup of the computer. If the monitor information reported by the operating system is not correct (usually the case), the "eye width" parameter will not be in true millimeters. Note that this parameter will be saved between different sessions of the program (not currently done on MS windows). Depth Cueing These parameters are only used if the "grayscale" output type has been chosen. Enable/Disable Depth Cueing Specify whether or not we want depth cueing. Depth cueing puts in a "fog" that causes more distant voxels to appear less bright. Front Factor This is the transparency of the fog at the front of the data set. If this number is greater than 1.0, voxels toward the front of the data set will be brightened. If this parameter is less than 1.0, voxels toward the front of the data set will be darker, respectively. Density This is how thick the "fog" is. The thicker the fog, the darker distant objects seem. Rendering Movie Dialog Frames How many frames should be in the MPEG1 movie. The MPEG1 movies generated will be set to run at 30 frames/second, so the default of 300 frames will give a ten second movie. Rotations on [x,y,z] This setting determines how many times the data set will be rotated around the given axis over the course of the movie. The rotation for each frame is done in x->y->z order (rotate on x first, then y, then z). Dynamic Movie: No/Over Time/Over Frames Smoothed/Over Gates This option allows a rendered movie to be made over a time period, which is useful for dynamic data sets. Note that every time a frame boundary in the data set is passed over, the rendering process must slice and load in a new frame of data. This makes creating a rendered movie over time significantly slower than a movie with just rotations. Picking "over time" will allow entry of a start and end time for which the data from the data sets should be drawn. With the "over time" option, each second is given equal waiting in terms of how many images from that time period are generated for the output movie. Picking "over frames" allows entry of a start and end frame (note that this really only makes sense with a single data set). The advantage of "over frames", is that each frame is weighted equally in terms of how many images are generated for the output movie, so for data sets were the dynamics of interest correspond closely to the dynamics of the data set framing sequence, "over frames" may give a more appealing result. The "over frames smoothed" option is almost the same as "over frames", except that data will be interpolated between frames. This makes for a smoother movie (no jumps) but takes much longer as nearly every movie frame has to be reloaded. Additional Tools Alignment Wizard In addition to manually aligning data sets (described at ), data sets can also be aligned using the alignment wizard utilizing either mutual information or fiducial markers. Alignment with Mutal Information A rigid body alignment can be performed utilizing mutual information between two data sets. This algorithm works by taking orthogonal slices from one data set (transverse, coronal, and sagittal) and computing a transform to best allow matching of these slices to the second data set. This algorithm works best when the two data sets have already been roughly aligned. Note that the orthogonal slices utilized for the matching are derived utilizing the current viewing parameters (current viewing location, slice width, interpolation method, etc). Alignment with Fiducial Markers A rigid body alignment can be performed utilizing fiducial markers. The process is basically: Draw at least three pairs of fiducial makers between the two data sets that you wish to align. Drawing fiducial markers is described below as . Run the alignment wizard (under tools->alignment wizard). For the alignment wizard to recognize two fiducial markers as a pair, they must have exactly the same name. So if you have a marker labeled "1" under the first data set, you will need another marker, also labeled "1", under the second data set. Drawing Fiducial Markers Fiducial markers can be added to any of the data sets in the study in a variety of ways. For the currently active data set, hitting the "Edit->Add fiducial mark" menu item will drop a fiducial maker at the currently viewed location. Fiducial marks can be added for the active data set directly from the views by pressing ctrl-right mouse button, which will drop a fiducial marker at the point that the mouse is currently at. Finally, fiducial markers can be added to non-active data sets by pressing ctrl-right mouse button while hovering over a data set's name in the study list. After being created, the fiducial marker can be moved by clicking on the marker point shown in any of the views. Fiducial Marker Modification Dialog Box To modify parameters of a fiducial mark, right click the point in the study list to pop-up the Fiducial Marker Modification Dialog. From this dialog, the name and location of the fiducial marker can be altered. Crop Wizard Coming soon. Note that only what is strictly inside the cursor lines is saved. What's underneath and outside the cursor lines is cropped away. Factor Analysis Wizard The factor analysis wizard is currently being developed. It probably won't work for you, and is only included in AMIDE for those who might be interested in working on it (rather than with it). Filter Wizard Nothing written yet... Fly Through Wizard Nothing written yet... Note, will generally get much better results for fly through if using trilinear interpolation. Profile Tool A complete description of this tool has not yet been written. The left and right limits of the gaussian fit can be altered by clicking on the profile with the left and right mouse buttons, respectively. The x value used for initializing the gaussian fit can be picked by clicking on the profile with the middle mouse button. Note that the line profile is extracted from the currently viewed image, not the underlying raw data itself. This means things like the current interpolation and FOV will effect the line profile that's generated, and as such may effect the FWHM that's fitted. ROI Statistics A description of the ROI statistics tool can be found at: .
amide-1.0.6/amide-current/help/C/figures/000077500000000000000000000000001423227705100201155ustar00rootroot00000000000000amide-1.0.6/amide-current/help/C/figures/amide_main_window.png000066400000000000000000001757071423227705100243160ustar00rootroot00000000000000PNG  IHDRD^~[bKGD pHYs."."ݒtIME &R$ IDATxw@lJRDT h1ib5y)1Xb RT ;:3c6Xݻv9qH;w@A@TVKtKн6Jwt sss{{>I=zWF333h4GV0|}I" % C@@76w(tRclY,QRa8$@5A@O#Z ]_'ϟJ=) o=v] p(BL&TVVZXX==zuzGB~;{섄={tv 1 13kٵjN#wtTƂ*qR[D*jޯ75 J.R$^]' @<<AU_Fk7ݟ(iw!9|0k׮500hmmy#G=/O)wKK˗=zt׮]d2Y*)KeXKko՘LZY%b#\dfa0T*T"w(ZFjra&&v*wPc@eԟ.} b[c]BO-I^p4"QT=z w "ɞcƌR2 So<,WW76JeP&I2j5ܡPj DR6C*TQR؀K}GbkekD(ß, Ci'*_V'mhf{ܵ?/UƱ߾};LfͽrѣRt: (:u w8҅ OZlBPOO/u? 8?-}؀, R---ѣ`0 նDꕑ;RfZ =zs=z3+w=z2P;㥥ZO Ʋ&>hyyR|aohhhkk---#~GT='[ZZRP(wǏ ɓ'3̔ZMPp700dT*ի0 ܿ5..N+JD+MMMR)a4PZZp޽khh T*rN755 ѣGK0 VB0;;[,[n Bcc㼼ﷴ 555T*URS(ETT*}ammmmm- JBۿr\,B!DH$b* ;zt@[&''Ĥ"`V$L&+J*8HW( AA'y h4F)J&)J D"h0 T*FCRr90LRh4BA&&&Jq5JjmmR P.H$_9yT*D<OGd(+zG0 2z^/>>>_|ѣGe@lh|||t+=z,6l1cw}WRRxqDD'٧hoooooݻ~ y}!bbbMMM###ۢ"Bkt FAQ411`ؐHW0%%]w._ 077dA "11ƆD{UƦҥK]((GGT__ߙ3g ²\?Bd2mllRibbZNLLJ> P]YfX,tڵkW\yL6/`Æ 111gdd2:%///+++--Et]?N|x…œ'O>~8F[`+W,--: 8wܺux<ŋϞ=qٳg=zT;uMMܹsKKK|T*=<vvvgΜ;vѣG'NDR_GD8i$77;wr\F}aǷlr!&%K:t?h4[nܫW^O #]N>뛐 \h,XPRR2a„~N,_fgӦM=z/윞r7mtwEDD|7|\._t|򊊊YYYc/ZmԨQ^ggŋSRRFѣF]|K.ݽ{M6>>>妤8;;o۶oJII^땻.駟233_mvʕ+WT:$((yݼys񩩩Ǐwuuݵk׆ /\oܹ;??ݻW\9ui4ڝ;w7mڴbŊ7.\pҤIvss#شiɬx>ގaX~~IJJJƌdbb믿fee]tE牭RVZe˖}-X?_llly"h}?Jw^fMNNΪUf̘ygo7n͛7=<<&L=nܸ144Zlه~9{+֚C޼yW^---ݸqѣcbbNz֭[W^M̾f͚O>ѣSLqppؽ{weeeUUնmV^} X";;AS;v5/**233#[xxϟ?R^땻.Yrʕ+322{P  YbEJϘTYf9Hkڲe###6l nݺj*A&Nj*ghhB W *2dΜ9YYY 766Gr|IbUWW\&,,,??dԡx&[#%%B /^lcc`ǏԬZ&444??xQWP.@ɓ۷osNZZҥKy<^>%%%Ǐ;vldddvvZ>qB0gaooODh7l0dȐt[[[7|А9s#˕wޅ h"H |۷͜9.00p~~~SNh1Rtƍ>T*h4FP`&(ZM6d[[[\~ ӧT5kּ+@RT*mioo766)lmm-[l2@uuunnnZZZNNNeeeotpp3gN/J2耞E13 5ʯ^Z[[O?EEE nb577[XX477kougt@ q(*JRݿ&pRD"aXL6}݅ \bffFp8t:`P(&wwޚFGG߿?::z޼y555X,DV92zhyf.xbzX,@HNN&L&sϞ=[o5tnL;T*?0,55uϞ=ӧO:ujAA}Ba||<@Tы-|auu55jԎ;bqGG?n_'LT*;::^Sr)++fX.\.WRuvvzxxY&M4իӧOoߞ={T*mll400p830.;;;;;;33B7!*>J$smٲ[dIGG37.\啑A/"^zw>Ğ'9sݻ,XÞ{Ϟ={ڵAAA'O xfb2 b֬Y|>U?_|2, x￯Z/^\hٳ׬Y/?󰰰Rs΍xT*6mO?ԵOHHƍ͛Du[[ݻwegg߼y]h^__)b:&;={6&&iǧٳg?/RiBB”)Sƌcmm㸍ͶmBBBd2R֭YYY7o˗/}||f̘AϞ=`YXX>: ˗/{zz%%%;PI_.\?mmm㏎__ߛ7o;99=~gX .444lll0lܹ]G+)) hR4338)))4SNa8!!/((Ç|>ǏE.--x񢡡 ?~ J}}}b3g|>q O&--FM2e8gdd8;;GFFR(˗/]V*:u7 ^92==uȐ!yyy\.>///33'$$$++W{1 KKGTVV2 Rijj gHkk!{fccXQQ`0PebeiiA"@mmmFFFffۦMzkX=ɵkf̘SXXԔ͢GϋSVVrʶw%}-?Eii[\nhhh}=z^ǏgeeQԐW6w=z#G9r/>;a3@ Ȁ2=}JTTwܩkA^e˖準e 2;uw8 By~JVϞ=yK{d8G믿ō{B޾}Futtݽ{`xyyXZZvvvŽ֦&CCÊ ssƎdL͠ @"F^͵*&,ʗk4r^UD"qaÆYYY`g38Dw=H$066:ueϏ㵶BDFAQ#PAa eԨQl6:+++::Z(vM3Tjj:YL*CM-:į  PL&wG5jT{{;A+++svvh7n!S+Jwܙ5k,GVWVV u-˿ .H$9s# z`[[ۢsW0 H/w R^^f5 QM B"'B0 EQ2or޽#G c„ iii刌<Kt-exp\21,6/L͝H$붼8lՄ'''++,Hw]Ajj&3@H$"[Ak"УG B>}#G,XkqU$%%dW? PDǾN#aL& ${Pz޻;wd] 2]"bȐ!8wvv 'y<+/;::ALD'',,L&;w믿~= III&Lе,>TD"( AU(vvv> Bh4HD"( qJ0fU*a&2djD&BT*]7dL&LaaZ h42V{0򔔔+W$zP(S&%%ݻw[K|J '\@*[Ν;p+遁mmmǎ4iRyy\.P(bظ\*BR4P|>a++;w888HRcccH$ҤI^J6E ɓBa}.\ ._f`` ̪삃'x @Cter-N:/@iݻl6`aaannNR---ʪD"4110޽{ݒ`Fb1@RJAA^M'n5J%L0MѴ3>lj҈vW6%%eĉ---ږݻwEQUU5qĶŋs:ŤI"v9996l_P‰'i$**D"?^ׂK ׮]366 |=z4 ׯ1IӝP]]|/ҭ}r>}:a?xZ`.K"f͚eeeH$a??ڮfk'''Tp6nCoooPA+l#TSS3vخAL#F044T(VVVk׮~L&b30_U6ggnHa!ɮ_Nd@#lkIREJP(o߾֭[酅b&bL8QSS.k4be@<&Aojmmmooݚ}sEL`^HׯGEE999.8rDP*l6[{jLFZ(dɒ .,]t񶶶F,cr)T*r9!DNC*J| ̛7> z2tEKR-mܹ\.Z1[ IDAT cСd2p8+++CCCwwwVmmmj}ذa(X,&IPZ^Dbffյ>a[[!Vfff*LPXZZb$1'N\ svvvڢ8o޼9,,L"|wVVVׯ0ݻǏ:˗ӧOgXiiiwl۶rϞ=?vvv.))9s挓SeeLR__q|H evv3^N CQ455Uׂ O&**jǎ;vXti^^5kVZuIkkkSSS/O4tժU#G433ڳwt(0l0SSu}w4ѣGD1cZ_lffޮT*̙cnnnkkoͮ N>}ȑ-[޺u맟~JMM}wƌtݯs^|Y&]v-** & Մ;vBFQ__jooV mmmaaa%dӦM%%%O,o`Ѕ@6^6""9v\.葝G}UUU⧟~ڶmosĉZ;zhJJ 1,Lپ}X,622ںu@ ڼy3ðuֽ---{=w\ffGnݺ}UVnڴiĈNXXX{{;"3g<5\!&L`2ڐ{9ڵk*/R(ߺuٳL&3448ׯUT][lað߸qb7o޼}v71cX,-ޒ;w3>>></55UP"_"ٳ{7꧟~J>|8h9"J $tqq1446lFyA@_gffn۶̬ðYfUUUi +7mmmEEET*[nֆA>|foDEh@wvvn.*Ɉ6cǎ]ѣG o177/))quu=tPEEۻLMM'NӧO6Ç"6vZ"EBa@@(4񆆆roRSLʚ6m$$$^dԨQraX",Z믿tvv}Awttٳ'<<<88ܹs\.w„ [l}"f׬Y#҂aXqqq\\L&s\>ϻ P(t-sQTl6[QP(Z[[-,,t+pqq!ceɓ';w,**3f̚5k̊nܸiӦ۷߼yڵk]58s^zI8uTSSӕ+WH[nD@///H4~/^x.]͝>}\.n⒓/_x/jH$sСӧO BX.5k֘XCCѣG/[,$$=""---111fP(+Vݻ7777%%%66622rϞ=aaa~~~ d:uj޼yWxŋ;׬LT*T*jjj5j5֦q~/tdlmm}B hذaÇtiIIJ*--uttRϟWT3g433q<==J$OOϮI$R///L&ֶ-!!ABsܡC޹sV(>xÇ ֶZ*VTT\v&&&?k5h1bmNNNiiivtt,))h\KVSN-Zhҥ^LVRRuD7nA|>?99y„ ?ǫ"jkk=<N(Ǐo޼NL>ؙ?N{ȑna,(N2%##c?|~~~7n())qww׵,c(T}&2cǎ%,---~~~-b22LV 6ͭf$J;,P(`foG766j4LVVVfhh믿h[XX̚5o3f\uqqy7_l=/޾vZ1+9sfԨQ֭Ӊ#44ƍM B!WOsnggWSSC8KҀbg0*E̤RRlmm}-@5P `DO(p`=xĝQKKˈ#Q___L"^ڷ(J+zW=ZdrqFFFO ܴiӘ1c´i> .zJrɒ%/E+!C}:QjȐ!RT|>„ eeeDƇMmR&YUU~z6lذډ'nѣG8p`׭<Ç*((ӻ #.]211 Keee_5=t萮ey!jN.H&:55ɩ aCCCG||<ԩSĺ@P888 BU*D9'mF377hl6 "Y|ֱEQIN!2g2,bu-cg`bmm}1z뭮tE`` VgΜ9Lj^ZP|'ښM>TOfff_ں!CH$'''"-Akk+a2<ݻ˗//++뚆ԴC.pݻ$0uuu B[ @dWTDP Jmooh4\.\;)5BUDbe d2Y[[H$qLC+3gܹsΝ;###z(~WIIIW֡"7=|pNN kVȞ!R^֭[+++'M Zj5 M0,..HRY[[5y8?RW^>ظʊ{)6oaWW׏>l6[9gϞMOOY}ꨨv]H"._+>B033<08p@5^osmhh(**$''O2۷~hoo?w\nn.㝝 GGܬuojj:p3gJJJK"PO>}x*jH$N>0GGǠ .AСC.]'44EѳgJQ [~2ͿKJj ɓ'CBBt HdddRRRQQD"9sǏSk׮tvv,ںfff?SaaappmLLR/{'v6۷oʕiiiaaa{MOO=\.7n̙3Ǐ__>##c{%>{쒒|:;wnAAcǂ}ƍ۵k3`5kjBuV{{u|>k'?KKKLf}})=zŋՍ=Z]]M4;Vi<@9rcLjpuu!nNRRB fΝ?_dxrW* Ba^D6C`hl|淯v5xeccc;::ZZZ޸qĉ!!!qqq~~~'N7n{]]?L\]]I$ptt\dɝ;wlqΜ9wپ}{ttc}}=OIIqqq ]%--MV;::Qyi̙-]TPd29<<<3g])**ꫯ8 5 2NR/_sA?)ᨨ(SSS#áP(+Vr'OqBd*JhaÆر>3fLXXؔ)Sw!KK˝;wڒH$bUgYZZn޼:(((((crÆ MMM/---?3}f9sE\q}g: 5Aٍ˗/xLDFF`nnڵkhmmy8'N:аk.*zq][ 2N"<<<P(d,ݻ#FpBhh%M:u۶mRtܹ]Ln ;;D8;-[D^d)PG|^)C rJPPЍ7&LP^^+Iv9cƌ/_W/Ȍ3 82ygϞ?q:wdAѣGʽ$uQ,3033KNN7n"a:tӧ~޾D_̋𓉈mmm6lƲlл 2of .6wq_ B9{ݻAddɓ'u";~8͎)((y-Zh>3@p5cccm]?/[L:J;055@@ Oo?8&&fҥuuu~a1q}[]]v%%%EDD\vŋW^MII*u ݻwk[֬YcffGw4(((<<|̙ 2l:=q℥W_}GWȢlJm.\ u8 W*/>z(Q?AQt…ӧOOHH aXUUU<8^TTaaJhu3+ ^RBLZ=p8N]]]jjԩSz^>?gΜbWEEũSEded2ه~ק%UZ '? ͽ /**277?yyZ[[YA92z˗/ٳh5k֌3PYJejjkgg%JrV5SL~>Duuuٳg;wN$/^,,,?~W_}UQQ1sfNH$///>E(r\QɏB- >ڵkcƌpBpppw6`0C$hswwOJJ*++^Ff͚yeR5G1yxf^Tzܹٳg;99SÇ߿?h:]1ȔD"Y~tV###Rir/|ѣGw}566+;99EQtŊƍӺ|Wbd2_~e円ןz{N>GYFjkkܹ},lmmb.2Ȕ;&/3ʽ044|%KL ?}5k9r>`ܹÇonn&dff޻wWƟ3gN>% H?dbb駟ѼO~N˽{Fy>T' 2ABL&uWޯH?=,,֭#Nˍ7]P===KK>lxwtwd]ԘU IDATT;wN[ﭏ`0M Uʽax֭h˖->mhhx뭷zk+.\8qb׽;wW&6l[o+C,ό O1W}ʔ)K.I:3{ӧ"dʝL&O4O|j >zzX@)))MVbH$Ct;v2d?) L2y>] Zl?w{ ]vm߾YS\\\iiiddd8KҁAvXt]/űcǞپm677ލo>K.=Ï?8gΜޚn5>~x&Oh4zޮtvv>-N{TTTDDLbouҚ0aBYYY1 {2rXu^T###AH$?0Cpa úp@q, 0d2ܨœD"p0P8q0!1  &8 A8jHKkTHҲ/l]Cp9J|m0`1,pq 0 (6(ɓ'0AWrL}AGGQS͟Y>!--AIєB!pCD&,Y T~ O*A=Q0 ?X)51`5D`4D"kP5 !a;{Jwt'?uRJ$*R1 Vd2(LCJ2Ti(J)PYFA4 *U8 +UTJ&>"v|+5>=iٽ[0*4l&U*\T#D!V1! T60NEr`1"⪔B@bqܛ>%B&.SbI6S,c8 % $JRIF8F!,pC]$L\@)Q*j!WHp2V1ihF2)A5" aT 3$\Ag0rd%dQ1Lb2$r)ŒKlLR%Mɠe2*tb*fE't{NX-QEj5N$r NH,JՁV)T0d) ,wQ6R*2͖K0FMSPlxF#&v  tF)0  5Br5Cl,d2L$aR;;; HvAfsgٗ.]z^Gbjj @5@-{wy<Ayyymmmﯬ q0ǭy ҄Πt*qw2fHtN!pScڂà,ف^FlH{m&XYc,dP(3-LY.`4#hPD05 #0 (؁ֺRB d (U !.F ` 5DBJRTT&SFC42*52d݄O,G>=RH԰TJ0R1:&IT6(N!R 4H,c0j"3IJAL̬-&u_*Ucd:ȔT* r BHHfsrLfkTfPaT q4H`4*@8*`dKU :MRh,[͋~R QTX)U4 ,+ jdPPLM ERLpBCe!Bf1JJ(8¦"jC1Y,XHj!oktLp %a\a3J2P+:ErLsXtHHej`\ *Pj \*DlWQ2VE~r;Ίl^i[ K"*ADLb%F?-Q%Uc&x QŠҥwX7gv~ {nc]]{3ý<U4>$kpH."8`4MwJH;o}wI˻%y{c w(j[,:7„;A Gl&p p큼1j^S0:_|L58q8&q 4ѴJ)%Hd0cR¼q1QHI ')@4Cc $c2AQ$N<}Bu!b럑p0IB*LRI14F4j NQ88)YBZE#$3 %ŨI\@sf%Nt#*C0$JVT*Z´ZObQ4)ժIEQ& &D[Htb؅*$h>j=0.ۧ_藻?o8ոS˯=|*K8#Su9e @\1!Ô0 p{ٕOYl QE! HF Y00b{!$ubLX{U@єl@IF8$Z(!$Ep=$EI$ y>w FI<¿UV߿߾}ov-Yկ~j*EYfǎN#6mڤ+)?g?g}{;l6?G}QI>QnZ]]Aϗ1clذ{{1 1mڴiӦ]bral޼yҤIk֬mW,3~Ap)۲-FO?!K/1 s׎;{KQSRR^{5EQƍS"b0t666:u*33nAÑ}~'s7l믿7AӧOߺukJJ I~j-++뱼S}{N-Zz׮]rԽ?QSSF]0׿%+}뭷^b)((={_*24wP(֨;HbIHH8qNSn5kVoK֙'NTHEh4x=ĉeYv:IIIg>p`ZpFQv&L7%99yĉEEEO=TBB,˓&M 8Xb%7x$… /q;\s͠FC]~/Ydʔ)0VsFpeYޞGĉO:YuG.mx,,+ 鬱t:rH]]ݜ9skǦMRSSMj|:/6ߓT6(Baw2EtoV% !}˲t.4jQdYos֧ޱchu_p?|p0,(( wɎx|>AÇ?z=mcL,UUU|?oMZ1u26ŞV[Ade@o%n}_|?f !Xjo]ZZZPPE/̙3v5kۜӒG?ϟ?$-[wN:͛gZ{hNmߕ:ᄏm۶ͽxii9ߍ22>\].q/B}P[[9kmm=pgfʔ)H"g܍!,Xn$ͽ-vWܕ* Cw ~O܀߯[G'H磱ǧ E̠{ܿ=*mcBrVUٍG) Eɲ=SGGG[[[Vf :--uR\.eN]]ךQutry?իWLn,ł He˖./gNZp?k׮-8׬Yx }2QT H$qV`ϯ4t:|P(~ԨQ5Jb!V|ǎ4x"0Ox $}i}+fY+=l1-kkO}y4Ǎ,ZZZjkk+++iVN8h4FB>( B'vti JKKcGZg$zt{}bزeKTG[M6=Zq]=zRE SNav|Ipcc#M .t\ʈ,޽{Μ9ݻA(//߼ysQQQnnn;9^BlןL mmm&LHNNnlllhh *޽vD"sf8 wN+w}N|w<~x&=]{Oe9'779--/r NN9=?y r׬z kJlq/{qe*[.33Sr-+W,((سgO0|衇%~#GRRRqhmm}CP/NNN>~xv9w|ٲΝ;y_JYpM`oXJ4&L-?//`ds{3`+>iC"e˖-]4%t;E93gڵ+%%tXTTtR>~իWkZ].z~ҤIp8z(o֒%Kv V, 7|ɓ'-_| ØL&В%KK.MNNVt͛7K(*++[nc=,84ttt( 6L2ݻ7++K%K?!{g}v7'+Vhi_' IDATi1 Gms)S(iFc 0 /Raa_?`8eRSSw1}(lL|eBPoQɄi4\WW\lc3 K* NY랾8h~R8;;`0HQTd&It:Nzd h4 ٖcDz{_f͚|0jx￿cg|6mt'^'4ܟ[( = 8cǎhVK-b۳O<9f̘ΝpBjb |s]lYNN"@Rew$I?>55uƌ&I$/_V;f2;wӧ}>ߨQʔ &(S:s'EB>Atff2t抢8z蒒EB.J70Pi xQ:( (Jɓ'GHK./9k)Ql6[~%hjy8첲`0f͚[o5n_8>/\__'#m\ =ԍ p??n)dZwxo`z׫TKW^+(Бx5{ݗL1 iZwu?н>J۷ۻ$Gj੟yJ{FCHzg͚kjoooh41cFCCŋ7o;;CK6mHOOh4JTsiiUne$kjj8@^y=Ϙ1cXMMMav.7/]277w߾}7pC 6m,+O6 +p(jڴi] ܅'$I2 pT_/Y?8Qn0d_}ѢEo^^>x֯w 8,*T*T8臠}ͪ ]sv$軚^+lqVEG4iRTFF1X&~Û233ۑ5o^ðm=/n^k|n[p2F39{R&^bZ |AeWҨVPLC zO~eK$`yy}ʂJJHH>yB)+++VXo6eWYk";N%I1cnw429##7to߾fYSBm2k֬hصn(#a& 喑$ޕ<qYn΅(Z}466kl||!mK?U* /d AFyk1QKhݪބarַvQVu))) .,[RR 8DG$y-"y~FJJ̱̟~j_zhIO9Q{o(:zΝ;ϟ,DZZZ xջ}' %&&:NQU*UN|} *px(?h/_[R{N|Oʥ &s?6mѽgj5hӧ|#W>貈5 T- 甛]5FvvvCCy (pl+ ٻp7WlvRR((p8)@D9sDQljjSL8A0 KSr>J$Bpt:y6qiyLjі} Wj7 ?0$ 2{C˲|7P\MV̀0b)..ٲ,wɎx? K%B$I%ndɒ~4$)xΖ78#xV l6ZJ%qG#> 0**.(n!C=8Õ-0j8 w۽nݺ QF`f`GZ Mӗm\e1 ^ 6Napzd6w^\h](#殐9ൊl@qFZkllYĉ3` 'h dGrJQ]6mEׂ |'NT$B[lYpa'%cW_}u͚5wsh0m4%$I!΁\YY |>7M޽{`X/ZH;馛/h4o&aj3Bcƌey0*]bp߼yA;vZ~g,c+Ds_I/{r$q^*ρpp_u",c~9c :q+T5r06J( (eGmkkːp W_}u@;{gJzp G}7Mu.*KF`T}FJχc;/ }qSg0L\s͹ [.k_>3_nuZI`0{+Ds}sA_ g|cRW L@xY qNC8!U a1\Dyf5B 'TQSE_p,ƹB/2EQfǓxb JXkkĉq {ѣdc>9-\92kڿӲui l]5mU  9,8Of#h)H!N1JQ8ғus&enpg$|FE}}uƄ4/񧂮ٹ&%o?xɦ$hfMJUm\_n``7nZ^)5gZ~OӲ2 ."xcfch9C;ۯݲwԢ+BHB$+R$ Ig(B(Y60LV8 R H766h2̙s]XQӟ~.׿9SK* <ϯ]x0+)Yo\¶͙C=8atB 0 Tki߿e˖'ND"#Y nܼdpꫯ |4}]wرgig1=z]wݕ>zh>|!Ռ3x Qsrr꫍7s<9Bꜜ>}'?I3|3gNyyO=8:u;_ @Z~/ˊ#G9sFFM>=}]rJ:zhEEŮ]z衋l˔LI"˖-=zcǪjbMMM,gdd?^`0(Iү둭bq>k֬kv٣ \@Qw9^S56(TAY9ooo$I{+jkBQFQtmYU ֌#Inn$INkJJ\c |kkk{.G H5״)1# cǎ,s Ngp\.T8@Fj*a>yLGSSGsk1f5),#8no:uj߮]'m6xxs>hF=nȄ͛JgЖ-[ /nr@:y$˲P__ijp[[=PIo.sDNW_}qqq#GC+YNڟq z,VQW_bl;u-w77.h 70!0Cav[]--AoZ+WGV2(CaÆcǎݻjVUUaH裏|>Rl6_X,$ya;wLKKx<)))^7766JD,#b BFGn" h ôZmtf׿'Nd\uF< ΤjzΝn;X~5כo֩O>}Y:Fϴ^tݶ<(w>w qz~֭ 8ߟZn̙3JgϞt⋔Fܜr-/ K: 51sss_xe_ ,(&BGќ`vTZaƎ [X$"Fn!2π~LZpڼy<Dž{GF QSYQ_9cƏ|z۶mp04}Ŋ<3 GӴ,p ,TH$A(:ŌURR"˲$If؝2eʔ)Speyر8SqEQ5"1LOb6Sxh,aMe8sF0߻& rNy(_bũ˴$ի?zsH%͉93RC!I} ~.r?°szUE{ˠ?NEQeXU樂{VpzΝgTNHcoyChBqƹ^am/$=ڥ6J̼"{M&oa$ǎtҋlK #jo[1$&M I F, B.xÚsjUl4~߲{ #2 ͜ 2'6idPgN#ڰR]=&?+W>€a ydܐ+S*$uttpYYYFǏWR~>ʑ?MMMn[q*(((,,ܹ0!!a./Eb;@QjkKT$yIq݀IqNQg΄|Av;0B8jk;q[o}/N#-$΅9+\(ѣp8;;:::N:mE߷o˲ӟjjj^}՗^zih ^!Ӝuw4*MQ_D1ppFL,;+O쩯yk,q`0jP(T[[{}qwرrCg0rXQcT>] *NQ`PUSSTTdooG"$E) uCDP^p8!c&Lj4b$reef8UQ!sIH:Z[0pyI;']AD!1>˞{Ϧ($C;AUUU)n,_R&k۟~'NX`jwvo?J  Ð$rx뭷-Z4g%"/NeiZM[1f#x^D$C@h42tC! :]Q`1؁ IDATbBD9EPv'Z,khZǩjC@$TQ P(PѰ~(50}9&h cq]9_ 4YCkfLe:sܧJ2$G?3fD?ol?3M?c{xG`ܸq?8 4չZ[&Sݱc*T -v;aiii>EEt9.ܣ 2QE&r\brsʅ^ho?(pK0{܏>V3#q5sʀtңzvhX?NVd0Ӊ'$K\E ٹ$*O\J]XOo4F>jrg(ø rZNlnkmu9&izC@YY'|rA^^\A:\2 s=7Գ3(—(6BKeσ,޷D|Pۍґ$+~i cr?jA{8Cž/Ȃ A1ikj*(( VYfY`6Ru 8(J03s @,e>A fPgKJ @)K iO{l @Ӏ"cX3f IJJNnt8 :f8I"/`qI֮]':uj̘1?ϦN:ԓ#Ѵ-I& Y2B(<Y|(r'2E18t86)17[6-m)H1A9$.$)*STvnѣ$OUV6߾!Ñp6m8,SN4nԩk׮U/^u%I (jb}l~`y^㥧K$j4en΋WTDӴH2:{&(dYEMECq!6`YP(tXxAq +Ͱąq5w]vvڵk~sg=(++S*[.99=111VyeOcJ8l˨ ))D'?zd08 T>u?% j].J;_p'Oq~)S$%%;w>ʧZ6vD%7Ct W1$''씆H$BQd=,@16`tFcFFpI|n7q%%(::JA`uV+qPɓIʢh0-{Y~7W76FDQjmob J$^5jBi)˲--%%#3`(yp yhxרDgq᫶C\$~oٲ_׊+}+9?|0ydJ{kk1c1 3p8%%E߯v{RRӧ322DQʪiZ?0sr2Mϓ$IFG |__\xBpm;|Ø,V;&77Az@6XSLfa\^^JF pYy9M2@k["$)IJV+ N#11LqgHHHX|craj: T*YBA(^:JZ(qDQs8%!!!11gf͛7YIqi=12B!4:R'  4FIh4Jq8P#J۷m#RGܳG$9Ƴ%:8 h4 TRXh,y̙p($, ip!58qz!TYYSO):B~l6fgZl$I$axw:@]b,"ʿk*rff&q<_}UUU4MϜ93 :t$IV;s ,Qi]z^'H0$(JD Bdh4)RB؈fӹl$""0Jh: 657 O@^/mpq5DDn$80\0(r `X  AQ:NRx^>1 8p3g(ӧ'&&^LHOӻ;a„=XuubsP;a3>8~^?7p9s&;~x{Os^yvO "@ Ò H0aHHz@ b yÑVe:P;$aq0.tj&1+Ȓ ;{ dgnL{ Y'LV+aFJ`hs}>U*aђ$$*FIcA}H~v`fFaa; NVRv8U*y Bg0`m8 a|gPf?h1^Ȳ(uuu'NPv+**x%Kߑ={8&$OZAx^a :kIq[V~}Q}:07|s\233+++`GGEQNꫯƌo> #ۯO>WVV;v쩧y@KIV0,$'N3 fD!DiA!^&ht;ή_e{rf&3dRH# A *"Pz\^ r\.(H %4i)LSHdz9gΙkx2%LH$?kF\6"t]%#CDDžAFlWaDJa׻+$I,gҙt*4qJ P˵o}>/ )qx3qaΰ9 (=mk[|꺖2ao`YMnGyl"V EQ2MٹsgvOOqmmmGnMY|y[[ /K/ΝO|8 )b63!дiu}`ԧ>U~?OMӌkwnGrE[nNeG?,n(!(RJ939$!m0ftWyu0BF&=g2DQ4M|*lŢѓ-ydOݶm75k֔F({{>B9}$YΥ^zW_+H( pz==MǏnnj}%u\XaU8YQTt4e `0U(L&͖ө{wpѣGo?N*Adobb(Cx\.M-PQMV+0&p;#T|_~&_?FexzGovFʕ+cz#GYWDZ(>o۵z^/|YƳpWq5+N@4}뭷26Ȱ,q$ m;jU_s6/NfKrp8/I˒K/Ʉ@ `2):Q$d@hxi&CJ@@@!$_(@/bBZƞUXVHAB&SU],8 饗~ Κ5kƙ3mڴ{OSmmkk_,yoБHds,|76lg?nݺ\rIAOOo}W_}W_M$㹄+r}y>藾_T 0bllVŀz3¼}exg>S$% 57f[l6P4ʲL)UTƶFٳgz_}׭[3?e=hT5->ԷI U|]:/}{oh@ Pب,s=W򅞵T|dr'hp8;L>6x~;Ϩ_z?XJ$R)m,^x'߼yy l|O'J^… /_>]ʰcp{ʒdۛ'ٲ9y`n{4'rao.lnGV_?NDQ$*(gKBh…]Ľvڛos=*(@dLs!noXTUuvuu:rnVIb>!پ}>aÆRaұkT g5{CA[_(Ɲ)S߿ .X,.[0u6NT*f'Mbg(J%,|稆l`t%\y'{qjD B7 *UtlQxU)nXCLm}>͖h0 t};g8EK7 ʣHoђc|B#`\!(cx|bOώ-[i--"(>VodvB_q0d;v߸q eE͛7od`ƌ?/ts+/n*ERX,a cr|>_OOvR)mܛZ[[_ ->@eӡ2rJCcwpZk3V mv{2l͓'756_US8X,aBB$AY!E_>$i֭%I XjTnLf74֣e30V,̲a D B),#sL2wx<>oԩ.=HƝi*,B۷oܸq6lz}}իW\|c⊇~xƌ?O/_~yx]!veYJi.kll|ODdi{NeΟ?mt1*!:R3BVݵ-ӦEַߖhά=Z-Pq&YqUUB1%B(5,;Bj,on6q\ s:  ;B=}Gc`dY,prQB^!heY|.-<ZdlYCŸyDQ_~7| q܌3ڏ}cSL)W/g?>ą|Lc_09й 47͔ri`q] +ϣl֤iD.t:^tѶM\3(8NP_==]WUJRJ`)!i!@)%y2 F @:MϝN&3 qD(a'@4DkjXKn߱:e>H*'?T*/>۷oO&Az IDATVXqW\{`p] /6 'Ayve>c֬Sb1{Vg(d8jުˉ  `c[_=(QAZ3RBPss3PP{atJYEP d!%De@):wcS׫}>Yx<3R&a[t%?NHP a!:!D@EQL$Ҵ|2 I&Ef͚5ݥϋ/~vr-V7y^uUO?)z7Rg}ؓL&oW^y!vڟ6mՁ@]͟?KMg{F|;Fpڵn?yÆ b"]. Tfw2W6k,}eM9 BPXV|6r8d8do>H^S8eʡ7z, uÐϝxС}?O\s͆ F288(ʮ]Qڵkʕ+ꪽ{^~FP$Ip\jƍҡ8O,[lw;mڴS~زe˔)SKO<ڵk+}bQS?D͚MЏ~ێl:mQ}ч~W7ovTU=UQ͘bʦ#9 knZF0 0,<1 qc1FQr R)/bQePPY5I,ٳ-elOeɸ61^,iQJ)B&g*Ib.WfE,+0u}swyn={wyu~W>}͛M4n4mΝӧOonn^pa(ի3Lkkk<omm]vm>Jlܼx⁁믿_$IӦM뮻bX}}͛K]} MMMk׮E[n~/5D".S>c\rɽ|{޼yO?4}Y׮]ظb ;Ð/ߺuk}}0o???mذaǎ'O2eJSS믿}/yԧ?O3ɓ/ѣsփ>C+V8-+|7/EŔc5ŋ/Z}۶7~y緻/# /]seFXXgiFEՙL&Ո Ԩ`0F,9,PUMUYu]QUUuT]hkRTU4 !vd9<0 r@Q xWHU5aá"˚ EA麮p8hOx^>1A屔L&w. /}$_/X,t: B-zz-Ͷ|rBH<u_G?h41?gΜ_|^۱cG:={O{{=#>|zꩧ_|t[n%L4iʔ)֭x<ַjkkࠑ)3O~w}H$y槞zQn,Guu__sϞ=o`Y{2|xΝ<>7|skmm]dɤIJiʗ\rg7n8V*Qr-[쮻?~___yB=/$I#qm۶ ό,c 4,Ѱ.S* P,{b,#Kfj.oجYhTfm6[>7[,UPG[[QY&͖~h2VL'FR*I@g]!Bj&K*ITHXVS1V2nGQӅDH0FyøvGAWqRJ% Ah$R骪2uFfe[,s93U]uQ&f kq°DF̺u{tMnnzׯ__իW:th^{m~}-<<̏ӧXbEMM]~~_UnUU<ȱ|:mڴO_}jؿ$IRý^[[.rɉqڵk׭[uW;6H >+W~Ph۶mÖa_yO<į1oYa"رc~:bmLtckE FVR!p1%N( R)6}(3f[5~p'pmb>f}f< !Ju1Dz,ƐRM34C(8HDBfQ `A \Ƒc8@6Qn`9Y8 ,h4Lj0°쮝;cONdtZZZ.og>Jm__gW\^8 -Xnd nnG>0%\288x/X ]qͻ V\lٲt:=d^aÆ /pժU1l/̙s=\ p7e˖]wunᆃ.]tOfڴiUUU=w=cƌ_wuf'?+/~_*`,= Wհ'x[/M9:d*պej%_g/kcYf)!Jd`@eCzp… ;'WyQα,.[d'p83t2N$CCx\!D1JwttwvF Ƭɤ@HR"&44iƚB:=y7GL!eY,TU%P Tyl.ołXxb?Y»7_,j;ڰa /P,WX̟?w}93'|Re' wo}kɒ%{!xvmP讻[,nܸqƍ\.$i1]v١C6oެ(=3k,[nX,??XUUe2w+,X@Ӵ&ܹsTY4=BK#~o{߾}Gɔo yA s4_/q&R)0ɀf/X`wNnH$bX,X0JGޗo<SLٸq?_HI#2 r;sM&xt?AzYeyϾ}C55ar|*"!񁁡!B0v1fYBHU"n'Hm<_eb1r:X==O@vpx~YDMKg2bpy<UUuJ!DQ6s0˦p8,+>lzX,<ܹsOTB^xW_:uc`8q)B̲>eYJ@,m 63~y*Hz ԴGv}vF `_gg4 9ͨYgkN <_XYMihh=n7$$,'H$ !̲TUYU5 Cf!D"ayeys8aX q3񔞦cs+*mǚLp?&P`6!== Hqra֭==6?q8| B{_|?y8^6ՅB MMtF4/\0_|#g_O!% ӚCT Z,xrT>[׾S|0Ela|$CH&VWs6O&6%b8 H3erSSwww>W 9lv=t:D!oig3tƽBnݺuHёdjC@0z s n^fG0gabsyjQQt[{{{{{AK!c̔zVTEPBLt:nj%ѡRק)E)JA qٜd(D(L&:bH#C =YTUR ceIbBq.%Xjj:}z2t­ NX+LzN댉v<Oc 0Ehi!/mXXv뫯8K$82lɹ>jNɠCRJⰙ{g'#$LRUU1˖-;|]:L&EQ̂zi('*PU LJav;k2J|^eͦ(A$I/`Yv0R@J!&yjn*fh;(5zP`];Jܨ/LqP)SO,dt]͛'75UUUxr0ӓHbGGG6!KrVBEQ9'3^hX  ٳ{ AiZ6EAHQ\# uMuf cX0ÐBAd4ETb6V_  a NRo@)Bh64MD1JU (D4n5IrHDeI cM,LŸWprhw xa颪9|avjhIdJ@Y¿' @r\@o__XnoorI-->(!J0,,[ĸiyI~]UM328 BX,|u: &r9P(յVCØw8 !p8ɸ<E(&YѴeRʳlX>E(Hs9PelX!U BzKl6;q# *n N zK'qj}*:K! e3ɤn8zŋmVk&OE=ugDu: =Ȳ %X8 !fsdpdP:/Umh8g1>rh:SaAUUP( ( 6[8fv{ޚh,!$ "J&'lqPTcl,5T*%B6UU"{n8iήh4iq+I$˅bgs~H:x<KUUI5fΙw95<,kZuuW dY,qԟT{ (ggYayeTTR ﯫr%D FQ J riIHB)  ebٽgh<! 1*ǻ_z4RB B&6A@u@XS[ Yj2qX>ʩ ND$)S:,|>oNEΘ1c^U 'b& pRJ)SJ!]/z6J5drN  cBj(JRAAh4 c-K$% B8,x0JpdtEX^$ IDATVas΍ (jYb+z˫'x|BT2L뽽uuu;wgI UU)R0\f(,bQ"<{VX*~{֢iٳ *qYbh2 ?Ծz5p{6F#T8~ )lVE#T`z !]12X4)0Zx&d@$UUuM ^tJ -_ uM~)CȂll㡤 QEM<@YNfSd#tPIRl`+W,b+4BbPJ3gG}}}<EOrrÇK&clCںuX x?>C&)=X 2azlgUm5WϜ9Ssd:[D"aUU%bj_+>UՋSb*Fia;\.M)uy<͓'/YĨL$/>1088PO]EfaB,9].&g^es:|:.R`b*AS1N`0䦛nڻwo>/K,y7|>̙3ftvvΛ7e;vx%K`_z%cX<ώ;^C:;;=oqן+-T>}i?d1<z6ctñ /^׷ap$B( B.iD:-k|ߗ.vib)~28a|>(>__nߟN!AEU *ƽIqYf/d-Z绻Ng ,˯dھ}yb+H|WWv޽{GE<?|ԩS+rgaUXxB_ 4zEal6 mVk: :!BAVUFuMf}K0 7?3+L86oR>|JT.bZQa{*.ޝ)2Ee>DBuJ)!X,E#5Ljn/^l8w\,]jXlVdx2yr*|8qrhHuf0qcH(z=ٜdك9 4[-@f*Ap{Y:;;KILDbӦMbrL˗/ooo8n׮]dX,rϟxB&{+aUU򗿴GѺ`0uVJioo5kH#> x2Db/8ciy4]W5#<2sp@׬YSZ[[k,z!˲ .4"čșo|FBȻ k&Iz 7PJ>)n{͚5!C:{ժU!Êj(dtJ1B!fEQ%P)!!qg{7YUMs{.\[oeYI`st:uβsr tEQu`LNe?Ba!Ff+,fiϛBH)ڪ~U|P1NIUPLAI8)}5XG+իO"*(>TM+̞m64M TdYI&ul6e$@0 ʕ+#Ȇ?IS N%y]A`YB(2X4xX9"YQ0]'0GR͆16<3a8SB8g잮΃c!qp[ovG-Dw!C`Qp˨F@)y۫jZ*&kld7oْX,f@{]wfc5MSŘ[m6@iPuj25-[(D"y_b.dX,ڻo_I{Zl6Bȟ{ IDb+O>_bsnڴ:NTjvժU}}}MR/T/:TfyBd tPPfp P߯(J{{{NB͐a^{-NpxX,ZZZ6V:1.1m^ᤘ5kV8>ns9/ҢEJAX|9tBBBhԩglN.m!ѡΞbyW!pQoQ*r"b.-uT*sǎ(Sϝ?,DB,~() 8.ɤS)vx3땙{FFjV\Y!K3&"-2>hmb!4y1,LDXV+qb!BcnikҏɱBڏ 8a0Ʋ,3i%{(ˉ0 C)˲C9]I)䬣b+;F{;$I,*)^BU#TXx&%]O%۹O:jiMXk `ݮ2bYr,i3kl$,aE6qQ xYTТPU{[KE/Z-W^Xm ( !,gf~̏ܔMD8ghs,OKK8KBXEk+ Ewkd\bmmM 2LOOoĈl=Wj*f͚eaar ---B!:::&&&%566d2ق `uwL&rHUw!P_0yX,SQ jD ҈ X`P,EA[ۀ8;AC}1c( 11ؘմMChb*ܹ˓dyyyl6[*=Z*VWWO6ƍ #..А>|~ nXBQi*OTQB!AX,L(NgQE"Ar gε1 R C.)^T,3t--nj+nk~"x!L&S z`stL6a===CCCE߿?i$sss===w]]]iiikkY(}Z  (@Q_G-|dGGP`\.KBxeA0D<)9A;>2mb_(wo Ci Ν%P8(!F!J$Zx{;!`܈Ja.QV۝O6xR!:@ n,Oߙ4Wi;UzTh(Q|+}̧"? C )8'6{_ kxz{B( *,}x[-S~/rywq oDBӉ]%2h mi=r8=LUY\~k+@[H0Dm~a }h^\\aoHMMW@,0ҥK8_t /8^RRs~QQZ"Q(y =tg @>6ʰ'F@#1Cv{3C`.^III "==Ȋp222lmm߼yS[[{e@@IMMmkkc0G$&&5 Oi4۷ ϟ2@ oc*/W'ˆrV>&C~gՙad;4wH155DTe0!zO0APSԩSYtuuy<Ųhll$jR) 1cGGGpAB>-owO\e@GQ0}`*wI?g:;y/^ T&J;lnA;;;S[[[D2H@ܕT`]+7crjC4wB jwz<ާ/DyoP{Gym@s@ ]Oggۀւ~?`]RIRYX,hZZ,]]z@J566|>_P߃.Wj !Knn@5%H|}}ɚ?~|QQQwW>䓐jkkS!HJ˗/嗟~I.-#uuuAAAiii? .@ׯ'J$G0U0 3g0\nbbB;={l@WW޽{dP+pX@  ;rssq\@ 谏g8u.E_|m2d2wwwի666K---xT*=ztWOI+,44TAsSN& Κ㙙nnnW G666D=7o522|3&2JD"]]V6-H`ﱲ200V(=R^qvv~uSSCAAAg :::...dT*BPOOO l>/Sf̙kee%  !Cjj@N8._~]__ܳL@{EpppuuueeYrrrhh9͛cƌyرcLɓB:tR@KKKZZ̙3>S &LPQQ1rȊ hfffiD.K$FP(y=@޽+}||:\Ň {g#Bhcc󝉈nMdƶzLMAꫯ={Ҫ.//͈#lmme2YIIIss1clll̈!/^y5aP( ٳ '''.+E"kmmm8 *w0bXOO0---6=R\5Fc2D:##;۷oˆ b///D Huuĉ>|HNNNNNNʶ+VJ&&&~~~^裏D"D"144,))󳲲0ٳg b0,ww9sXZZL"ѣǎb <>0ŋ\B EѦ&"X,&T^d}mrABBB:P(r&L466dPmhhNtwUPpܱc\H$3 y!==H[[;0 {Gw ECC)3DR*L&knn9rdmkkS2>Ք孭]p8ƍcX |>_9 055U(//W9T*%CrNwib1q'S2qDz}} __߾܇#WSp999?ez̪CfBaff[:kkW^;B vqԩoI]rǏRf& zM6m۶.=P=;IS"1@k0XQQvڀ*jMMMEEÇoܸАɓFab֭[gϞ~ݻwM9L&aVDT^^NعsǏ.10hаg$}}jSSK.577[[[|ѣGmmmgޔ'OP(bEQ*P(4Y{VV͛5s0Lu}y :pX3-IDATD111MMMD͛---;d29677_tiCCuMM xOKK1SWW^YY}Ov %D\7nDDD۷Owdee233׭[G.9r;dXaؕ+WN8QQQ,>}5k{@<=Ez vL6 @J{{{CCÖX&{nu?~X&wA֭[ C,4$Gdgg^e2QQQ X`'O;vl@@يD")((ɓ'nܸ؛:rH ~N](0HP TVBsӚ*rv sn ՚'a8o۶FfCzHOOH$ӧO5gpYYYxx2ļA?,_MU$X}M͒\>tunbX(?AZ ''>>^yf zqff&q_֢/a0s@}x! 8p@uK* 3gT0H144xS6}-WWW%gdd"ɂ:::r\BCL m4n2H .7n׮]9;oήt",Xk쪧999$477wpɓ'._p`ڵ=ԙ4iҮ]& ~t%Hɓ'! du(PO3ҁ>\pvvyuڑ#Gv>_²2//D$߿ƍ;;;@IC hÈ~7nԐG8q2*eee!!!*j&99CɣG)6d(O?ŋ]^2Vb˖-+V\>jԨ(끼9ԭ[-[!xhmmP\RRf%;v]^g~hk׮QTaG*z7oܽ{WeggwĠaG 4aΝ;wIђÕ$ 9~wYNϟߺuk76"_p vNIIq\*LMM߼yC:HߐVVV]~uuuwrթ [m2r d2߾}61}#֯_s玲\&_zDm&44y!rʺ:5+!rdw}QoYJ q$IPPPLL̓T_tKzNXT%#B߲e`N " ["|,$>H$K.MJJIOO3f ي rNu޼yiiiNBQ4""BJz~I Z`D[Kdp8D&;;J@ ֭[a"AYIPPe;DL6,qppP/_lQSSC<~O?miiQr>4xzz @ABBIP!77I?s5hpXfp<<<VQ .9sf~~~bb"ZH… ƛ7o&[ @sjTVVzzz{zz޸qCGGlE5AR;wT&UM[*m۶|3܇3f̨/7<<<={vY@fffBBlB>t6m:v옦'={PÇ3G/wZZZdk!hC.\燇?~BÔ3f|駯_>|0Z˗o߾HLB Μ9!Ǐ-B2,ȑ#MMMdkQ "22AÇ]vX'&&fÆ 89s/&Yf =`kk矷ÁaS{؜9spg§Q9rl-P(?Iю;F  a|_rydd$ZYfEAhxx#G o޼(ٰa+W>}JA:tJWGaXxxSoݺGCW\.7<<|ԩdk,`>}9!!!ǏOOOW]pN:sNh?$ҠCz`:tm۶(Jg׮]"hӦM'u 322&N2rHA>ݳ2]p|Ϟ=dkDTVVedd̜9ݻ!B|_2l9ɁPuuu֢@sxⅧgff'͛dɒϟ>}l-ݻwƍN S^^뀀K.H TjTTTkk+r ؿ? }5˓'Odk0N>_x4%%͍lE 0hXaÆ#F;򰰰xss{M}bǎdk`N&MMMޗ.]1cݻwV+Jɖn"##QݵkZ>FSSgΜymu2{lJ?y$11qԨQW&[ˇ Q3#5 NHHf .9rg}6a„js88NaGAAUϟg``@"2Ԁn VZ #A Bd>ܹظ~sAg@ GO^TTmhh8mڴׯESWWכ<OyJP077755/|~/*/^ܸq#p>=p5k㄄///@С?k׮> {ѣGO>MRrȘ={kzzzr2^^^\.w_^5Uƍ:D={vŊ555^^^ dӭx<.{ WW˗gee0  r\T*H$7|{nX.D\<߯]v֭{8p@ٸH$R}!BP,Q89r$1~UVƍץ.啔<~8p8#ެT*D/KrEQD@||U0 e˖jB HiiElӧP(TCvvvMMɓ'Ν322b23f Rnӡd2PUx7\pBdgg8P(6mEѬnܸxPPʕ+MLL llmmM:ܼbŊ>lt:¢[lqttlhhq<555))abbd2׮]P(N8`ӧtb c  FPPD"9qŋMLL?'$$$899x<7u䤤$+++:L*BCCGwN7n\tܹsiii˗/oO8d"uBB?;;ym۶>%%%55B$442JǏWKJJ}}}e2T*]`\lپ}f͚uƍWM>}ƌ7oTz喖۷o[~k׮yzzUUUGFF677++0 :~С+֬Ys̙%KzxxL0aʕK. U ξz?Y~uu={222 EA&Nhoo/ ]\\T׭[qFE|}}.\m6777"$?/0lڴimmm0*=P0,55`ȑ/&iii˖-c0yyyeeeM8ʕ+-z*4iR~~>ӧO///olltuu}Izzu딡-*++ܹ#ΝKPڮ\ںhѢѣGzɩ͍&$$ggg777bh---.\5kI[[ԩSGGGT*vZCCڜo޼yٳE"˗e2leeUQQ!H&O[ZZ/Y.ph2,))ŋGgXb8;;>b2ׯ766ð;wO>A KKϟS(q]vϟ?ŋc,--EQtҤIH⢥uɓ'"ۢ"gggX\\\}zSSM,VyaXׯN"1&4j|%KzP(l6 BxfX Ãb):{aGDD>(JVQ%|~VVVaa{WUUw;w޽[)={|Eڵ_~O[kmmm]tX,ӧO/..&O>aɓsssZW([ʿ3b۷̙33f8wܮ]\Ml6`&f)rsscX|>Ã(>pD"jڧzB&.[/^xŊ2gygwܑJ V2xoIFQgϞ]ZZzWΝ;%Pr+**6o' `URRf͚8>OL8qرӟL&8py___Ht/"www'oܸA dX111";wp8fW~WE4ݵ^ɇ%INNݻwCCC+`X/^$>|alJxt|>_Vx<ZNSSS7mڴ~??v[nn)S~8sMF O[[[IUf===[ZZ<==y戈ɓ'}g&MR(~RRR~Cƍ6lX~~kUTT{---=ޯx W@ Xt){Ν+Wxyy-^lkk3(Gt428xNFJ@a`V閖zCӴZvssyNcXuuuT*MOO6dbŊ7nh4߿>P.駟jԉ'FGGGFFn߾]?~|ԨQ&o9EQB8|#GFAFDWT 33ܹsW\𨮮g__߫W޸qӆY+W?w}" u:7|bHWK(ٳ'%%f|aLOyy9EQFRJbX?s@@@[[ϟ={6û \̛7pj*2}gMϟ?c=oʠnh?JZ3f‘#GRR|5W^ ;:Y)4(*::ㅄk\^[[%S} @'YYbfҭGw//cő3HLwů?#vڵO`d/څP/@E?*mӀFh][%ѡƢ(ΣQBkF@ `~#xx !Uܽ@gUutP?+6\4 |@g0T`5ǁk-ZE8 @'ߏ?SP(*pp;j@ : ǀǀ hxM ~ $hqOeC'#h<#0?1G aE@(4+Je'0|3ǀ`$ 9,Ln)߀1΅=`fXj|y@Bk=a|wo@?Qq5 n5f~pw2f <4@^ac1d2{nkPqT 9 5 @<}~ǮX7냀6c׾C+@C/@TC;rw<_ x@eu m ;$.ʹRmpfe{IEuaO9j =_f&pVj.]-[Uߓ׷5eKOhib/2؜I#*6Kwl7q`Z`C U *ʠiPԖ@P CMu&q'x6>Lz NpZ ;7+ڹF NQˉ'.,]/k.ŗv0"ugarB?_zKlwg7D6@V]D F}RiKFue*ꮂ+M@; ځkMӪv揿ly^ʼ}vESZ[UʿϮ0N#z-!6,*忝뺯~ k 5F_c[F4@p=maZx@LR'İ&F5_EeKjzŢ|}x$޿f upԅjެg(6Bο[5-4#@x:,@Mh c"UϏ_ܿvޑ}eIPjlR&| W0J]%௲xgUu ӡXC:Yͫ @ёע> /W!l  0u ~T Pr DOX =loSkrq߽)n͢ /F6xh6͆w0hUS p"8G 1j.n @ @bݍWPR_V)i̸EnaVlN0 M:]`de/܀z1 0mBJ48XxxFx<eh:.5–8g4RVMZnSFs8_=Y,oAnh\+@Y9nEa3ĀP Pm[5 x ՊHIItcǮ)4R~u2nb;OypZ}cngkwd=TZںw#wt|fwы!8`q7)pxD<0 @% /t@gad F@\9.* 2@@+p n(@;0sŸ1N} CW8xzJc @pTCT/6t.3֕  ZP~ M@^տ{,Z6QL١@) `|5 |@ 7 `f5ٰO#"ɾh=  hZ``n,Kzo+:, S09>Εs'0$O7 %GK5:#~$2]qpK`,]]N8D]"KN8B/ 6x-f'ep*G52'8*2B [GA:LKŝ*2q'v.EQǏ7vy7cb:フ߻w)`L( {=}kvO?GY82v-GƎ%?gcnj]\|RYYryi lAuWHDFFN>}߾}C=3>>/0׃><e+Wh.+lr˗/߿?M_|+ o)2x@냂2hKw*P]]^ssa;vlɒ%KKK#""N:lٲr|O`8v9T\֨6G>k֬y1H]` ,Ǫ[NOOOícǎHMM%hWYbիW\bpsŋUʠ*C|o EQaaaϟDgΜhѢ7|!!!.]p 7Zg9 .<}ܹs- A39񈵙V 6Ell͛7{=>lٲ˗O26|322zFH$k֬h4ա7o*_&OBCJѣGi>qDss6RD"ݻiNOO 8s MH.IӴRϟi^裏hPSSCB͚I]m YZ$6oABB_Ԕl2uuuXL\zϠZhf ϴM#+V>}:--mL/"0}.徝69R:wܔ)Sz| m')1 [nEDDܺuK"w\ 6wJu; (ιPHp #c/w0,q vp\;8.1]qq]SWx]):Y} jv3 丹3FT`MWe`O]ζ5t>ʄ .u=3KXkB-[E"QRRk׮őEyzzzzz.Z8O4I,:tԚNРrUY3zmRXXzI5hkk ZxqCCV-//iZ& Ç4]PPpJKK-ϝI] ԕ_~ >ܤ~޽{СCl6ٟuYJ|…V??~ɶ4t[{U62] :w\QQQttرc/\`L9rcCCEQ{ٵk׮]&O,mHe 0X~KP(, B] ښ-{+ cƌ鮬ϙ3'887ިR*.\zjLwܱ9_;cU-l xyyy{{ҦJ0M%%%qqqnnnM+++ "$Iya\􀟺 [bnfmփ]tٝ,_8f ڿ# n+l]h=q vp\;80e'>8N vdJ0[(s F_1Ɨ`L~H8NNNNr hO)u:k[XŠOLW֭[g޿]W𯷿5U ܯ+ JǏ׮]PGeff޽{̘1^^^b899F(o7o[BBN;M{}+&ߝKތodddX'NǨRРw)o HΞ=?|Md l+'01 izԩɓ ɓ'e',/iRvGܟ 6te@D.r9:t(HJJJJJ S*&'(,`iqXB*=:;;Y`y%%%ˋ/h>%%@eebNNK,4iҥK;(L6mٲeqqqӦM8qٳ1}S7ݙ0Z.&M#ls *$x N.ۋV-TE`qN\aؤ$0VչPFEEI$GnԬYf ,PTRfR4v%X*֪TXҟ2d֭\.ƆpڮQ5552L* BВRjD" 0yEFFn۶ӱ{#O81k,///%NgQx뭷zMƤ9>?jCV €07 P"6^D"3{`[K{#{綾^JHH}v{{{AAڵkccc \a[&.-ݬ)3fXdZ&_@~ rdRD"a&E%'' ?W$9salq 7j4֭6lsss Ydɓ{gNZ^D" ޸qmCZS2@RZғʙ$ <̙3DؿjjjJJ?n޼yΝ/6QTw Ɵ>|pzzzHHHll… ̞=ㅇtN;5ۧ*;ilk̆6:::4k3$Ǐ'$$+555r.+._L y͛7GDDL<>4iIxtFvv6o;Hҿonnn޽{ɛ˼[E WPՆPLɅZnhL&KLL 49 $1yHN<uuu 1^%9555'o&D$TLMM54V ֒TJ'0y1SN ݱcV>x/iӦ>`ӦM>u޽{ ,#':jkk 555&uҵ&tRryllD":1MOO ߱cG'nnniiižO?-[l۶Gnnnttό3GmsJzSdK9sP(,**2vy<2"@D|2HD tIDATG&% Lf)hLvqTySN#6@D<2D-祉ҤDXڥ~w: " @T>,++7n,d2R,**(*&&&>>~lW ٵCd0UTTT#0LG Ud1,9 hEWr#.K`Al\Tv#lҝpaa]9@Nm[ęOuNVn^///75Vkc Ɨ1|;F~T\#V}Zqqq9H;Y%%%pHׯ"# [ y젫5rT,bSۙz·tlb^?7㇦-[x{{D$:nڴi{!?'M$:)w͛੧Z~=-3=,P,;رƷ' @YYMӭ(v1k,rL& tSZZj8]C84Mk4DfFS]]yft%`rJ^[͗cg_~ >pƍ;wLNN&1={VR_p履~2x6K:>|ڲeˢE&NwǠdYeBQe_|@Ptܹ۷GGG3&))iVRRرcCBBφ ɓb!wэa 3=CF;kKE 4z醆 =9o޼ydM6=w}wݺu~_W!!!ZСCC 1PXxK2[VVkxtn:lذ{4]YY0d@ HRSSOz瓓̙5| 6GD\-dY;e1S`c#lܲSNv-oμo!E0v#.K`%3Ytpa d9L6q>˙'/9的#t +=zk4Hf lZ=p8c777 xwvlrͼd۳͉1x/%v&۷ߟ[a9wN%O]!T|ݰGR|ڵkzݻw3K,'''ׯϞ=7¿IG.a=K l˂GdddX'Nlhh;wD4M{2hƞ%**@TZ? hWJѣGi>qDsssi ڣDNh,0APbU4mS 5`cU%' 8p؀Ҏ;kq@]N vp\;8.K`%q vp?8,JƳIENDB`amide-1.0.6/amide-current/help/C/legal.xml000066400000000000000000000031411423227705100202560ustar00rootroot00000000000000 Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to the below address. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to:
The Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
For more details see the file COPYING in the source distribution of AMIDE.
amide-1.0.6/amide-current/help/ChangeLog000066400000000000000000000001751423227705100200440ustar00rootroot000000000000002007.12.16 * converted to gnome-doc-utils.make setup for compiling help files * converted es translation to using .po file amide-1.0.6/amide-current/help/Makefile.am000066400000000000000000000004611423227705100203240ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in. include $(top_srcdir)/gnome-doc-utils.make dist-hook: doc-dist-hook DOC_MODULE = amide DOC_ENTITIES = legal.xml DOC_INCLUDES = DOC_FIGURES = \ figures/amide_main_window.png \ figures/study_tree.png DOC_LINGUAS = es DISTCLEANFILES = *~ */*~ amide-1.0.6/amide-current/help/README000066400000000000000000000001271423227705100171470ustar00rootroot00000000000000To check the validness of these doc's, run: xmllint --valid --noent --noout amide.xml amide-1.0.6/amide-current/help/amide.omf.in000066400000000000000000000004771423227705100204660ustar00rootroot00000000000000 user's guide amide-1.0.6/amide-current/help/es/000077500000000000000000000000001423227705100166765ustar00rootroot00000000000000amide-1.0.6/amide-current/help/es/es.po000066400000000000000000004062271423227705100176600ustar00rootroot00000000000000# translation of amide manual to spanish # Pablo Sau , 2002 msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2007-12-16 19:37-0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../C/amide.xml.translate:13(title) msgid "The AMIDE User's Manual V0.3" msgstr "Manual de Usuario de AMIDE V0.3" #: ../C/amide.xml.translate:16(para) msgid "" "AMIDE stands for Amide's a Medical Image Data Examiner. This program is a " "tool for viewing and analyzing volumetric medical imaging data sets, and has " "been designed from the ground up with support for multi-modality imaging." msgstr "" "AMIDE (Amide's a Medical Image Data Examiner). Este programa es una " "herramienta para ver y analizar datos multidimensionales médicos , y ha sido " "diseñado en el terreno de la imagen multimodalidad." #: ../C/amide.xml.translate:23(year) msgid "2000-2005" msgstr "" #: ../C/amide.xml.translate:23(holder) ../C/amide.xml.translate:47(para) msgid "Andy Loening" msgstr "" #: ../C/amide.xml.translate:28(firstname) msgid "Andy" msgstr "" #: ../C/amide.xml.translate:28(surname) msgid "Loening" msgstr "" #: ../C/amide.xml.translate:32(email) msgid "loening at alum dot mit dot edu" msgstr "" #: ../C/amide.xml.translate:38(releaseinfo) msgid "This is release 0.3 of the AMIDE User's Manual." msgstr "Revisión número 0.3 del Manual de AMIDE." #: ../C/amide.xml.translate:44(revnumber) msgid "AMIDE Manual V0.3" msgstr "" #: ../C/amide.xml.translate:45(date) msgid "2003-06-09" msgstr "" #: ../C/amide.xml.translate:65(title) msgid "Introduction" msgstr "Introducción" #: ../C/amide.xml.translate:67(title) msgid "Licensing" msgstr "" #: ../C/amide.xml.translate:69(para) msgid "" "AMIDE is released under the terms of the GNU General Public Library (GPL)." msgstr "" "AMIDE se ha liberado bajo los términos de GNU General Public Library (GPL)." #: ../C/amide.xml.translate:73(para) msgid "The text of the license is fairly verbose. A quick summary follows:" msgstr "El texto de la licencia es el siguiente:" #: ../C/amide.xml.translate:79(para) msgid "" "You are free to run the program, for any purpose. Please note that, although " "the GPL makes no restrictions on use of the program, your government " "probably does. For instance, in the United States, AMIDE is not FDA approved " "and cannot be used clinically." msgstr "" "Usted es libre de usar este programa para cualquier propósito. Por favor " "note que, aunque la GPL no hace restricciónes sobre el uso del programa, su " "gobierno probablablemte sí. Por ejemplo, en Estados Unidos, AMIDE no está " "aprovado por la FDA y no puede darse uso clínico allí ." #: ../C/amide.xml.translate:88(para) msgid "" "You are free to study the source code of the program, and adapt it to your " "needs." msgstr "" "Usted es libre de estudiar el código fuente y adaptarlo a sus necesidades." #: ../C/amide.xml.translate:94(para) msgid "You are free to redistribute the program." msgstr "Usted es libre de redistribuir el programa." #: ../C/amide.xml.translate:99(para) msgid "" "You are free to release modified versions of the program, as long as you " "also redistribute the source code to the modified program, and you label " "your modified version of the program appropriately." msgstr "" "Usted es libre de sacar versiones modificadas del programa, siempre que " "también redistribuya el código fuente del programa modificado, y etiquete " "apropiadamente la versión como modificada." #: ../C/amide.xml.translate:112(title) msgid "Availability of Source Code" msgstr "Disponibilidad del Código Fuente" #: ../C/amide.xml.translate:114(para) msgid "" "The source code for AMIDE is readily available from the AMIDE web site." msgstr "" "El Código Fuente de AMIDE está disponble en el sitio web de AMIDE." #: ../C/amide.xml.translate:122(title) msgid "Supported Platforms" msgstr "Platformas soportadas" #: ../C/amide.xml.translate:124(para) msgid "" "In addition to source code, binary versions of AMIDE along with installation " "instructions can be found for several systems on the AMIDE web site. The currently " "supported systems are Linux/i386, Microsoft Windows, and Macintosh OS X " "(achieved through the use of the fink add-on packages)." msgstr "" "Además del Código Fuente, las versiones binarias de AMIDE junto con " "instruciones de instalacion se pueden encontar en el sitio web de AMIDE web. Los " "sistemas soportados actualmente son Linux/i386, Microsoft Windows, y " "Macintosh OS X (logrado mediante el uso del paquete complementario fink)." #: ../C/amide.xml.translate:136(title) msgid "Contact Information" msgstr "Información de Contacto" #: ../C/amide.xml.translate:138(para) msgid "" "Questions and bug reports can be addressed to the AMIDE users list " "amide-users@lists.sourceforge.net. Information on joining the list " "and/or viewing archived messages can be found here." msgstr "" "Pueden dirigir sus preguntas a lista de usuarios AMIDE amide-" "users@lists.sourceforge.net . La informacion para unirse a la lista " "y/o ver mensajes archivados se puede encontrar aquí." #: ../C/amide.xml.translate:150(title) msgid "AMIDE Basics" msgstr "Fundamentos del Amide" #: ../C/amide.xml.translate:152(para) msgid "" "As the use of AMIDE is bound to be completely intuitive only to the one who " "wrote the program (i.e. me), this section provides a brief overview of " "operating within the program. It assumes you already have a data set loaded " "in. For instructions on getting a data set into AMIDE, see " msgstr "" "Com el uso de AMIDE es completamente intuitivo sólo para el escribió el " "programa (es decir yo), este sección proporcióna una breve panorámica de del " "uso del programa. se asume que tiene estudios cargados. Para ver " "lasinstruciones para cargar estudios en el AMIDE referirse a ." #: ../C/amide.xml.translate:163(title) msgid "A Quick Theory of Operations" msgstr "Teoría Rápida de Operaciones" #: ../C/amide.xml.translate:165(title) msgid "AMIDE Objects" msgstr "Objetos AMIDE" #: ../C/amide.xml.translate:173(term) msgid "Data Set" msgstr "Volumen de Datos" #: ../C/amide.xml.translate:175(para) msgid "" "A data set object contains the raw information from a medical imaging study, " "along with the corresponding parameters needed for interpreting that " "information (thresholds, colormaps, etc.)." msgstr "" "Un volumen de datos contiene la información cruda de un estudio de imagen " "médica, junto con los parámetros necesarios para su correcta interpretación " "con esa información (umbrales, mapas de color, etc.)." #: ../C/amide.xml.translate:183(term) msgid "ROI" msgstr "" #: ../C/amide.xml.translate:185(para) msgid "" "A region of interest object defines a volume of space over which statistics " "can be calculated. All ROI's in AMIDE are volumetric. Currently, AMIDE " "implements ellipsoid, cylinderical, rectangular, and isocontour based ROI " "geometries." msgstr "" "Región de Interés(Region Of Interest,ROI), este objeto define un subvolumen " "del volumen de datos sobre el cual pueden calcularse estadísticas. Todos los " "ROI's en AMIDE son volumétricos. Actualmente, AMIDE implementa las " "siguieintes geometrías en los ROI: elipsoide, cilídrico, rectangular, and " "isocontornos." #: ../C/amide.xml.translate:194(term) msgid "Fiducial Mark" msgstr "Marcador Fiducial" #: ../C/amide.xml.translate:196(para) msgid "" "A very simple object, fiducial marks encode only the location of a reference " "point in space, and are used for rigid body alignment." msgstr "" "Es un objeto muy simple , los Marcadores Fiduciales sólo tiene la " "información sobre la referencia a un punto del espacio, y son usadas para el " "alíneamiento de cuerpos rigidos." #: ../C/amide.xml.translate:203(term) msgid "Study" msgstr "Estudio" #: ../C/amide.xml.translate:205(para) msgid "" "Each AMIDE session has a single study object, which is used for grouping " "together a number of related data sets, ROI's, and fiducial marks." msgstr "" "Cada sesión de AMIDE tiene un simple objeto de estudio, que se usa para " "agrupar un número de volúmenes de datos, ROI's, y marcas fiduciales." #: ../C/amide.xml.translate:167(para) msgid "" "AMIDE can work with and display a large number of objects simultaneous " "(limited only be available memory). The object types current implemented in " "AMIDE are as follows: " msgstr "" "AMIDE pude trabajar y visualizar multiplicidad de objetos simultáneamente " "(limitado sólo por la RAM disponible). Los tipos de objetos actualmente " "implementados en AMIDE son los siguientes: " #: ../C/amide.xml.translate:218(title) msgid "Object Tree" msgstr "Objeto Arbol" #: ../C/amide.xml.translate:222(title) msgid "Study Tree" msgstr "Arbol de Estudio" #: ../C/amide.xml.translate:229(phrase) msgid "" "An example of a study's tree structure within AMIDE. The two data sets (FDG " "PET and microCT) and 1 ROI (bladder) are children of the study object " "(m2862). The remaining ROI's are children of the data sets." msgstr "" "Un ejemplo de árbol de estudio en AMIDE. Los dos volúmenes de datos (FDG PET " "y microCT) y 1 ROI (vegiga) son hijos del objeto estudio (m2862). Los ROI's " "restantes son hijos del volumen de datos." #: ../C/amide.xml.translate:240(para) msgid "" "In order to facilitate working with a large number of objects " "simultaneously, AMIDE conceptually groups all objects into a tree hierarchy, " "with the study object as the root of the tree (see ). Data set objects will generally be primary branches off of the " "study object, while ROI's can be branches off of the study object or off of " "individual data sets. Why is this important? Because the structure of the " "tree determines how movements are mapped within the program. If a data set " "is moved relative to the rest of the study, the ROI's that are branches from " "that data set object will be correspondingly moved, so that they will " "maintain the correct orientation and position with respect to the data set " "that is their parent." msgstr "" "Para facilitar el trabajo con un gran número de objetos simultáneamente, " "AMIDE conceptualmente agrupa todos objetos en una jerarquía de árbol, con el " "object estudio como raiz del árbol (ver ). " "Los objetos de volúmenes de datos serán ramas principales del objeto " "estudio, mientras que los ROI's pueden ser ramas del objeto estudio o de los " "objetos de volúmenes de datos. Por qué es esto importante. Porque la " "estructura del árbol determina como los movimientos son seguidos por el " "programa. Si un volumen de datos es movido con respecto al resto del " "estudio, los ROI's que son ramas de ese volumen de datos son movidos " "acordemente con aquel, así se mantendrá la correcta orientación y posión con " "respecto al volumen de datos padre." #: ../C/amide.xml.translate:255(title) msgid "Real World Units" msgstr "Unidades del mundo real" #: ../C/amide.xml.translate:257(para) msgid "" "An important thing to realize when working with AMIDE is that the program " "will try to abstract away the underlying digital format of the data as much " "as possible. When you listen to digital audio, the CD player automatically " "converts the series of 0's and 1's encoded on the compact disc into an " "analog format so that you don't have to worry about the underlying digital " "format. Similarly, AMIDE presents the digital data to you in analog form. " "When ever possible, units are given in terms of real world units (e.g. mm's, " "seconds), and most operations are not constrained by the discrete nature of " "the underlying data. For example, data in AMIDE is viewed in terms of " "\"slices\", not fixed image planes. These slices can be taken from the data " "set at arbitary angles, and can be of any thickness (they are not " "constrained to be integer multiples of the underlying voxel size). You may " "be used to looking at medical images in terms of voxels and integers, but " "remember that the object or subject scanned is an item in the real world, " "and AMIDE tries to recreate this \"analog signal\" for you." msgstr "" "Es importante darse cuenta trabajando con AMIDE que el programa intentará " "abstraer el formato de sobreimpresión digital tanto como sea posible. Cuando " "eschucha un CD de audio, el reproductor convierte automáticamente una serie " "de ceros y unos codificdos en el disco en formato digital, y así usted no " "tiene que preocuparse del formato digital subyaccente. De manera similar, " "AMIDE presenta los datos digitales de forma analógica. Siempre que sea " "posible las unidades empleadas son unidades del mundo real (mm, seg..), y al " "mayoría de operaciones no estan limitadas por la la naturaleza discreta de " "los datos subyaccentes. Por ejemplo, los datos son vistos en término de " "\"cortes\" y no de planos fijos de imágenes. Estos cortes pueden extraerse " "del volumen de datos en cualquier ángulo, y con cualquier grosor (no sólo " "limitado a múltiplos del tamaño del voxel). Usted pude estar acostumbrado a " "mirar las imágenes médicas en términos de de vóxeles y de enteros, pero " "recuerde que el sujeto escaneado es parte del mundo real, y AMIDE intentará " "recrear esta \"señal analógica\" para usted." #: ../C/amide.xml.translate:276(para) msgid "" "The only place the abstraction starts to break down is when dealing with " "dynamic data sets. Einstein understood time to be a \"special\" dimension, " "and AMIDE agrees. The reason for this, is that trying to represent dynamic " "data as anything but separate frames of data becomes overly complex from a " "computational standpoint, primarily because dynamic data is generally not " "equally spaced. While moving 1 voxel in the x, y, or z directions will " "always move you a constant unit of measurement (say 0.4 mm) in the " "appropriate direction, moving 1 voxel in the t direction may move you 30 " "seconds or 30 minutes in time, depending on what frame you're looking at. " "Because of this, AMIDE deals with dynamic data in terms of frames, although " "it should always tell you the time that those frames correspond to." msgstr "" "El único sitio donde la abstracció empieza a romperse y cuando se trabaja " "con volúmenes de datos dinámicos. Einstein entendió que el tiempo es una " "\"dimensión\" especial, y AMIDE está de acuerdo. La razón de esto es que " "intentando representar datos dinámicos pero en segmentos de tiempo separados " "resulta complejo desde el punto de vista computacional, primeramente por que " "los datos dinánicos no suelen estar igualmente espaciados. Mientras que " "moverse en el espacio 1 voxel en las direciones x, y o z siempre equivale a " "una unidad constante de medida (por ejemplo 0.4 mm) en la dirección " "apropiada, mover un voxel en la dirección t puede ser de 30 segundos o de 30 " "minutos, dependiendo que segmento de tiempo este mirando. Por esto, AMIDE " "trabaja con el tiempo en términos de segmentos (frames), aunque AMIDE " "siempre nos dirá el tiempo al que corresponede cada segmento." #: ../C/amide.xml.translate:303(title) msgid "Components of the Display" msgstr "Componentes del Display" #: ../C/amide.xml.translate:306(title) msgid "AMIDE Main Window" msgstr "Ventana Principal de AMIDE" #: ../C/amide.xml.translate:313(phrase) msgid "A diagram pointing out the salient features of the main window" msgstr "Diagrama señalando lo más destacable de la ventana principal" #: ../C/amide.xml.translate:320(title) msgid "Context Sensitive Help" msgstr "Ayuda Sensible al Contexto" #: ../C/amide.xml.translate:322(para) msgid "" "Located in the lower left corner of the window, the context sensitive help " "window shows what different mouse buttons and key strokes can accomplish " "given the current cursor position. Note that mouse buttons are labelled in " "UNIX fashion. Buttons 1, 2, and 3 correspond to the left, middle, and right " "mouse buttons, respectively. Under Macintosh OS X, the middle and right " "buttons are emulated by pressing the option key or the open apple key, " "respectively, while pressing the mouse button." msgstr "" "Localizada en la esquina inferior izquierda de la ventana, la ayuda sensible " "al contexto mostrará que lo que sucederá al apretar los diferentes botones " "del ratón o las combinaciones de teclas. Los botones estan marcados a la " "manera UNIX, correspondiendo el 1, 2 y 3 a izquierdo, medio y derecho " "respectivamente. En los ratones con sólo dos botones, el del medio es " "emulado apretando los dos botones a la vez." #: ../C/amide.xml.translate:336(title) msgid "Tree View of Study Data" msgstr "Vista del Arbol de Datos del Estudio" #: ../C/amide.xml.translate:338(para) msgid "" "Located on the left side of the window is a tree listing of all the objects " "in the study. The tree structure shows how movements will be propogated to " "other objects in the study. For instance, if a data set is rotated, all of " "its children will be correspondingly rotated." msgstr "" "Localizado en la parte izquierda de la ventana esta una árbol que lista " "todos los objetos del estudio. La estructura de árbol muestra como los " "movimientos serán propagados a los objetos del estudio. Por ejemplo si un " "volumen de datos es rotado, todos sus objetos hijos serán rotados " "acordemente." #: ../C/amide.xml.translate:344(para) msgid "" "Objects in the tree can be selected for display by left clicking on the name " "of the object. Middle clicking on a data set will make that data set the " "\"active\" data set. The \"active\" data set is designated by being " "highlights, and when a function is chosen that can logically apply to only " "one data set (e.g. filtering), the active data set is the one chosen." msgstr "" "Objetos del árbol pueden ser selecionados con pulsación en el botón 1, en el " "nombre del objeto. Click en el 2 \"activa\" el objeto. El \"volumen activo " "de datos\" aparecerá remarcado, y cuando se una selecciona una función (por " "ejemplo un filtro), esta será aplicada sólo al \"volumen activo de datos\"." #: ../C/amide.xml.translate:351(para) msgid "" "Object modification dialog boxes can be brought up by right clicking on the " "corresponding object. ROI's can be added by right clicking on the blank area " "of the tree, or shift-right clicking on one of the objects. These functions " "are further described in and ." msgstr "" "Al diálogo de modificación de objetos se pude acceder con el botón 3, " "haciendo pulsación sobre el objeto, correspondiente. Los ROI's se pueden " "añadir haciendo pulsación con el botón 1 en un área desnuda del árbol, o con " "MAYUSCULAS+botón 3 en un objeto. . Estas funciónes se describen con mayor " "detalle en and ." #: ../C/amide.xml.translate:359(title) msgid "Orthogonal Views" msgstr "Vistas Ortogonales" #: ../C/amide.xml.translate:361(para) msgid "" "Most of the main window display consists of the orthogonal views used for " "visually displaying the data sets being studied. Data is usually presented " "as three orthogonal slices taken from the data sets, but the user can choose " "to display fewer of these views if desired by using the view selector " "(described below in ). The three views " "shown are the transverse, coronal, and sagittal planes. Note that the views " "may be incorrectly labeled for you. This could be because the data in the " "file you imported was not in the order that AMIDE expected it to be in. It " "could also be because you want to use the transverse/coronal/sagittal " "terminology differently then the program does (e.g. a coronal section of a " "rat brain is not the same as a coronal section of a rat)." msgstr "" "La mayoría de la ventana principal corresponde a vistas ortogonales del los " "volúmenes de datos a visualizar. Los datos usualmente se presentan como tres " "vistas ortogonales, pero el usuario pude decidir usar menos, usando le " "selector de vistas (descrito abajo en ). " "Las tres vistas mostradas son los planos axial , coronal, and sagital. " "Nótese que las vistas pueden aparecer incorrectamente marcadas. esto puede " "ocurrir si si el fichero importado no esta en el orden que AMIDE espera. " "Podría ser por que usa una terminología diferente de orientación al la del " "programa (por ejemplo la sección coronal del cerebro de una rata no es la " "misma orientación coronal de la rata)." #: ../C/amide.xml.translate:376(para) msgid "" "Below the views are sliders for adjusting where in the data set the slices " "are being taken from. The location can also be changed by directly clicking " "on any of the canvases. The appropriate mouse clicks are as follows" msgstr "" "Bajo las vistas hay barras desplazables para cambiar el lugar de donde las " "vistas son tomadas. La localización también puede cambiarse haciendo " "pulsación directamente sobre imagen de la vista. Las pulsacións de ratón " "apropiadas son:" #: ../C/amide.xml.translate:384(term) msgid "Left Mouse Button" msgstr "Boton 1 del ratón" #: ../C/amide.xml.translate:386(para) msgid "" "Changes the location in the data set that the slices are taken from, without " "changing the thickness of the slices." msgstr "Cambia localización de los cortes sin cambiar su grosor." #: ../C/amide.xml.translate:391(term) msgid "Middle Mouse Button" msgstr "Boton 2 del ratón" #: ../C/amide.xml.translate:393(para) msgid "" "Change the location in the data set that the slices are taken from, along " "with setting the thickness of the slices to the minimum reasonable." msgstr "" "Cambia la localización de los cortes, poniendo el grosor de los cortes a un " "mínimo razónable." #: ../C/amide.xml.translate:400(term) msgid "Right Mouse Button" msgstr "Boton 3 del ratón" #: ../C/amide.xml.translate:402(para) msgid "" "Clicking an dragging with this button changes the thickness of the slices " "without changing the location. The thickness of the viewed slices can also " "be altered by adjusting the slice thickness setting spin button (see )." msgstr "" "Haciendo pulsación y arrastrando sin soltar cambia el grosor de los cortes " "sin cambiar su localización. El grosor de los cortes también puede alterarse " "con el botón rotatorio de ajuste de grosor de corte (ver )." #: ../C/amide.xml.translate:412(term) msgid "Other" msgstr "Otras" #: ../C/amide.xml.translate:414(para) msgid "" "Additional functionality of the mouse buttons for manipulating data sets and " "ROI's is explained in and " msgstr "" "Funcionalidades Adicionales de los botones del ratón se explican en y ." #: ../C/amide.xml.translate:425(title) msgid "View Selector" msgstr "Selector de Vistas" #: ../C/amide.xml.translate:427(para) msgid "" "Which of the three orthogonal views are shown can be selected by using these " "toggle buttons. By default, all three views are shown." msgstr "" "Cual de las tres vistas ortogonales se puden selecionar usndo esos botones. " "Por defecto las tres son mostradas." #: ../C/amide.xml.translate:434(title) msgid "Linked Viewing" msgstr "Visión Sincronizada" #: ../C/amide.xml.translate:436(para) msgid "" "In addition to the three orthogonal views, AMIDE can display mutiple sets of " "these orthogonal views, all looking at the same point (\"linked\") in three " "dimension space. This is most often used for looking at fusion images of two " "data sets, with one set of views used for the first data set, the next set " "of views used for the second data set, and the third set of views used for " "the fusion of the two data sets." msgstr "" "Además de esas tres vistas, AMIDE pude mostrar múltiples conjuntos de vistas " "ortogonales, todos mirando al mismo punto (\"sincronizado\") del espacio 3D. " "Esto se usa más a menudo para ver la fusión de dos volúmenes de datos, con " "un grupo de vistas del primer volumen, y el siguiente usado para el segundo, " "y el tercero para la fusión de los dos volúmenes." #: ../C/amide.xml.translate:447(title) msgid "Thresholding Tool" msgstr "Herramienta de Cambio de Umbral" #: ../C/amide.xml.translate:449(para) msgid "" "This button on the toolbar will pop-up a thresholding and colormap selection " "dialog for the currently active data set. In the dialog, the maximum and " "minimum thresholding levels can be changed by either directly typing in the " "values (in absolute or percentage units), or by using sliders on the color " "bar. The color scale can be changed using the corresponding drop-down menu. " "A log normalized histogram is shown to give an idea of the distribution of " "the data set's value. Finally, the thresholding type can be changed. The " "thresholding type determines how the maximum and minimum threshold values " "are applied to the data set, and are:" msgstr "" "Este botón en la barra de herramientas lanza el selector de mapas de color " "del volumen de datos activo. En el diálogo, los niveles máximos y mínimos de " "umbral pueden cambiarse directamente escribiendo los valores (en unidades " "absolutas o porcentage) , o usando las barras de desplazamiento en la brara " "de color. La escala de color se puede cambiar usando el correspondiente menú " "desplegable. Un histograma normalizado da una idea de la distribución de los " "valores del volumen de datos. Finalmente el tipo de umbral se puede cambiar. " "El tipo de umbral determina como los valores de umbral mínimos y máximos se " "aplican al conjunto de datos, y son:" #: ../C/amide.xml.translate:464(term) msgid "Per Slice" msgstr "Por Corte" #: ../C/amide.xml.translate:465(para) msgid "" "The max and min threshold values will be applied in proportion to the max " "and min values in the current slice of data" msgstr "" "Los valores mínimos y máximos se aplicarán en proporción al corte " "selecionado." #: ../C/amide.xml.translate:470(term) msgid "Per Frame" msgstr "Por Marco" #: ../C/amide.xml.translate:471(para) msgid "" "The max and min threshold values will be applied in proportion to the max " "and min values in the current frame of the data set" msgstr "" "Los valores mínimos y máximos se aplicarán en proporción al segmento de " "tiempo selecionado." #: ../C/amide.xml.translate:476(term) msgid "Interpolate Between Frames" msgstr "Interpolación entre Segmentos de Tiempo" #: ../C/amide.xml.translate:477(para) msgid "" "This threshold mode only makes sense for dynamic studies. In this mode, two " "sets of max and min threshold values are specified, along with which frame " "of data each of these sets corresponds to. For data frames before and " "including the first reference frame, the first set of threshold values are " "used. For data frames after and including the second reference frame, the " "second set of threshold values are used. For data frames between the two " "reference frames, the max and min threshold values are derived by " "interpolating (as a function of time) between the two sets of thresholding " "values." msgstr "" "Este umbral sólo tiene sentido para estudios dinámicos. En este modo dos " "pares de valores máximos y mínimos son selecionados para cada segmento de " "tiempo. Para cada segmento anterior e incluyendo el primer segmento " "seleccionado se usa el primer par de valores. Para el segmento segundo y " "subsiguientes se aplica el segundo par de valores. Para los segmentos " "incluidos entre el primer y segundo segmentos seleccionados los valores " "máximos y mínimos son interpolados como función del tiempo entre los dos " "pares de valores establecidos." #: ../C/amide.xml.translate:491(term) msgid "Global" msgstr "" #: ../C/amide.xml.translate:492(para) msgid "" "The max and min threshold values will be applied in proportion to the max " "and min values in the entire data set" msgstr "" "Los valores mínimo y máximos serán aplicados en proporción al los valores " "mínimos y máximos del conjunto total de datos." #: ../C/amide.xml.translate:499(para) msgid "" "If the data set's modality is set to CT, buttons will be shown for applying " "bone and soft tissue windows as the thresholds." msgstr "" #: ../C/amide.xml.translate:507(title) msgid "Zoom Selector" msgstr "Selector de Zoom" #: ../C/amide.xml.translate:509(para) msgid "" "This specifies how much to enlarge the views. AMIDE tries to make an " "educated guess about how large the display of the data should be, by using " "the smallest voxel dimension from the data set with the largest voxels to " "correspond to a displayed pixel. Zoom can be used in addition to that " "guesswork." msgstr "" "Este especifica cuanto se magnificarán las vistas. AMIDE intenta hacer una " "educada adivinanza de cuan grande han de ser las imágenes usando la " "dimensión más pequeña con los vóxeles más grandes correspondiendo al pixel " "representado. El zoom se pude utilizar en adicció a esto." #: ../C/amide.xml.translate:519(title) msgid "Slice Thickness Setting" msgstr "Ajuste del Grosor de Corte" #: ../C/amide.xml.translate:521(para) msgid "" "Thickness specifies how deep the slices displayed on the views are. The " "minimum slice thickness is determined by the smallest voxel dimension of any " "of the data sets in the study." msgstr "" "El grosor especifica cómo de profundas han de ser la vistas representadas. " "El grosor de corte mínimo viene determinado por la dimensión del voxel más " "pequeño del conjunto de datos." #: ../C/amide.xml.translate:530(title) msgid "Frame Selector" msgstr "Selector de Segmentos de Tiempo(Frames)" #: ../C/amide.xml.translate:532(para) msgid "" "This button pops up a dialog for picking which frames of data to show from a " "dynamic data set. A frame (i.e. time period) to display can be selected by " "clicking on a list element. Multiple frames can be selected by holding down " "the shift key and selecting additional frames. Note, that for each data set " "selected for view, at least one frame from that data set will be displayed. " "If the choosen time period does not encompass a frame from that data set, " "the closest appropriate frame will be choosen." msgstr "" "Este botón abre un diálogo para seleccionar el segmento a mostrar de un " "conjunto de datos dinámicos. Un segmento (p.e. periodo de tiempo) para " "mostrar puede ser seleccionado haciendo pulsación en una lista de elementos. " "Múltiples segmentos puden ser seleccionados a la vez con pulsación y " "simultáneamente apretando la tecla MAYUSC para seleccionar segmentos " "adicionales. Nótese que por cada conjunto de datos seleccionados al menos un " "segmento será visulaizado. Si elige un periodo de tiempo que no incluye un " "segmento de tiempo de ese conjunto de datos, el segmento más aproximado será " "elegido." #: ../C/amide.xml.translate:545(title) msgid "Gate Selector" msgstr "" #: ../C/amide.xml.translate:547(para) msgid "" "This button pops up a dialog for picking which gates of data to show from a " "gated data set. A gate to display can be selected by clicking on a list " "element. Multiple gates can be selected by holding down the shift key and " "selecting additional frames. Note that by using the entries, a span of gates " "can be choosen that loops around (e.g. gates 8, 0, and 1)." msgstr "" #: ../C/amide.xml.translate:557(title) msgid "Target Selector" msgstr "Selector de Puntero(Target)" #: ../C/amide.xml.translate:559(para) msgid "" "The target cross hairs are generally only displayed when one of the mouse " "buttons is depressed. With this toggle button, you can tell the program that " "you want the target cross hairs left on the views." msgstr "" "El puntero en forma de cruz generalmente sólo resulta visible cuando " "apretamos un botón del ratón. Con este botón la cruz permanece siempre " "visible." #: ../C/amide.xml.translate:567(title) msgid "Interpolation" msgstr "Interpolación" #: ../C/amide.xml.translate:569(para) msgid "" "Interpolation refers to the method whereby AMIDE extracts data from the " "original medical imaging data set in order for it to be viewed on the " "screen. The interpolation selection button lets the user specify what type " "of interpolation to use when generating slices from the active data set. " "Nearest neighbor is faster, while tri-linear interpolation produces better " "looking (smoother) images with the penalty of being ~8x slower." msgstr "" "Interpolación se refiere al método con el que AMIDE extrae datos del " "conjunto de datos de imagen médica original para ser representados en " "pantalla. El botón que seleciona la interpolación permite al usuario " "especificar que tipo de interpolación usar para generar cortes del volumen " "activo de datos. \"Nearest neighbor\" es el más rápido, pero tri-línear " "produce imágenes de mejor aspecto, con la penalización de que es casi 8 " "veces más lento." #: ../C/amide.xml.translate:581(title) msgid "Fusion/Overlay Selector" msgstr "Selector Fusión/Sobreimpresión" #: ../C/amide.xml.translate:583(para) msgid "" "By default, AMIDE displays multiple data sets as fused images. With the " "fused/overlay selector, you can tell AMIDE that you want the active data set " "to simply be overlayed on the other data sets, rather than fused." msgstr "" "Por defecto AMIDE muestra múltiples volúmens de datos como imágenes " "fusionadas. Con el selector fusión/sobrimpresión(fused/overlay) usted elige " "si quiere mejor los volúmenes sobreimpresiónados mejor que fusionados." #: ../C/amide.xml.translate:590(title) msgid "Preferences Dialog Box" msgstr "Diálogo de Preferences" #: ../C/amide.xml.translate:591(para) msgid "" "Underneath the edit menu is the preferences menu item. This will pop-up a " "dialog box that allows you to change preferences as to how things in AMIDE " "are displayed. The preferences will be saved in a configuration file for use " "by future AMIDE sessions (note: saved preferences are not currently " "supported on MS Windows)." msgstr "" "Debajo del menú de Edición esta el de preferencias. Este desplegará un menú " "de como las cosas deben de ser mostradas por AMIDE. Las preferencias se " "guardaran in un fichero de configuración para su futuro uso en AMIDE." #: ../C/amide.xml.translate:602(term) ../C/amide.xml.translate:1543(term) msgid "ROI/View Preferences" msgstr "Preferencias de Dibujo de ROI" #: ../C/amide.xml.translate:603(para) msgid "" "Here are several preferences for changing how ROI's are the view canvas are " "drawn, more thoroughly described in . Note " "that these preferences are only used when a new study is created. To change " "these preferences for an existing study, you need to use the study " "modification" msgstr "" "El grosor de la línea para dibujar ROIs pude ser cambiado aquí. El grosor " "oscila entre 1 y 5 pixel." #: ../C/amide.xml.translate:612(term) msgid "Threshold Windows" msgstr "Preferences de la Disposión de las Vistas" #: ../C/amide.xml.translate:613(para) msgid "" "The window preferences are more throughly described in . Note that these preferences are only used for new data sets. " "To change the window levels for an existing data set, use the data set " "modification dialog." msgstr "" "La primera opción le permite usar tres vistas (axial, coronal y sagital) con " "un estilo lineal usualmente usado por los software de PET, y un estilo " "ortogonal usado por el software de RNM. La segunda opción le permite fijar " "si el tamaño de la vista ha de permenecer constante o no. Si no esta " "activada, el tamaño de las vistas mostradas dependerá sólo de los volúmenes " "seleccionados. Si esta activada, el tamaño del las vistas dependerá de todos " "volúmenes del estudio. La opción final es para ajustar el tamaño del área " "vacía en medio del puntero (la cruz mostrada cunado se cambia la " "localización de la vista)" #: ../C/amide.xml.translate:621(term) msgid "Default Colortable Preferences" msgstr "Preferencias de las Tablas de Color" #: ../C/amide.xml.translate:622(para) msgid "" "The program uses the specified color tables by default on a newly imported " "data set." msgstr "" "El programa usa por defecto la Tabla de Color del conjunto de datos más " "recientemente importado." #: ../C/amide.xml.translate:628(term) msgid "Misc. Preferences" msgstr "Misc. Preferencias." #: ../C/amide.xml.translate:631(para) msgid "" "The \"Send Warning Messages to Console\" option does exactly that. This is " "useful if enough warning messages are popping up that they're becoming " "annoying." msgstr "" #: ../C/amide.xml.translate:635(para) msgid "" "With the \"Don't Prompt for 'Save Changes' on Exit\" option, you can tell " "the program to not prompt you to save changes done on the study when exiting " "an AMIDE session." msgstr "" "Con la opción \"Don't prompt for 'save changes' on exit\" No notificación " "para guardar los cambios al salir, evitará que AMIDE le notifique al salir " "del programa si quiere gurdar los cambios." #: ../C/amide.xml.translate:640(para) msgid "" "The 'Save .XIF file as directory' option allows AMIDE's XIF file's to be " "saved in a directory structure, instead of as a single flat file (the " "default). This option is of interest mainly to developers" msgstr "" "La opción segunda 'save .XIF file as directory' (Guarde fichero .XIF como " "directorio) permite que el fichero de AMIDE XIF se guarde como una " "estructura de directorio y no como un fichero plano (por defecto). Esta " "opción intersa sobre todo a los desarrolladores." #: ../C/amide.xml.translate:659(title) msgid "Importing Data and Saving Studies" msgstr "Importando Datos y Guardando Estudios" #: ../C/amide.xml.translate:662(title) msgid "Importation of Data Sets" msgstr "Importación de Conjuntos de Datos" #: ../C/amide.xml.translate:664(para) msgid "" "AMIDE uses its own format (described below: ) " "for saving data between session. To get new data into AMIDE, it needs to be " "imported (located under the file menu). You can either let AMIDE try to " "guess the file format (which works for most data types) or tell AMIDE " "explicitly which format the file to be imported is suppose to be in. " "Importing of all data types except for raw data is done using Erik Nolf's " "(X)medcon medical imaging conversion library." msgstr "" "AMIDE usa propio formato (descrito abajo: ) " "para guardar datos entre sesiones. Para cargar datos al AMIDE, es necesario " "importarlos (localizado bajo el menú \"File\" ). Puede optar entre que AMIDE " "adivine el formato ( funciona para la mayoría de los tipos) o decir a AMIDE " "explícitamente que formato de fichero debe importar. Importando todos los " "tipos de datos excepto datos crudos(raw) se hace a través de la librería de " "conversión medica de Erik Nolf's (X)medcon." #: ../C/amide.xml.translate:674(title) msgid "Raw Data Files" msgstr "Ficheros de datos crudos (raw data)" #: ../C/amide.xml.translate:676(para) msgid "" "AMIDE will generally attempt to load any file ending in \".dat\" or \".raw\" " "as a raw data file. The user will be prompted for the dimensions of the " "study, the offset of the data in the file, and the data format of the data " "in the file. Both big endian, little endian, and PDP endian files can be " "loaded (endian refers to the order in which bytes are arranged in memory)." msgstr "" "AMIDE intentará cargar cualquier fichero que tenga el sufijo \".dat\" or \"." "raw\" como fichero de datos crudos. Al usuario se le pedirán las " "dimensiones , los bits que existen desde el pricipio del fichero hasta los " "datos, y el tipo y formato de datos. Ficheros en big endian, little endian, " "y PDP pueden ser cargados (endian se refiere al orden en que los bits son " "dispuestos en la memoria)." #: ../C/amide.xml.translate:683(para) msgid "" "The following data formats are supported: 8 bit signed or unsigned integer, " "16 bit signed or unsigned integer, 32 bit signed or unsigned integer, 32 bit " "IEEE floating point, 64 bit IEEE floating point, and ASCII data." msgstr "" "Los siguientes formatos de datos son soportados: enteros con o sin signo de " "8 bit , 16 , enteros con o sin signo de 32 bit , coma flotante de 32 bit " "IEEE , coma flotante de 64 bit IEEE , y datos ASCII ." #: ../C/amide.xml.translate:690(title) msgid "ECAT Files" msgstr "" #: ../C/amide.xml.translate:692(para) msgid "" "Static and dynamic ECAT 6.4 and 7.2 files are supported through (X)MedCon. " "AMIDE will generally try to load any file ending in \".img\" as ECAT 6.4, " "and any file ending in \".v\" as ECAT 7. Please note that ECAT 6.4 files are " "very difficult to autodetect, so if the file does not end in .img, you will " "probably have to tell AMIDE explicitly to import the file as ECAT 6.4." msgstr "" "Ficheros ECAT 6.4 y 7.2 , tanto estáticos como dinámicos se soportan a " "través de (X)MedCon. AMIDE intentará cargar cualquier fichero que tenga el " "sufijo \".img\" como el ECAT 6.4, y cualquier fichero con sufijo \".v\" como " "el ECAT 7. Por favor nótese que los ficheros ECAT 6.4 son muy difíciles de " "autodetectar , así si el fichero no acaba en .img tendrá que comunicar " "explícitamente a AMIDE para que importe el fichero como ECAT 6.4." #: ../C/amide.xml.translate:700(para) msgid "" "Although not compiled in by default, AMIDE can be configured to use the " "z_matrix_7/libecat library for handling ECAT files instead of (X)MedCon." msgstr "" "Aunque no se compila por defecto, AMIDE se puede configurar para usar la " "librería z_matrix_7/libecat para el manejo de ficheros ECAT en vez de (X)" "MedCon." #: ../C/amide.xml.translate:707(title) msgid "DICOM Files" msgstr "Ficheros DICOM" #: ../C/amide.xml.translate:709(para) msgid "" "DICOM 3.0 is supported through (X)MedCon, which actually uses a slightly " "modified version of Tony Voet's VT-DICOM library. The level of support for " "DICOM 3.0 is entirely determined by (X)MedCon/VT-DICOM." msgstr "" "DICOM 3.0 se soporta con (X)MedCon, el cual tiene una librería ligeramente " "modificada de Tony Voet's VT-DICOM . El nivel de soporte de DICOM 3.0 viene " "enteramente determinado por (X)MedCon/VT-DICOM." #: ../C/amide.xml.translate:715(para) msgid "" "DICOM data is often distributed as a series of single slice data files. To " "read these into AMIDE as a single data set, you will need to stack these " "slices into a single, volumetric file. Notes on how to do this can be found " "at the (X)medcon website." msgstr "" "Los datos DICOM normalmente aparecen distribuidos en un grupo de ficheros. " "Para que los lea AMIDE como un conjunto único de datos, necesitará agrupar " "esos ficheros en un único fichero de todo el volumen. Notas de cómo hacer " "esto se encuentran en el website de (X)medcon. ." #: ../C/amide.xml.translate:725(title) msgid "Concorde microPET files" msgstr "" #: ../C/amide.xml.translate:727(para) msgid "" "Concorde format files are generated by the Concorde company's series of " "microPET scanners. It's a two file format (a data file and a header file), " "with the header in easily read ASCII format. Please note that you will need " "to tell AMIDE to open the header file (.img.hdr), not the raw data file (." "img)." msgstr "" "Los ficheros Concorde son generados por los tomógrafos de microPET de la " "compañía Concorde. Es un formato con dos ficheros (uno de datos y otro de " "encabezamiento), con el de encabezamiento fácilmente leíble en ASCII. Usted " "tendrá que decir al AMIDE que abra el fichero de encabezamiento (.img.hdr), " "no el fichero de datos (.img)." #: ../C/amide.xml.translate:735(title) msgid "Acr/Nema 2.0, Analyze (SPM), InterFile3.3, Gif87a/89a" msgstr "" #: ../C/amide.xml.translate:737(para) msgid "" "A variety of additional file formats are supported through (X)MedCon, " "including: Acr/Nema 2.0, Analyze (SPM), InterFile3.3, and Gif87a/89a. For " "more information, please see the (X)MedCon documentation, or the " "corresponding " "webpage (http://xmedcon.sf.net) ." msgstr "" "Una variedad de formatos adicionales pueden ser soportados a través de (X)" "MedCon, incluyendo: Acr/Nema 2.0, Analyze (SPM), InterFile3.3, y Gif87a/89a. " "Para mas información , por favor refiérase a la documentación de (X)MedCon " "sitio web " "(http://xmedcon.sf.net)." #: ../C/amide.xml.translate:751(title) msgid "XIF Files" msgstr "Ficheros XIF" #: ../C/amide.xml.translate:753(para) msgid "" "AMIDE saves studies in an extensible XML based format called XIF (Xml Image " "Format). This format can be stored as either a single file (flat file format " "XIF) or as a XIF directory. The flat file format is the default, and " "simplifies file moving and handling. The directory format on the other hand " "allows easy access to the raw study data external to the AMIDE program, and " "will be of interest to developers. Which of these two formats you wish to " "save in can be selected from the preferences dialog." msgstr "" "AMIDE guarda los estudios en un formato extensible XIF (Xml Image Format). " "Este formato puede guardarse como fichero (formato plano XIF) o como un " "directorio XIF . El formato por defecto es el plano, lo que simplifica el " "manejo y movimiento de los ficheros. Por otro lado el formato en directorio " "permite el fácil acceso a los datos del estudio AMIDE por parte de otros " "programas, lo que será de interés para los desarrolladores. En el diálogo de " "preferencias puede elegir cual de los dos formatos XIF usar." #: ../C/amide.xml.translate:762(para) msgid "" "In any case, these files or directories will characteristically end with \"." "xif\", and are treated identically within the AMIDE program." msgstr "" "En cualquier caso los ficheros o directorios tendrán el sufijo \".xif\", y " "serán tratados idénticamente por el programa AMIDE ." #: ../C/amide.xml.translate:766(title) msgid "Opening Studies" msgstr "Abriendo Estudios" #: ../C/amide.xml.translate:768(para) msgid "" "From the main window, select \"File->Open\", and a file selection widget " "will open up. Select an XIF filename in the right column, and then hit the " "\"OK\" button (or double click on the filename)." msgstr "" "De la ventana principal, selecciónar \"File->Open\", y se abrirá un " "diálogo de selección. Seleccione un nombre de fichero XIF en la columna de " "la derecha, y pulse el boton \"OK\" (o haga click doble en el nombre del " "fichero)." #: ../C/amide.xml.translate:775(title) msgid "Saving Studies" msgstr "Guardando Estudios" #: ../C/amide.xml.translate:777(para) msgid "" "To save a study, from the study window select \"File->Save As\" and a " "file selection dialog will appear. Look at the \"selection:\" line near the " "bottom of the window, if this is the desired XIF filename, hit \"OK\" and " "the file will be saved. If this is not the desired XIF filename, select or " "enter in the correct XIF study, and hit the \"OK\" button." msgstr "" "Para guardar un estudio, de la ventana de selección de estudios \"File->" "Save As\" y un diálogo de selcción de ficheros aparecerá. Mire la línea " "\"selection:\" cerca del pie de la ventana, si este es el fichero XIF " "deseado , pulse \"OK\" y el fichero sera guradado. Si no fuera el fichero " "XIF deseado , seleccione o entre el nombre correcto de estudio XIF, y pulse " "el boton \"OK\" ." #: ../C/amide.xml.translate:784(para) msgid "" "Note that the original data set files are no longer needed by AMIDE, as all " "the information AMIDE needs is saved inside the .XIF file. You should " "however still archive the original data files, as AMIDE only reads in and " "stores the information from the header that it needs (which is generally not " "all the information enclosed within the header)." msgstr "" "Note que los ficheros de datos originales ya no son necesraios para AMIDE, " "ya que toda la información que AMIDE necesita esta guardada en el fichero ." "XIF . De todas las maneras debería guardar los ficheros originales, ya que " "AMIDE solamente lee la información que necesita del encabezamiento." #: ../C/amide.xml.translate:795(title) msgid "XIF Directory Format" msgstr "Formato XIF en Directorio" #: ../C/amide.xml.translate:797(para) msgid "" "Although admittedly annoying from a data transfer standpoint, using a " "directory structure for saving study information has the decisive advantage " "of making the saved information easily accessible using standard command-" "line utilities and text-based tools." msgstr "" "Aunque desde le punto de vista de tranferecia es bastante engorroso, usando " "la estructura de directorio para guardarlos tiene la ventaja decisiva de " "hacer la información mas fácilmente accessible usando linea de comandos y " "herramientas estandar de texto." #: ../C/amide.xml.translate:803(para) msgid "" "Each XIF directory contains a file called \"study_*.xml\" which contains the " "basic study parameters. Additional files can also be found in the XIF " "directory, such as ROI_*.xml files which contain ROI's, and data-set_*.xml " "files and their corresponding data-set_*_raw-data files, which contain the " "image data set parameters and the raw data respectively. The raw data file " "format is arbitrary (double/float/int, 64/32/16/8 bit, little or big endian, " "per plane/per frame/single scale factor), and is determined by the format of " "the originally imported data." msgstr "" "Cada directorio XIF contiene un fichero llamado \"study_*.xml\" el cual " "guarda los paramnetros básicos del estudio. Ficheros adicionales se " "encuentran en el directorio XIF como los ficheros ROI_*.xml que guardan " "ROI's, y data-set_*.xml con sus correspondientes conjuntos de datos, data-" "set_*_raw-data files, que contienen los parámetros de imagen y los datos " "crudos respectivamente. El fichero crudo (raw) (double/float/int, 64/32/16/8 " "bit, little or big endian, por plano/por segmento de tiempo(frame)/factor " "simple de escala), y está determinado por el formato original de los datos." #: ../C/amide.xml.translate:814(title) msgid "XIF Flat File Format" msgstr "Formato Plano XIF" #: ../C/amide.xml.translate:816(para) msgid "" "The flat file format is basically a concatenation of the information " "enclosed within the directory format. It is not meant to be editable or " "developer friendly. Instead, it allows easy manigment of studies for casual " "users. If you wish to access the information in a XIF flat file external to " "AMIDE, you'll be much better off resaving the data as in XIF directory " "format." msgstr "" "El formato palno XIF es una concatenación de la información encerrada en el " "directorio XIF. No es de ninguna manera para ser editado o fácil para los " "desarrolladores. En cambio, facilita el manejo para los usuarios. Si desea " "acceder al al información a un fichero palno XIF por un programa externo, " "mejor vuélvalo a guardar como formato XIF en directorio." #: ../C/amide.xml.translate:823(para) msgid "" "The format is as follows: The first 64 bytes of the file contain a magic " "string for format identification. The next 16 bytes contain 2 64bit unsigned " "little endian integers, the first one being the location of the study xml " "data within the file, and the second integer being the size of this xml " "data. Within the study xml data, is encased the information as to where in " "the file the children's xml data is. And within the children's xml data, is " "enclosed the location information of the raw data and subchildren." msgstr "" "El formato es el siguiente: Los primeros 64 bits contienen una cadena mágica " "de identificación del formato. Los siguientes 16 bits contienen 2 enteros de " "64 bit little endian, el primero siendo la localización del estudio xml en " "el fichero, y el segundo correspondiendo al tamaño de los datos xml. Dentro " "de los datos xml esta incluída la información de donde se hallan ubicados " "los hijos de los datos xml, y dentro de los datos xml de los hijos se " "encuentra la localización de los datos de los subhijos." #: ../C/amide.xml.translate:839(title) msgid "Exporting a View to JPEG/PNG" msgstr "Exportando una Vista a JPEG" #: ../C/amide.xml.translate:841(para) msgid "" "To export one of the views (transverse/coronal/sagittal) to an external " "image file, select \"File->Export View->[view]\" from the menu. The " "saved data format by default is jpeg. If the saved filename ends in \".png" "\", the saved data format will be PNG." msgstr "" "Para exportar una de las vistas (transversa/coronal/sagital) a un fichero " "externo de imagen, seleccione \"File->Export View->[view]\" desde el " "menú. . La vista será guardada como jpeg." #: ../C/amide.xml.translate:857(title) msgid "Manipulating Medical Data Sets" msgstr "Manipulando Conjunto de Datos Médicos" #: ../C/amide.xml.translate:859(para) msgid "" "After being loaded in, medical images can be manipulated in a variety of " "ways with AMIDE. An important point to remember is that AMIDE deals with all " "data sets as 3 or 4 dimensional data sets. While 2D slices extracted from " "the the data set are displayed on the computer screen, at no time does AMIDE " "handle images as anything less than 3 dimensional data." msgstr "" "Despues de ser cargados los datos médicos pueden ser manipulados de varias " "maneras en AMIDE. Es importante recordar que AMIDE trabaja con volúmenes de " "datos 3D y 4D. Mientras que los cortes 2D son representados en la pantalla " "del ordenador , AMIDE maneja siempre datos tridimensionales." #: ../C/amide.xml.translate:869(title) msgid "Manipulating Data Sets on Screen" msgstr "Manipulando Volúmenes en la Pantalla" #: ../C/amide.xml.translate:871(title) msgid "Displaying Data Sets" msgstr "Viendo Volúmenes" #: ../C/amide.xml.translate:873(para) msgid "" "When initially loaded into the program, a data set is not displayed on the " "canvases. Rather, the name of the data set is contained in the study list, " "and the user needs to select the data set in the study list so that it is " "displayed on the canvases." msgstr "" "Cuando inicialmente se carga un conjunto de datos en el programa este no es " "visualizado. En vez de esto el nombre del conjunto de datos aparece en la " "lista del estudio, y el usuario debe seleccionar este conjunto de la lista " "para visualizarlo." #: ../C/amide.xml.translate:879(para) msgid "" "Displaying multiple data sets is as simple as importing more than one data " "set, and then selecting the data sets that you wish to view from the study " "list." msgstr "" "Ver múltiple conjuntos de datos es tan simple como importar mas de un " "conjunto de datos, y entonces selecionar que conjuntos queremos ver de la " "lista del estudio." #: ../C/amide.xml.translate:883(para) msgid "" "The time period over which the slices are drawn is determined by the time " "dialog, described in more detail in " msgstr "" "El periodo de tiempo se selecciona del diálogo de tiempo y se describe en " "mas detalle en " #: ../C/amide.xml.translate:889(title) msgid "Pertinent Mouse Actions" msgstr "Manejo del Ratón" #: ../C/amide.xml.translate:891(para) msgid "" "The following mouse actions can be used when the mouse is hovering over a " "data set on any of the orthogonal views" msgstr "" "Las siguientes acciones del ratón puden ser usadas sobre los datos de las " "vistas ortogonales" #: ../C/amide.xml.translate:896(term) msgid "Shift-Left Mouse Button" msgstr "MAYUSC+Botón 1" #: ../C/amide.xml.translate:897(para) msgid "" "This combination allows shifting of the active data set in space (usually " "used for aligning two data sets). While holding the shift key, left click " "(and release) on the canvas, and you'll grab the active data set. You can " "now shift the active data around on the canvas. At this point, to enact the " "shift, click the right button (button 3). Any other mouse button will cancel " "the shift action." msgstr "" "Esta combinación permite desplazar el volumen en el espacio (normalmente " "usado para alinear volúmenes de datos). Mientras se aprieta MAYUSC, al " "pulsar el el botón 1 en la imagen, se cojerá el volumen activo. Ahora puede " "desplazarlo alrededor del marco. Cuado el volumen se halla en la posición " "deseada para soltarlo pulsar el botón 3. Cualquier otro botón del ratón " "cancelará el desplazamiento." #: ../C/amide.xml.translate:906(term) msgid "Shift-Right Mouse Button" msgstr "MAYUSC+Botón 2" #: ../C/amide.xml.translate:907(para) msgid "" "This combination allows rotating of the active data set in space (usually " "used for aligning two data sets). While holding the shift key, middle click " "(and release) on the canvas, and you'll grab the active data set. You can " "now rotate the active data around on the canvas. At this point, to enact the " "rotation, click the right button (button 3). Any other mouse button will " "cancel the rotation." msgstr "" "Esta combinación rota el volumen en el espacio (normalmente usado para " "alinear volúmenes de datos). Mientras se mantiene pulsada MAYUSC, pulsar (y " "soltar) con el botón 2 en la imagen, se cojera al volumen. Ahora puede rotar " "el volumen activo. En este punto para soltar el volumen, pulsar el botón 3. " "Cualquier otro botón cancelará la rotación." #: ../C/amide.xml.translate:916(term) msgid "Ctrl-Right Mouse Button" msgstr "Ctrl+Botón 3" #: ../C/amide.xml.translate:917(para) msgid "" "This combination will place an alignment point at the current cursor " "location. A dialog will popup for entry of the alignment point's name." msgstr "" "Esta combinación situa un punto de alineación en la posición donde este el " "cursor. Un diálogo pedirá el nombre del punto." #: ../C/amide.xml.translate:930(title) msgid "Manually Aligning Data Sets" msgstr "Alineación Manual de Volúmenes" #: ../C/amide.xml.translate:932(para) msgid "What follows is a quick guide to manually aligning data sets in AMIDE" msgstr "" "Lo que sigue es una guía rápida para alinear manualmente volúmenes en AMIDE" #: ../C/amide.xml.translate:937(para) msgid "" "First rotate each of the data sets so that they are level with respect to " "the transverse, coronal, and sagittal views. This is easily done using the " "shift-2 mouse combination, but can also be done from the data set " "modification dialog." msgstr "" "Primero rotar los volúmenes para que esten a nivel respecto a las vista " "axiales, coronales, and sagitales . Esto se hace fácilmente con la " "combinación MAYUSC+2 botón , pero también pude hacerse desde el diálogo de " "modificación de los conjuntos de datos." #: ../C/amide.xml.translate:945(para) msgid "" "Choose one of the data sets to be the active data set. The other data set " "will be the \"fixed\" data set." msgstr "" "Elija un volumen como activo, este se moverá. El otro permanecerá \"fijo\" ." #: ../C/amide.xml.translate:951(para) msgid "" "Shift the active data set so that the two data sets line up appropriately. " "This is easily done using the shift-1 mouse combination, but can also be " "done from the data set modification dialog." msgstr "" "Desplace el volumen activo hasta alinearlo con el fijo. Esto se hace " "fácilmente con la combinación MAYUSC+Botón 1 , pero también puede hacerse " "desde el diálogo de modificación de los conjuntos de datos." #: ../C/amide.xml.translate:958(para) msgid "" "If fine tuning adjustments are needed, these are best done from the data set " "modification dialog." msgstr "" "Los ajustes finos es mejor llevarlos a cabo desde el diálogo de modificación " "de los conjuntos de datos." #: ../C/amide.xml.translate:968(title) msgid "Data Set Modification Dialog" msgstr "Diálogo de Modificación de Conjuntos de Datos" #: ../C/amide.xml.translate:970(para) msgid "" "To modify parameters of a data set, right click on the name of the data set " "in the study tree to pop-up the data set modification dialog box. Parameters " "that can be modified are divided into the following pages." msgstr "" "Para modificar los Parametros de un volumen, pulsar con el botón 3 en le " "volumen del arbol del estudio para que aparezca el diálogo de modificación. " "Los parámetros modificables se dividen en las siguientes páginas." #: ../C/amide.xml.translate:977(term) ../C/amide.xml.translate:1445(term) #: ../C/amide.xml.translate:1513(term) #, fuzzy msgid "Basic Info" msgstr "" "#-#-#-#-# es.po (PACKAGE VERSION) #-#-#-#-#\n" "Informacion Básica\n" "#-#-#-#-# es.po (PACKAGE VERSION) #-#-#-#-#\n" "Información Básica\n" "#-#-#-#-# es.po (PACKAGE VERSION) #-#-#-#-#\n" "Información Básica" #: ../C/amide.xml.translate:978(para) msgid "" "On this page are options to alter the data set name, type of modality, " "subject name, subject id, subject date of birth (DOB), conversion factor, " "and the interpolation type to use for this data set (described at ). The conversion factor is a parameter that is " "multiplied to the data set before it is used for viewing or quantitation. " "Since the data set is in ECAT/MAP/abitrary scale units, the conversion " "factor can be used in order to analyze the data set in another type of " "reference unit (e.g. Percent Injected Dose [%ID]). There is also a built in " "calculator, where parameters such as subject weight and injected dose can be " "entered, and the conversion factor will be generated. Note that 1 cc is " "assumed to equal 1 g when generating the %ID/g and SUV." msgstr "" "En esta página hay opciones para modificar el nombre, tipo de modalidad, " "factor de conversión, y tipo de interpolación usado en este volumen de datos " "(descrito en ). El factor de conversión es " "el parámentro por el que se multipilican el volumen de datos antes de verlo " "o cuantificarlo. Al estar los datos en una escala arbitraria de valores ECAT/" "MAP, el factor de conversión se puede utilizar para analizar los datos con " "otro tipo de unidad d e referencia(p.e. Porcentaje de Dosis Inyectada [%" "ID]). También hay una calculadora incluida, donde se pueden meter los " "parámetros como el peso del sujeto y la dosis inyectada, generandos el " "factor de conversión." #: ../C/amide.xml.translate:997(term) ../C/amide.xml.translate:1451(term) msgid "Center" msgstr "Centro" #: ../C/amide.xml.translate:998(para) msgid "" "The data set can be shifted by respecifing the center of the data set with " "respect to the origin. The x, y, and z dimensions are in millimeters." msgstr "" "Se puede desplazar el volumen de datos con respecto al origen de " "coordenadas. Las dimensiones xyz son en milímetros." #: ../C/amide.xml.translate:1005(term) msgid "Voxel Size" msgstr "Tamaño del Voxel" #: ../C/amide.xml.translate:1006(para) msgid "" "The size of the data set's voxels (again, in millimeters) can be altered on " "this page. The \"keep aspect ratio\" button specifies that when altering the " "size of any voxel component (x, y, or z), the relative sizes between the " "components should be kept the same." msgstr "" "El Tamaño del voxel de los datos (también en milímetros) pude ser alterado " "en esta página. El botón \"keep aspect ratio\" especifica que cuando se " "altera cualquier dimensión del voxel (x, y, or z), las demás dimensiones se " "alteraran en la misma proporción." #: ../C/amide.xml.translate:1015(term) ../C/amide.xml.translate:1466(term) #: ../C/amide.xml.translate:1527(term) msgid "Rotate" msgstr "Rotar" #: ../C/amide.xml.translate:1016(para) msgid "" "The data set can be rotated around its center in this page. There is one " "dial for each of the three slice planes. The transverse dial will spin the " "data set in the transverse plane (i.e. rotate on the z-axis). The coronal " "dial will spin the data set in the coronal plane (i.e. rotate on the y-" "axis). And the sagittal dial will spin the data set in the sagittal plane (i." "e. rotate on the x-axis). The \"reset to default\" button allows the data " "set to be rotated back to the default orientation. On the bottom of this " "page is a matrix showing the coordinate frame of the data set with respect " "to the base coordinate frame." msgstr "" "El volumen de datos puede ser rotado sobre su cento en esta página. Hay una " "ruedecita por cada plano. La ruedecita axial rotará el volumen en el plano " "transversal (rota sobrel el eje z). La ruedecita coronal rotará el volumen " "en el plano coronal (rota sobrel el eje y). Y la rudecita sagital lo hará " "sobre el plano sagital (rota sobrel el eje x). El botón \"reset to default\" " "deshace las rotaciones dejando el volumen como al principio. Al pie de " "página existe una matriz con las tranformaciones de las coordenadas del " "volumen con respecto al las coordenadas de origen." #: ../C/amide.xml.translate:1031(term) msgid "Colormap/Threshold" msgstr "Mapa de Color/Umbral(Threshold)" #: ../C/amide.xml.translate:1032(para) msgid "" "This page is analogous to the thresholding tool dialog (described at ) above)." msgstr "" "Esta página es análoga al del diálogo de Umbral (descrita en )." #: ../C/amide.xml.translate:1038(term) msgid "Time" msgstr "Tiempo" #: ../C/amide.xml.translate:1039(para) msgid "" "From this page, the timing information of the data set can be altered. Scan " "start time can be used for altering the start time of the scan with respect " "to other data sets. Corrections in the duration of each data frame can also " "be made on this page." msgstr "" "Desde esta página se puede alterar la información respecto al los tiempos de " "los datos. El tiempo de comienzo del scan puede cambiarse con respecto al " "tiempo de otros scans. También pueden hacerse correciones en la duración de " "cada marco de tiempo(Frame Time) ." #: ../C/amide.xml.translate:1047(term) msgid "Windowing Preferences" msgstr "" #: ../C/amide.xml.translate:1048(para) msgid "" "The max and min threshold levels used for the bone and soft tissue CT window " "buttons can be explicitly set here. The \"Insert Current Thresholds\" button " "will reset the max and min values with the data set's currently used " "threshold levels." msgstr "" #: ../C/amide.xml.translate:1056(term) ../C/amide.xml.translate:1565(term) msgid "Immutables" msgstr "" #: ../C/amide.xml.translate:1057(para) msgid "" "This panel lists information about the data set that cannot be altered. The " "underlying internal data format of the data set and the data set dimensions " "in voxels are displayed on this page." msgstr "" "Este panel lista la información que no puede ser alterada. El formato " "interno subyaccente y las dimensiones del voxel se muestran en esta página." #: ../C/amide.xml.translate:1075(title) msgid "Using Regions of Interest (ROI's)" msgstr "Usando Regiones de Interés (ROI's)" #: ../C/amide.xml.translate:1077(para) msgid "" "ROI stands for Region of Interest. An ROI designated a volume in space over " "which statistics should be calculated." msgstr "" "ROI(Region of Interést) es decir Región de Interés. Un ROI designa un " "subvolumen del volumen de datos sobre el que serán calculadas las " "estadísticas." #: ../C/amide.xml.translate:1082(title) msgid "ROI Types" msgstr "" #: ../C/amide.xml.translate:1084(para) msgid "The following ROI types are currently supported in AMIDE:" msgstr "Lo siguientes tipos de ROI son soportados por AMIDE:" #: ../C/amide.xml.translate:1088(title) msgid "Geometric ROI's" msgstr "" #: ../C/amide.xml.translate:1092(term) msgid "Ellipsoid" msgstr "Elipsoide" #: ../C/amide.xml.translate:1093(para) msgid "" "An ellipsoid is similar to a sphere, but with a radius specified for each " "direction [x,y,z]. In the case of x=y=z, the ellipsoid is a sphere." msgstr "" "Un elipsoide es similar a una esfera, pero con un radio que puede ser " "diferente en cada dirección [x,y,z]. Si x=y=z el elipsoide se convierte en " "una esfera." #: ../C/amide.xml.translate:1098(term) msgid "Elliptic Cylinder" msgstr "Cilindro Elíptico" #: ../C/amide.xml.translate:1099(para) msgid "" "An elliptic cylinder is similar to a regular cylinder, except it has an " "ellipse as its base instead of a circle." msgstr "" "Similar al cilindro excepto que su base en vez de un círculo es una elipse." #: ../C/amide.xml.translate:1104(term) msgid "Box" msgstr "" #: ../C/amide.xml.translate:1105(para) msgid "Exactly what it says, a 3D box." msgstr "Caja 3D." #: ../C/amide.xml.translate:1112(title) msgid "Isocontour ROI's" msgstr "ROI Isocontorno" #: ../C/amide.xml.translate:1114(para) msgid "" "Isocontour ROI's are regions selected from the data set such that the edge " "values of the ROI are always the same value. There are two types, 2D and 3D " "isocontours. Additionally, both these ROI types can be defined so that they " "encompass all neighboring values either above a certain minimum value, below " "a certain maximum value, or between a minimum and maximum value. After " "drawing of these ROI's, they can be modified by using manual drawing or " "erasing operations." msgstr "" "ROI Isocontorno, son regiones seleccionadas del volumen cuyos límites tienen " "el mismo valor. Hay dos tipos, isocontronos 2D y 3D ." #: ../C/amide.xml.translate:1125(term) msgid "2D Isocontour" msgstr "Isocontorno 2D" #: ../C/amide.xml.translate:1126(para) msgid "" "A 2D isocontour is derived by considering a value on one of the displayed 2D " "slices. The depth of a 2D isocontour is specified initially by the depth of " "the viewed slices." msgstr "" "El isocontorno 2D se deriva del dibujado en uno de los cortes. . La " "profundidad del isocontorno 2D esta determinada por el grosor del corte " "visualizado." #: ../C/amide.xml.translate:1132(term) msgid "3D Isocontour" msgstr "Isocontorno 3D" #: ../C/amide.xml.translate:1133(para) msgid "" "A 3D isocontour is derived by considering a value on the current frame of " "the active data set." msgstr "" "El isocontorno 3D se deriva considerando un valor del marco de tiempo " "selecionado del volumen activo." #: ../C/amide.xml.translate:1141(title) msgid "Freehand ROI's" msgstr "" #: ../C/amide.xml.translate:1143(para) msgid "Freehand ROI's are regions of interest that are drawn manually." msgstr "" #: ../C/amide.xml.translate:1148(term) msgid "2D Freehand" msgstr "" #: ../C/amide.xml.translate:1150(para) msgid "" "A 2D Freehand ROI is similar to a 3D Freehand, except that it is constrained " "to be only one voxel thick. By default, the depth is the current slice " "thickness, although this can be changed by the user." msgstr "" #: ../C/amide.xml.translate:1156(term) msgid "3D Freehand" msgstr "" #: ../C/amide.xml.translate:1157(para) msgid "An ROI that can be drawn freely in all 3 dimensions.." msgstr "" #: ../C/amide.xml.translate:1167(title) msgid "Drawing ROI's" msgstr "Dibujando ROI's" #: ../C/amide.xml.translate:1169(para) msgid "" "To draw an ROI, you first need to create a new ROI. You can add a new ROI to " "either the study, or a particular data set. To add an ROI to the study, you " "can either select the ROI desired under the \"Edit->add ROI:\" menu item, " "or right click on the blank area of the study tree. To add an ROI to a data " "set, shift-right click on the data set that you'd like to add the ROI to. In " "both cases, a dialog box will pop-up for you to enter in the new ROI's name." msgstr "" "Para dibujar un ROI, primero necesita crear un ROI nuevo. Puede añadir un " "ROI a todo el estudio o a un volumen en particular. Para añadirlo al " "estudio, puede seleccionar el ROI en el menu item \"Edit->add ROI:\" , o " "hacer pulsar el botón 3 en el área desnuda el árbol del estudio. Para añadir " "un ROI a un volumen , hacer SHIF+botón 3 sobre el volumen a añadir. En ambos " "casos emergerá una cajita de diálogo para entrar el nombre del ROI." #: ../C/amide.xml.translate:1179(para) msgid "" "When first added, the new (undrawn) ROI will be selected in the study tree. " "When an undrawn ROI is selected in the study tree, the program will use the " "next mouse input on any of the displayed views to begin the process of " "drawing this ROI." msgstr "" "Al añirlo al pricipio , el ROI nuevo (todavía no dibujado) sera seleccionado " "en el árbol del estudio. Cuando un ROI todavia no dibujado es seleccionado, " "el programa usara el la siguiente acción del ratón sobre una vista para " "empezar el proceso de dibujo del ROI." #: ../C/amide.xml.translate:1186(para) msgid "" "For ellipsoid, elliptic cylinder, and box ROI's, a click with the left " "button will begin an edge-to-edge drawing, while a click with the middle " "button will begin a center-out drawing. The x and y dimensions of the ROI " "are determined by this process. The z dimension (thickness) of the ROI can " "be specified by the pop-up dialog that will appear on the completion of the " "mouse movement." msgstr "" "Para ROI's elipsoide, cilindroide y caja 3D, una pulsación d el botón 1 " "empezará un dibujo de borde a borde , mientras que si pulsamos el botón 3 " "empezará el dibujo por el centro. Las dimensiones xy del ROI se determinan " "con este proceso. La dimensión z (grosor) del ROI se puede especificar en el " "diálogo que emergerá al acabar de dibujar el ROI." #: ../C/amide.xml.translate:1195(para) msgid "" "For isocontour's, the value of the data set at the clicked upon location " "will be used to derive the isocontour." msgstr "" "Para los isocontornos, el valor de donde este situado el cursor sera usado " "para derivar el isocontorno." #: ../C/amide.xml.translate:1200(para) msgid "" "For freehand's, the point on the screen that is clicked upon will be " "included in the ROI." msgstr "" #: ../C/amide.xml.translate:1207(title) msgid "Manipulating ROI's" msgstr "Manipulando ROI's" #: ../C/amide.xml.translate:1209(para) msgid "" "After an ROI is drawn, it can be further manipulated to adjust its size, " "placement, and orientation. You can directly manipulate the ROI by clicking " "on it in any of the viewing windows. Mouse button 1 is used to shift ROIs. " "Mouse button 2 is used for zooming ellipsoid, elliptic cylinder and box ROI, " "and is used for entering drawing mode for isocontour and freehand ROI's. " "Mouse button 3 is used to rotate ellipsoid, elliptic cylinder, and box ROIs, " "and for redefining the isocontour value for isocontour ROI's." msgstr "" "Después de haber dibujado un ROI, puede ser manipulado ajustando su volumen, " "posición y orientación. Puede manipular directamente el ROI pulsando en " "cualquiera de las ventanas. El botón 1 se usa para desplazar los ROIs. El " "botón 2 para rotar los ROIs elpisoides, cilindroides y cajas 3D y en el caso " "de los ROI de isocontorno para borrar puntos. El botón 3 se usa para hacer " "zoom de los ROI's elipsoide, cylindro elíptioco y caja 3D, y redefine le " "valor del isocontrono en el caso de esos ROIs." #: ../C/amide.xml.translate:1219(para) msgid "" "For isocontour and freehand ROI's, drawing mode can be entered by using thie " "middle mouse button (button 2). Once entered, points can be added or removed " "from the ROI by using the left (button 1) or right (button 3) mouse buttons, " "respectively. Holding down the shift key while using these buttons increases " "the size of the action. The middle button (button 2) allows the user to " "leave drawing mode." msgstr "" #: ../C/amide.xml.translate:1228(para) msgid "" "You can also edit the ROI size/placement/orientation/name etc. by clicking " "on mouse button 3 while over the ROI's name in the study item list. This " "brings up the ROI modification dialog (described at )." msgstr "" "También puede editar el tamaño,situación, orientación, nombre etc.. pulsando " "el botón 3 sobre el nombre del ROI en la lista de items del estudio. Esto " "hace que aparezca el diálogo de Modificación de ROIs (descrito en en )." #: ../C/amide.xml.translate:1239(title) msgid "Calculating Statistics" msgstr "Calculando Estadísticas" #: ../C/amide.xml.translate:1241(para) msgid "" "Statistics on an ROI can be calculated via the \"Tools->calulate ROI " "statistics\" menu item. Choosing this will pop-up a dialog that lets you " "choose which ROI's (selected or all) and which data sets (selected or all) " "you'd like to calculate statistics over. You will also have three options as " "to how you what the values to be calculated." msgstr "" "Las estadísticas dentro de un ROI se pueden calcular con el menu item " "\"Tools->calulate ROI statistics\" . Eligiendo este emergerá un diálogo " "que le permitirá elegir entre que ROI (o todos) y entre que volúmenes (o " "todos) quiere que se calculen las estadísticas. También pude elegir que se " "calcule sobre subconjuntos de vóxeles, significando el cálculo sobre el x% " "de vóxeles con valor máximo del ROI." #: ../C/amide.xml.translate:1253(para) msgid "Calculate over all voxels." msgstr "" #: ../C/amide.xml.translate:1257(para) msgid "" "Calculate over highest x percent of voxels. For example, if you choose this " "and pick 25% as the number, your ROI will be calculated from the 25% of the " "voxels in the ROI that have the highest values." msgstr "" #: ../C/amide.xml.translate:1265(para) msgid "" "Calculate for voxels >= % of Max. This method is based on Lee, Madsen, " "Bushnel, and Menda, Nuc Med Comm 2000, 21:685-690. As an example, if you " "choose this and pick 50% as the number, the highest valued voxel in the ROI " "will be found, and then the ROI statistics will be calculated for all voxels " "that are greater or equal to 50% of the highest valued voxel." msgstr "" #: ../C/amide.xml.translate:1275(para) msgid "" "Calculate for voxel >= Value. This algorithm only does calculations for " "voxels in the ROI that have a value greater than the value specified." msgstr "" #: ../C/amide.xml.translate:1283(para) msgid "" "There's also a check box to enable \"more accurate quantitation\". The " "default algorithm (corresponding to unchecked) makes some approximations in " "deciding which voxel are in our out of the ROI. If this check boxed is " "checked, the ROI results will be more accurate, but will take much longer to " "compute." msgstr "" #: ../C/amide.xml.translate:1290(para) msgid "" "After hitting execute, the program will crank for a while, and then show the " "calculated values in a new dialog window. Hitting \"Save as\" button allows " "saving these values as a tab separated values (TSV) file. This file should " "be easily imported into most spreadsheet applications (Excel's a little " "stupid, you may have to explicitly tell it you're importing a TSV file). " "Pressing the \"Copy\" button copies the information into the operating " "systems clipboard, allowing pasting of the results into other programs. The " "\"Save Raw Values\" button allows you to export the underlying raw data " "values for the ROI's in case you wish to do your own statistical analysis." msgstr "" "Despues de pulse 'execute' , ejecutar, tras unos instantes el programa " "mostrará los valores calculados. Seleccionando \"save as\" permite guardarlo " "es un fichero con los valores separados por una tab (TSV). Este fichero " "debería ser importado fácilmente a cualquier hoja de cálculo (Excel es un " "poco estúpido, tiene que expecificarle que esta importando un fichero TSV, " "Tab Separated Values)." #: ../C/amide.xml.translate:1308(title) msgid "Gotcha's to ROI calculations" msgstr "Facilidades para los Cálculos de los ROI" #: ../C/amide.xml.translate:1310(title) msgid "Variance and Standard Deviation Fallacies" msgstr "Varianza/Std. Dev./Std. Err." #: ../C/amide.xml.translate:1312(para) msgid "" "Currently, AMIDE generates variance and standard deviation values that may " "occasionally be of interest to imaging physicists. It is very important to " "remember, that these numbers represent the noise in the data set, NOT the " "noise in your experiment." msgstr "" "A día de hoy, AMIDE genera valores de varianza/std. dev./std. error que " "ocasionalmente pueden interesar para los investigadores. Es muy importante " "recordar , que esos números representan el ruido en los datos, NO el ruido " "en su experiemento." #: ../C/amide.xml.translate:1319(para) msgid "" "The variance of an experiment can only truly be measured by taking multiple " "samples (i.e. performing multiple scans) and calculating the variance " "between these different samples." msgstr "" "La varianza del experimento solo puede ser tomada repitiendo multiples " "muestras (p.e. haciendo multiples scans) y calculando la varianza entre " "diferentes muestras." #: ../C/amide.xml.translate:1326(title) msgid "Changing Calculated Volume" msgstr "Cambiando el Volumen Calculado" #: ../C/amide.xml.translate:1328(para) msgid "" "Short story: The calculated volume shown by the ROI " "statistics dialog is correct. Use this value as the volume of the ROI, not " "the value you might calculate by hand based on the ROI's dimensions." msgstr "" "Historia corta: El volumen calculado mostrado por el " "diálogo de estadísticas del ROI es correcto. Use este valor como volumen del " "ROI, no el que podría calcular a man basándose en las dimensiónes del ROI." #: ../C/amide.xml.translate:1334(para) msgid "" "Long story: AMIDE calculates ROI's by translating the " "ROI's dimensions into the data set's coordinate space. It then computes " "statistics for all the data set voxels that are in the ROI. For voxels that " "lie on the edge of the ROI, AMIDE will subdivide the voxel into a finite " "number of subvoxels, and calculate over the subvoxels. This approach yields " "correct statistics, but it is important to realize that the computed ROI is " "a discrete representation of the specified analytical ROI. So while the true " "volume of an ellipse is pi*r1*r2*r3, the computed volume of the ellipse in " "AMIDE will depend on the number of voxels and subvoxels that were determined " "to lie within the ellipse, which in turn can depend on the orientation of " "the ROI with respect to the data set in question. Since the computed volume " "given by AMIDE represents the volume in the data set that was used for the " "ROI calculation, you will want to use that value (not the real ellipse " "value)." msgstr "" "Historia larga: AMIDE calcula el ROI's trasladando las " "dimensiónes del ROI al las coordenadas del espacio del volumen de datos. " "Entonces calcula las estadísticas de todos los volúmenes de datos que hay en " "el ROI. Para los vóxeles que caen en el límite del ROI, AMIDE subdividirá el " "voxel en un número finito de subvóxeles, y hace el cálculo sobre los " "subvóxeles. Esta aproximación resulta en estadísticas correctas, pero es " "importante darse cuenta que el ROI calculado es una representación " "discretizada del ROI analítico. Así que mientras el verdadero volumen de un " "elipsoide es pi*r1*r2*r3, el volumen calculado por AMIDE dependerá del " "número de vóxeles y subvóxeles que se determinan dentro del elipsoide, que a " "su vez puede depender de la orientación del ROI respecto al volumen de datos " "en cuestión. Como el volumen dado por AMIDE representa el subvolumen en el " "volumen de datos para el cálculo del ROI, querrá usar ese valor (no el valor " "real elipsoide)." #: ../C/amide.xml.translate:1353(title) msgid "Why isn't a \"total\" statistic calculated for the ROI?" msgstr "" #: ../C/amide.xml.translate:1355(para) msgid "" "AMIDE doesn't present the \"total\" value in the ROI, as it doesn't " "necessarily know what the units of the underlying data are. If you're using " "PET or SPECT data, your voxel values are most likely proportional to " "activity/volume/time. To calculate the total in your ROI, you should " "multiple the mean value of the ROI times the ROI volume and the frame " "duration. If you're using CT data, your values are probably proportional to " "density, so to calculate the total you would multiple the mean ROI value by " "the ROI volume." msgstr "" #: ../C/amide.xml.translate:1369(title) msgid "Explanations of ROI Statistical Values" msgstr "Explicaciones de los Valores Estadísticos de los ROI's" #: ../C/amide.xml.translate:1373(term) msgid "Median" msgstr "Mediana" #: ../C/amide.xml.translate:1374(para) msgid "" "This is the median value of all the voxels that are enclosed (partially or " "totally) within the ROI. For an even number of voxels, the median is defined " "as the average of the center 2 values." msgstr "" "Es el valor de mediana value de todos los vóxeles que estan total o " "parcialmente incluidos en el ROI. Para un numero par de vóxeles , la mediana " "se define como el promedio de los 2 valores centrales." #: ../C/amide.xml.translate:1380(term) msgid "Mean" msgstr "Media" #: ../C/amide.xml.translate:1381(para) msgid "" "The mean value of the voxels in the ROI. Voxels that are partially enclosed " "within the ROI are appropriately weighted." msgstr "" "El valor media de los vóxeles del ROI. Los vóxeles parcialmente incluidos en " "el ROI son proporcionalmente sopesados." #: ../C/amide.xml.translate:1386(term) msgid "Variance" msgstr "Varianza" #: ../C/amide.xml.translate:1387(para) msgid "" "The variance of the voxels in the ROI. This is a weighted variance " "calculation so that voxels that are partially enclosed within the ROI are " "correctly handled." msgstr "" "La varianza de los vóxeles en el ROI. Esta es de hecho un cálculo de " "varianza sopesada asi los vóxeles parcialmente incluídos en el ROI son " "correctamente manejados." #: ../C/amide.xml.translate:1393(term) msgid "Standard Deviation" msgstr "Desviación Estandard" #: ../C/amide.xml.translate:1394(para) msgid "The square root of the variance." msgstr "La raiz cuadrada de la varianza." #: ../C/amide.xml.translate:1397(term) msgid "Standard Error" msgstr "Error Estandard" #: ../C/amide.xml.translate:1398(para) msgid "" "The square root of the variance, divided by the square root of the total " "number of voxels in (totally or partially) the ROI." msgstr "" "La raiz cuadrada de la varianza , dividido por la raiz cuadrada del numero " "total de vóxeles (total o parcialmente) en el ROI." #: ../C/amide.xml.translate:1403(term) msgid "Minimum/Maximum" msgstr "Mínimo/Máximo" #: ../C/amide.xml.translate:1404(para) msgid "" "The minimum and maximum values for all voxels enclosed totally or partially " "within the ROI." msgstr "" "El valor mínimo y máximo de todos los vóxeles parcial o totalmente incluidos " "en el ROI." #: ../C/amide.xml.translate:1408(term) msgid "Size" msgstr "Tamaño" #: ../C/amide.xml.translate:1409(para) msgid "" "The volume of an ROI (mm^3). Details as to its calculation are above in: " "." msgstr "" "El volumen de un ROI (en mm cúbicos). Detalles de este cálculo arriba en: " "." #: ../C/amide.xml.translate:1414(term) msgid "Fractional Voxels" msgstr "" #: ../C/amide.xml.translate:1415(para) msgid "" "The is the sum of the voxel weights, and gives an indication of how large " "the ROI is in voxel space." msgstr "" "Es la suma del peso de los vóxeles, y da una indicación de cuan grande es el " "ROI en el espacio de vóxeles." #: ../C/amide.xml.translate:1420(term) msgid "Voxels" msgstr "Vóxeles" #: ../C/amide.xml.translate:1421(para) msgid "" "This is the total number of voxels used in calculating the ROI, both partial " "and total. In contrast to the \"Fraction Voxels\" measure, the \"Voxels\" " "measure gives a better indication of the statistical validity of the mean, " "variance, etc." msgstr "" "Es el número total de vóxeles incluidos calculando el ROI, tanto parcial " "como totalmente. En contraste a la medida \"Fraction Voxels\", los \"Vóxeles" "\" dan mejor indicación de la valided estadística de la median, varianza, " "etc .." #: ../C/amide.xml.translate:1435(title) msgid "ROI Modification Dialog" msgstr "Diálogo de Modificación de ROI" #: ../C/amide.xml.translate:1437(para) msgid "" "To directly modify parameters of an ROI, right click on the name of the ROI " "in the study tree to pop-up the modification dialog. Parameters that can be " "modified are divided into the following pages." msgstr "" "Para modificar directamente los parámetros del ROI, pulsar el botón 3 en el " "nombre del ROI en el árbol del estudio, para que emerga el diálogo de " "modificación. Los parámetros que se pueden modificar se dividen en dos " "páginas. pages." #: ../C/amide.xml.translate:1446(para) msgid "The name and type of ROI can be altered on this page." msgstr "El nombre y tipo de ROI se puede alterar en esta página." #: ../C/amide.xml.translate:1452(para) msgid "" "The center of the ROI can be shifted with respect to the origin on this " "page. The x, y, and z parameters are in millimeters." msgstr "" "El centro del ROI puede despalzarse en esta página . Los parámetros xyz " "estan en milímetros." #: ../C/amide.xml.translate:1458(term) msgid "Dimensions" msgstr "Dimensiones" #: ../C/amide.xml.translate:1459(para) msgid "" "The size of the ROI can be altered from this page. The x', y', and z' " "dimensions are in millimeters and are orientated with respect to the " "orientation of the ROI." msgstr "" "El tamaño del ROI se puede alterar en esta página. Las dimensiónes x, y, y z " "estan milímetros y orientadas con respecto a la orientación del ROI." #: ../C/amide.xml.translate:1467(para) msgid "" "The ROI can be rotated around its center in this page. There is one dial for " "each of the three slice planes. The transverse dial will spin the ROI in the " "transverse plane (i.e. rotate on the z-axis). The coronal dial will spin the " "ROI in the coronal plane (i.e. rotate on the y-axis). And the sagittal dial " "will spin the ROI in the sagittal plane (i.e. rotate on the x-axis). The " "\"reset to default\" button allows the ROI to be rotated back to the default " "orientation. On the bottom of this page is a matrix showing the coordinate " "frame of the ROI with respect to the base coordinate frame." msgstr "" "El ROI puede rotarse sobre su centro en esta página . Hay una ruedecilla " "para cada uno de los tres planos. La ruedecilla transversal rotará el ROIen " "el plano transverso (rota sobre el eje z). La rudecilla coronal rotará el " "ROI en el plano coronal (rota sobre el eje y). Y la ruedecilla sagital " "girará el ROI en el plano sagital (rota sobre el eje x). El botón \"reset to " "default\" deshace los giros dejando la orientación original. Al pie de esta " "página hay una matriz que muestra las coordinadas del ROI respecto a las " "coordenadas de origen." #: ../C/amide.xml.translate:1490(title) msgid "The Study" msgstr "" #: ../C/amide.xml.translate:1492(para) msgid "" "The \"Study object\" in AMIDE is used for grouping a set of related data " "sets and ROI's. Note that the use of the word \"Study\" here diverges from " "the traditional nuclear medicine use of the word, in which study generally " "connotates a single scan (or occasionally multiple but highly coupled scans) " "done on a single patient. A study in AMIDE is often used to group an entire " "experiment (several patients, several animals, whatever) into a single file. " "The study object itself is used mostly for storing parameters that effect " "all other objects stored in the study." msgstr "" #: ../C/amide.xml.translate:1502(title) msgid "Study Modification Dialog" msgstr "Diálogo de Modificación de Estudio" #: ../C/amide.xml.translate:1504(para) msgid "" "Similarly to the data set and ROI modification dialogs, the study " "modification dialog can be used to alter parameters relevant to the entire " "study. Right click on the name of the study in the study tree to pop-up the " "study modification dialog box. Parameters that can be modified are divided " "into the following pages." msgstr "" "Para modificar los parámetros globales del estudio, pulse el botón 3 del " "ratón en el nobre del estudio en el árbol del estudio o en la caja de " "diálogo de modificación de estudio. Los parámetros pueden dividirse de las " "siguientes categorias." #: ../C/amide.xml.translate:1514(para) msgid "" "On this page are options to alter the name and creation date of the study." msgstr "" "En esta página estan las opciónes para alterar el nombre y fecha de creación " "del estudio." #: ../C/amide.xml.translate:1519(term) msgid "View Center" msgstr "Ver Centro" #: ../C/amide.xml.translate:1520(para) msgid "" "From this page, the point that the study is currently viewing can be " "explicitly changed. The x, y, and z dimensions are in millimeters." msgstr "" "Desde esta página se pude cambiar expliícitamente el centro desde el cual el " "estudio es visto. Las dimensiónes xyz son en milímetros. También se pueden " "cambiar explícitamente. The x, y, and z" #: ../C/amide.xml.translate:1528(para) msgid "" "The entire study (including all objects within it) can be rotated around the " "view center in this page. There is one dial for each of the three slice " "planes. The transverse dial will spin the study in the transverse plane (i." "e. rotate on the z-axis). The coronal dial will spin the study in the " "coronal plane (i.e. rotate on the y-axis). And the sagittal dial will spin " "the study in the sagittal plane (i.e. rotate on the x-axis). The \"reset to " "default\" button allows the study to be rotated back to the default " "orientation. On the bottom of this page is a matrix showing the coordinate " "frame of the study with respect to the base coordinate frame." msgstr "" "El estudio completo(incluyendo todos su objetos) puede ser rotado sobre el " "centro de vista de la imagen. Hay una ruedecilla por cada vista ortogonal. " "La ruedecilla axial rota sobre el plano axial (rota sobre el eje z). La " "ruedecilla coronal rotará el plano coronal (rota sobre el eje y) . Y la " "sagital rotará sobre le plano sagital(rota sobre el eje x). El botón \"reset " "to default\" permite volver a la rotación original del estudio. A pie de " "página hay una matriz mostrando las coordenadas del estudio con respecto a " "las de referencia." #: ../C/amide.xml.translate:1544(para) msgid "" "The width of the line used to draw geometric ROIs can be altered here (1-5 " "pixels). This parameter is not relevant for isocontour ROI's. For isocontour " "ROI's, you can choose to have them draw as filled in or hollow." msgstr "" "The width of the line used to draw geometric ROIs can be altered here (1-5 " "pixels). This parameter is not relevant for isocontour ROI's." #: ../C/amide.xml.translate:1549(para) msgid "" "Canvas layout allows you to switch the three views (transverse, coronal, and " "sagittal) between a linear style layout more commonly seen in PET software, " "and an orthogonal style layout more commonly seen in MRI software. " "\"Maintain view size constant\" allows you to pick if you want the size of " "the view to remain constant or not. If not checked, the size of the views " "shown will depend only on the data sets selected. If the checkbox is " "checked, the size of the views will depend on all the data sets in the " "study. Finally, \"target empty area\" is for setting the size of the empty " "area in the middle of the target (the crosshairs on the views when changing " "the view location)." msgstr "" #: ../C/amide.xml.translate:1566(para) msgid "" "This panel lists information about the study that cannot be altered. \"Voxel " "dim\" is the preferred voxel dimension, this is what the canvas will use as " "the \"basic\" voxel dimension, from which the zoom factor is relative too." msgstr "" "Este panel lista las características del estudio que no puden ser alteradas. " "\"Voxel dim\" es la dimensión preferida del voxel, este será usado como " "dimensión \"básica\" del voxel, a la cual el zoom es relativa." #: ../C/amide.xml.translate:1585(title) msgid "Viewing Series of Slices" msgstr "Viendo Series de Cortes" #: ../C/amide.xml.translate:1586(para) msgid "" "Instead of looking at three orthogonal slices through the data set, a series " "of slices (all of the same orientation) can also be examined. Select: \"View-" ">Series\", and a dialog box will come up allowing you to pick which " "objects you'd like to display on the series viewer, along with if you'd like " "to display the slices over space, time, or gates. The thickness of the " "slices are determined at the time the series window is brought up. A slider " "appears on the top of the window which allows moving through the data set. " "Note that since slices are cached in memory after being displayed, already " "displayed slices do not need to be regenerated from the data set and " "reviewing these slices is significantly faster." msgstr "" "En vez de examinar las vistas ortogonales , se pueden observar series de " "cortes (todos en la misma orientación). Seleccione: \"View->Series->" "Space->[view]\" del menú para para extraer la serie de cortes de una " "misma orientación. Alternativamente, seleccione: \"View->Series->Time-" ">[view]\" desde el menú para ver un mismo corte a lo largo del tiempo en " "un estudio dinámico. El grosor de los cortes es el que había antes de " "deplegar el menu. Una barra de desplazmiento aparecera encima de la imagen " "para moverse por el volumen de datos. Notese que una vez vistos los cortes " "quedan en la memoria lo que hace que su revisión sea mucho más rápida." #: ../C/amide.xml.translate:1608(title) msgid "Rendering Data" msgstr "Renderizado de Datos" #: ../C/amide.xml.translate:1610(para) msgid "" "Rendering in AMIDE is accomplished using the Volpack volume rendering " "library. This software library is both portable, and provides for " "true volume rendering (as opposed to the surface rendering used by many " "other libraries and hardware accelerators)." msgstr "" "El Renderizado en AMIDE se lleva a cabo usando la librería de renderizado de " "volumenes Volpack. Esta librería de software es portable y , " "permite renderizado verdadero del volumen (en oposición al renderiazado de " "superficie usado por otras librerías de software para aceleradoras de " "hardware)." #: ../C/amide.xml.translate:1617(para) msgid "" "To start a rendering window, select the \"View->Rendering\" menu item. A " "small dialog window will pop-up allowing you to select which objects you'd " "like rendered, along with some additional options. The first \"Set values " "greater than max threshold to zero\" allows you to strip high level voxels " "out of the rendering process. In general you won't want this, but it might " "be useful if you have high valued areas in your data set that obscures what " "you'd like to see. The second option \"Accelerate Rendering\" tells VolPack " "to use a faster method for doing the volume rendering. You will in general " "want to use this option, as it causes a significance performance enhancement " "(around 10 fold). It does, however, require around 3 fold as much rendering " "as the non-accelerated option, so if you're running out of memory, you'll " "want to try to rendering without the acceleration. The third option " "\"Initial opacity functions only density dependent\" sets things such that " "the initial gradient opacity function does not contribute to the rendering. " "This is useful for data sets (e.g. PET) where one is more interested in " "having an accurate view of the data, rather than a view where gradients in " "the data set are highlighted." msgstr "" "Para comenzar la ventana de Renderizado, seleccionar los volumenes y ROI's " "que deseara incluir en el rederizado, y pulse el item del menúg \"View->" "Rendering\" . Se desplegará una pequeña ventana de diálogo con dos opciónes. " "La primera \"Set values greater than max threshold to zero(Poner los valores " "mayores que max a cero)\" permite excluir del proceso los valores máximos. " "En general no deseará esto, pero prodría ser útil cuando hay valores muy " "altos que obscurecen zonas que quisiera ver. La segunda opción \"Accelerate " "Rendering(Acelerear Renderizado)\" hace que VolPack use un método de " "aceleración del proceso de renderizado. Obtendrá un aumento de velocidad " "(sobre 10 veces). Sin embargo requiere aproximadamente tres veces mas de " "memoria RAM, así si dispone de poca RAM no use esta opción." #: ../C/amide.xml.translate:1637(para) msgid "" "After hitting \"Execute\" the program will reslice the data sets and ROI's " "into a data structure that the volpack library can handle, and then perform " "some initial renderin gcalculations. For data sets, the interpolation type specified for the data set will " "be used. This whole process will take some time, so be patient. Please also " "note that, when converting the data set, the data is scaled between the " "current minimum and maximum threshold, with all data above the current " "maximum threshold set to the maximum threshold value (or zero, if " "specified), and all data below the current minimum threshold set to the " "minimum threshold value. This scaling can be relative to the data set's " "\"Global\" maximum and minimum, to the \"Per Frame\" maximum and minimum, or " "can be from maximum and minimum values \"Interpolated Between Frames\". " "\"Per slice\" scaling does not make sense in the context of volume " "rendering, and is interpreted as \"Global\" scaling." msgstr "" "Despues de pulsar \"Execute\" el programa convertirá los volúmenes y ROI's, " "al formato utilizado por Volpack y hará los cálculos iniciales de " "renderizado. Para los volúmenes se utilizará el tipo de interpolación especificado. Este procedimiento tarda algo " "de tiempo , luego sea paciente. Por favor note tambien,que al convertir los " "volámenes, los datos se escalan entre los límites mínimo y máximos " "establecidos, luego todos los datos mayores del valor máximo se igualaran al " "valor máximo y todos los valores por debajo del mínimo se igualaran al " "mínimo. Este escalado pude ser relativo al mínimo y máximo \"Global\", al " "mínimo y máximo \"Por Segmento de Tiempo(Frame)\" , o al mínimo y máximo " "\"Interpolado Entre Segmentos\". El escalado \"por Corte\" carece de sentido " "en el contexto de rederizado volumétrico, y sera interpretado como escaldo " "\"Global\"." #: ../C/amide.xml.translate:1654(para) msgid "" "When all this is completed, the rendering window should pop-up. Its use is " "described below." msgstr "" "Cuando se finaliza esto se despliega una ventana. Su uso se describe abajo." #: ../C/amide.xml.translate:1659(title) msgid "Rendering Window" msgstr "Ventana de Renderizado" #: ../C/amide.xml.translate:1661(title) msgid "Main Rendering Canvas" msgstr "Panel Principal de Renderizado" #: ../C/amide.xml.translate:1662(para) msgid "" "The result of the rendering process is presented on the canvas in the center " "of the window. This canvas can accept user input to change the orientation " "of the rendering. Button 1 allows rotating on the x and y axis, and button 2 " "allows rotating on the z axis." msgstr "" "El resultado del renderizado se representa en el centro de la ventana . Esta " "ventana permite la interacción con el usuario. El botón 1 permite rotar en " "el eje xy , y el botón 2 permite rotar en el eje z." #: ../C/amide.xml.translate:1672(title) msgid "Spin Sliders" msgstr "Barras de Giro" #: ../C/amide.xml.translate:1673(para) msgid "" "You should notice two slider type widgets, one on top of the rendered image, " "and one on the right side. These are both appropriately labeled with the " "axis around which the rendering will be spun if they are changed. " "Additionally you should notice a dial widget (labeled 'z'). The dial is for " "rotating on the z axis (which comes out of the plane of the display). Note " "that the effect of rotations are cumulative." msgstr "" "Existe dos barra de desplazamiento, una encima de la imagen renderizada, y " "otra en el lado derecho. Estas estan marcadas apropiadamente con el eje " "sobre el cual rota el volumen. Adicionalmente existe una rudecilla marcada " "con la 'z'. esta ruedecilla es para rotar sobre el eje z, que es el " "perpendicular a la imagen. Nótese que los efectos de rotación son " "acumulativos." #: ../C/amide.xml.translate:1684(title) msgid "Reset Axis" msgstr "" #: ../C/amide.xml.translate:1685(para) msgid "" "This button will reset the rendering's orientation back to the default " "orientation." msgstr "Este botón situará el volumen en su posición original." #: ../C/amide.xml.translate:1692(title) msgid "Toolbar" msgstr "Barra de Herramientas" #: ../C/amide.xml.translate:1694(title) msgid "Transfer Function Button" msgstr "Botón de Función de Transferencia" #: ../C/amide.xml.translate:1696(para) msgid "" "This will pop-up a dialog with a panel for each object being rendered. The " "available options are described below:" msgstr "Este desplegará un diálogo con las opciónes abajo descritas:" #: ../C/amide.xml.translate:1702(term) msgid "Return Type" msgstr "Tipo Retornado" #: ../C/amide.xml.translate:1703(para) msgid "" "This setting determines whether the rendering returns an image which looks " "more analogous to an x-ray (the \"opacity\" setting), or returns an image " "which looks more like a surface (the \"grayscale\" setting). The \"grayscale" "\" setting does this by specifying a light source, material properties, and " "using depth cueing." msgstr "" "Este determina si el renderizado sera mas análogo a una radiografía (the " "\"opacity\" setting), o mas pareciado a una superficie (the \"grayscale\" " "setting). El \"grayscale\" hace esto especificando la iluminación, el " "material y usa indicación de profundidad." #: ../C/amide.xml.translate:1711(term) msgid "Color Table" msgstr "Tabla de Color" #: ../C/amide.xml.translate:1712(para) msgid "The color table of each rendered object can be changed here." msgstr "Aquí se puede cambiar la tabla de color de cada volumen renderizado." #: ../C/amide.xml.translate:1718(term) msgid "Classification Functions" msgstr "Funciones de Clasificación" #: ../C/amide.xml.translate:1720(para) msgid "" "This is the most confusing part of rendering, so hang on here. The " "classification functions are used to map between the value in each voxel and " "how much that voxel should be represented in the final rendered image. On " "the x axis is the possible values of the different voxels. On the y-axis is " "the opacity that will be given a voxel based on its value." msgstr "" "Esta el la parte más confusa del renderizado. Las funciónes de clasificación " "se usan para la correspondencia entre el valor de cada voxel y su " "representación final en el renderizado. El el eje x son posibles valores de " "diferentes vóxeles. En ele eje y es la opacidad lo que otorgara el valor en " "función del valor del voxel." #: ../C/amide.xml.translate:1728(para) msgid "" "Both classification functions have several buttons on the right side of " "their graphs. The top button allows the classification function to be drawn " "as a spline. The second button allows the classification function to be " "drawn as a series of straight lines. Finally, the last button resets the " "classification function to a straight line." msgstr "" "Las funciónes de clasificación tiene varios botónes a la derecha de sus " "gráficas. El botón de arriba permite dibujar la función como segmentos " "curvos. El segundo permite dibujar la función como varias segmentos rectos. " "Finalmente el último dibuja de nuevo la linea recta inicial." #: ../C/amide.xml.translate:1736(para) msgid "There are two classification functions:" msgstr "Hay dos funciónes de clasificación:" #: ../C/amide.xml.translate:1742(para) msgid "" "Density Dependent: This function tells you how opaque " "each voxel will be based on its current value. In a sense, this is analogous " "to an x-ray, where the amount of the x-rays that are absorbed in a structure " "is related to the density of that structure. of the display." msgstr "" "Dependientes de la Densidad: Esta función dice cuan " "opaca es en fución del valor del voxel. De alguna manera , tiene analogía " "con los rayos X , donde la cantidad de rayos X absorbidos depende de la " "densidad de la estructura." #: ../C/amide.xml.translate:1749(para) msgid "" "Gradient Dependent: Instead of relating the density of " "a voxel to its opacity, this function relates the gradient of a voxel (how " "much the value changes between this voxel and its neighbors) to its opacity. " "This has the effect of giving added weight to surfaces." msgstr "" "Dependiente del Gradiente: En vez de relacionar la " "opacidad con la estructura, esta función depende la opacidad del gradiente " "entre vóxeles (es decir cuanto cambia el valor de un voxel con respectoa sus " "vecinos). Este tiene un efecto de realzar las superficies." #: ../C/amide.xml.translate:1764(title) msgid "Monoscopic/Stereoscopic Buttons" msgstr "Botón Monoscópico/Estereoscópico" #: ../C/amide.xml.translate:1765(para) msgid "" "You can choose between generating a single rendered image (monoscopic), or a " "stereoscopic image pair. A stereoscopic image pair is a pair of images that " "have been generated at slightly different angles. When viewed correctly, " "these two images can be interpreted by the viewer's eyes as a single image " "containing depth information." msgstr "" "Puede elegir entre renderizar una imagen única (monoscópica), o un par de " "imágenes esteroscópicas. Un par esteroscópico de imágenes es cuando se " "generar a un ángulo ligeramente diferente la una de la otra. Cuando se las " "mira de manera adecuada pueden ser percibidas por el observador como una " "imagen única tridimensional." #: ../C/amide.xml.translate:1774(title) msgid "Zoom" msgstr "" #: ../C/amide.xml.translate:1775(para) msgid "" "Determines the size at which the resultant rendered image will be displayed. " "Note that changing the zoom will not affect the speed of the rendering, and " "increasing the zoom past 1 will not increase the resolution of the rendered " "image." msgstr "" "Determina el tamaño de la imagen resultante renderizada. Nótese que el " "cambio de zoom no afecta a la velocidad de renderizado, e incrementando por " "encima de factor 1 de zoom tampoco se incrementara la resolución de imagen " "renderizada." #: ../C/amide.xml.translate:1786(title) msgid "Rendering Menus" msgstr "" #: ../C/amide.xml.translate:1787(title) msgid "File->Export Rendering" msgstr "" #: ../C/amide.xml.translate:1788(para) msgid "" "This menu item allows you to export the rendered image to an external image " "file. The saved data format is jpeg." msgstr "" "Este menú le permite exportar la imagen renderizada a un fichero con formato " "jpg." #: ../C/amide.xml.translate:1794(title) msgid "File->Create Movie" msgstr "" #: ../C/amide.xml.translate:1795(para) msgid "" "This causes the movie generation dialog box to pop up. This dialog box is " "further described below: ." msgstr "" "Este causa el despliegue de la ventana de generación de video. Este diálogo se " "describe en mayor detalle abajo: ." #: ../C/amide.xml.translate:1802(title) msgid "Edit->Rendering Parameters" msgstr "" #: ../C/amide.xml.translate:1803(para) msgid "" "This causes the rendering parameters dialog box to pop up. This dialog box " "is described below: ." msgstr "" "Este despliega el diálogo del parámetros del renderizado. Este dialogo se " "describe abajo en: ." #: ../C/amide.xml.translate:1813(title) msgid "Rendering Parameters Dialog" msgstr "Diálogo de los Parámeters de Renderizado" #: ../C/amide.xml.translate:1815(title) msgid "Speed versus Quality" msgstr "Velocidad vs. Calidad" #: ../C/amide.xml.translate:1816(para) msgid "" "With this drop-down menu, the user can choose between rendering speed and " "rendering quality. To increase speed, voxels with values either close to " "zero or close to unity can be counted as completely translucent or " "completely opaque, respectively. The highest quality doesn't use this " "approximation at all, the lowest quality setting uses this approximation big-" "time." msgstr "" "Con este menúg desplegable el usuario puede elegir la velocidad y calidad " "del renderizado. Para incrementar la velocidad, los vóxeles cuyos valores " "sean el máximo y el mínimo, seran tratados como totalmente opacos o " "translúcidos respectivamente. La mayor calidad en cambio no usa esta " "aproximación, la menor calidad si." #: ../C/amide.xml.translate:1825(title) msgid "Stereosopic parameters" msgstr "Parámetros Estereoscópicos" #: ../C/amide.xml.translate:1827(para) msgid "" "These parameters are used for controlling the results when the \"stereoscopic" "\" option has been chosen." msgstr "" "Estos parámetros son usados para controlar el resultado cuando se ha elegido " "la opción \"estereoscópica\"." #: ../C/amide.xml.translate:1830(title) msgid "Stereo Angle" msgstr "" #: ../C/amide.xml.translate:1831(para) msgid "" "This is the angle offset (in degrees) between a pair of rendered images. " "Increasing this number will generally give a greater sensation of depth in " "the image pair. A Reasonable value for this parameter is between 2 and 5 " "degrees. Note that this parameter will be saved between different sessions " "of the program (not currently done on MS Windows)." msgstr "" "este es el angulo (en grados) entre el par de imágenes renderizadas. " "Incrementándolo dara mas sensación de profundidad. Un valor razonable para " "este parámetro es de 2 a 5 grados. Este valor se puede guardar entre " "diferentes sesiones." #: ../C/amide.xml.translate:1839(title) msgid "Eye Width (mm)" msgstr "" #: ../C/amide.xml.translate:1840(para) msgid "" "Ideally, this should be (roughly) the distance between the two rendered " "images, and corresponds to the distance between the user's eyes. It is " "impossible for a person to resolve a stereoscopic pair if the images are " "farther apart then the person's eyes, since human eyes cannot move " "independently. While this parameter is specified in millimeters, the " "actually distance between the pair of images that gets displayed on the " "monitor depends on the setup of the computer. If the monitor information " "reported by the operating system is not correct (usually the case), the " "\"eye width\" parameter will not be in true millimeters. Note that this " "parameter will be saved between different sessions of the program (not " "currently done on MS windows)." msgstr "" "Idealmente correspondería a la distancia entre los ojos del observador. " "Aunque este parámetro está especificado en miliímetros, la distancia real " "entre las dos imágenes depende de el ajuste de pantalla de cada ordenador. " "Si la información del monitor que tiene el sitema ioperativo (que " "normalmente es el caso), the \"eye width\" el parámetro no estara realmente " "en milímetros. este parámetro pude ser guardado entre sesiones." #: ../C/amide.xml.translate:1856(title) msgid "Depth Cueing" msgstr "Indicación de Profundidad(Depth Cueing)" #: ../C/amide.xml.translate:1858(para) msgid "" "These parameters are only used if the \"grayscale\" output type has been " "chosen." msgstr "" "Este parámetro sólo se usa cuando los resultados son \"en escala de grises\"." #: ../C/amide.xml.translate:1861(title) msgid "Enable/Disable Depth Cueing" msgstr "Permitir/Anular Depth Cueing" #: ../C/amide.xml.translate:1862(para) msgid "" "Specify whether or not we want depth cueing. Depth cueing puts in a \"fog\" " "that causes more distant voxels to appear less bright." msgstr "" "Especifica si queremos o no 'Depth cueing'. Depth cueing pone una \"niebla\" " "que ocasiona que los vóxeles mas distantes aparezcan menos brillantes." #: ../C/amide.xml.translate:1867(title) msgid "Front Factor" msgstr "Factor Frontal(Front Factor)" #: ../C/amide.xml.translate:1868(para) msgid "" "This is the transparency of the fog at the front of the data set. If this " "number is greater than 1.0, voxels toward the front of the data set will be " "brightened. If this parameter is less than 1.0, voxels toward the front of " "the data set will be darker, respectively." msgstr "" "Es la transparencia de la niebla que se halla por delante del volumen. Si es " "un número mayor que 1.0, los vóxeles de delante del volumen apareceran mas " "brillantes. Si fuera menor que 1.0, los vóxeles de delante del volumen " "apareceran mas obscuros." #: ../C/amide.xml.translate:1875(title) msgid "Density" msgstr "Densidad" #: ../C/amide.xml.translate:1877(para) msgid "" "This is how thick the \"fog\" is. The thicker the fog, the darker distant " "objects seem." msgstr "" "Es cuan gruesa el la \"niebla\" . A mayor grosor de niebla los vóxeles " "aparecen más obscuros." #: ../C/amide.xml.translate:1884(title) msgid "Rendering Movie Dialog" msgstr "Diálogo de Animación del Renderizado" #: ../C/amide.xml.translate:1886(title) msgid "Frames" msgstr "" #: ../C/amide.xml.translate:1887(para) msgid "" "How many frames should be in the MPEG1 movie. The MPEG1 movies generated " "will be set to run at 30 frames/second, so the default of 300 frames will " "give a ten second movie." msgstr "" "Cuantas imágenes debería haber en el video MPEG1 . Los MPEG1 se generan a 30 " "imágenes/segundo, así el valor por defecto, 300 imágenes dará un video de 10 " "segundos de duración." #: ../C/amide.xml.translate:1895(title) msgid "Rotations on [x,y,z]" msgstr "Rotatciones en [x,y,z]" #: ../C/amide.xml.translate:1896(para) msgid "" "This setting determines how many times the data set will be rotated around " "the given axis over the course of the movie. The rotation for each frame is " "done in x->y->z order (rotate on x first, then y, then z)." msgstr "" "Esto determina cuantas vueltas sobre un eje dado ocurrirán a lo largo del " "video. La rotación de cada eje sigue este orden x->y->z (rota primero " "x , luego y, y al final z)." #: ../C/amide.xml.translate:1904(title) msgid "Dynamic Movie: No/Over Time/Over Frames Smoothed/Over Gates" msgstr "Static/Over Time/Over Frames" #: ../C/amide.xml.translate:1906(para) msgid "" "This option allows a rendered movie to be made over a time period, which is " "useful for dynamic data sets." msgstr "" #: ../C/amide.xml.translate:1910(para) msgid "" "Note that every time a frame boundary in the data set is passed over, the " "rendering process must slice and load in a new frame of data. This makes " "creating a rendered movie over time significantly slower than a movie with " "just rotations." msgstr "" "Nótese que cada vez que se atraviesa un marco de tiempo del volumen, el " "proceso de renderizado debe de cargar y prepara otro marco de tiempo. Esto " "hace que crear un video de renderizado dinámico es significativamente mas " "lento que crear un video solo con rotaciones." #: ../C/amide.xml.translate:1916(para) msgid "" "Picking \"over time\" will allow entry of a start and end time for which the " "data from the data sets should be drawn. With the \"over time\" option, each " "second is given equal waiting in terms of how many images from that time " "period are generated for the output movie." msgstr "" "Esta opción permite la creación de un video de un estudio dinámico. " "Seleccionando \"over time\" le permitiría definir el tiempo de inicio y " "finalización dentro del volumen dinámico. Con la opción \"over time\", cada " "segundo es igual en terminos de cuantas imágenes de ese periodo de tiempo " "seran generadas para el video." #: ../C/amide.xml.translate:1922(para) msgid "" "Picking \"over frames\" allows entry of a start and end frame (note that " "this really only makes sense with a single data set). The advantage of " "\"over frames\", is that each frame is weighted equally in terms of how many " "images are generated for the output movie, so for data sets were the " "dynamics of interest correspond closely to the dynamics of the data set " "framing sequence, \"over frames\" may give a more appealing result." msgstr "" "Seleccionando \"over frames\" permite la la entrada de la primera y última " "imagen (esto sólo tiene sentido cuando se trata de un volumen único). La " "ventaja de la opción \"over frames\", es que cada marco de tiempo repercute " "por igual en el video final, asi cuando la dinámica de interés corresponden " "a la dinámica de la secuencia del marcos de tiempo del volumen, dando un " "resultado mas atractivo." #: ../C/amide.xml.translate:1931(para) msgid "" "The \"over frames smoothed\" option is almost the same as \"over frames\", " "except that data will be interpolated between frames. This makes for a " "smoother movie (no jumps) but takes much longer as nearly every movie frame " "has to be reloaded." msgstr "" #: ../C/amide.xml.translate:1948(title) msgid "Additional Tools" msgstr "Herramientas Adicionales" #: ../C/amide.xml.translate:1950(title) msgid "Alignment Wizard" msgstr "Herramienta de Alineamiento(Alignment Wizard)" #: ../C/amide.xml.translate:1952(para) msgid "" "In addition to manually aligning data sets (described at ), data sets can also be aligned using the alignment " "wizard. The process is basically:" msgstr "" "En adición al alineamiento manual (descrito en ), los volúmenes tambien pueden alinearse con el " "\"alignement wizard\". El proceso es básicamente:" #: ../C/amide.xml.translate:1958(para) msgid "" "Draw at least three pairs of fiducial makers between the two data sets that " "you wish to align. Drawing fiducial markers is described below as ." msgstr "" "Dibujar al menos 3 pares de puntos fiduciales en los volúmenes que desee " "alinear. El dibujo de puntos fiduciales se describe debajo como ." #: ../C/amide.xml.translate:1965(para) msgid "" "Run the alignment wizard (under tools->alignment wizard). For the " "alignment wizard to recognize two fiducial markers as a pair, they must have " "exactly the same name. So if you have a marker labeled \"1\" under the first " "data set, you will need another marker, also labeled \"1\", under the second " "data set." msgstr "" "Corra el \"alignment wizard\" (bajo tools->alignment wizard). para que el " "\"alignment wizard\" reconozca 2 marcadores fiduciales como par, deben de " "tener exactamente el mismo nombre. Así si tiene un marcador llamado \"1\" en " "el primer volumen, tendrá que tener un marcador, también llamado \"1\", en " "el segundo volumen." #: ../C/amide.xml.translate:1976(title) msgid "Drawing Fiducial Markers" msgstr "Dibujando Marcadores Fiduciales" #: ../C/amide.xml.translate:1977(para) msgid "" "Fiducial markers can be added to any of the data sets in the study in a " "variety of ways. For the currently active data set, hitting the \"Edit->" "Add fiducial mark\" menu item will drop a fiducial maker at the currently " "viewed location. Fiducial marks can be added for the active data set " "directly from the views by pressing ctrl-right mouse button, which will drop " "a fiducial marker at the point that the mouse is currently at. Finally, " "fiducial markers can be added to non-active data sets by pressing ctrl-right " "mouse button while hovering over a data set's name in the study list." msgstr "" "Se pueden añadir marcadores fiduciales de varias maneras. Para el volumen " "activo, seleccionar el item del menu \"Edit->Add fiducial mark\" y " "añadirá una marca fiducial en la vista seleccionada. Las marcas fiduciales " "se pueden añadir directamente a la vista activa pulsando CTRL+botón 3 del " "raton, que dispondrá una marca fiducial en el lugar que apunte el ratón. " "Finalmente, los marcadores fiduciales se pueden añadir a volúmenes inactivos " "pulsando CTRL+botón 3 del ratón mientras se selecciona el volumen de la " "lista del estudio." #: ../C/amide.xml.translate:1988(para) msgid "" "After being created, the fiducial marker can be moved by clicking on the " "marker point shown in any of the views." msgstr "" "Después de crear, el marcador fiducial puede ser movido pulsando el punto de " "marcaje en cualquiera de las tres vistas." #: ../C/amide.xml.translate:1993(title) msgid "Fiducial Marker Modification Dialog Box" msgstr "Caja de Diálogo de Modificación de Marcadores Fiduciales" #: ../C/amide.xml.translate:1994(para) msgid "" "To modify parameters of a fiducial mark, right click the point in the study " "list to pop-up the Fiducial Marker Modification Dialog. From this dialog, " "the name and location of the fiducial marker can be altered." msgstr "" "Para modificar los parámetros de una marca fiducial, pulse el botón 3 en la " "lista del estudio para desplegar la Caja de Diálogo de Modificación de " "Marcadores Fiduciales. Desde este diálogo, se pueden modificar el nombre y " "localización del marcador fiducial." #: ../C/amide.xml.translate:2006(title) msgid "Crop Wizard" msgstr "Herramienta de Recorte(Crop Wizard)" #: ../C/amide.xml.translate:2008(para) msgid "" "Coming soon. Note that only what is strictly inside the cursor lines is " "saved. What's underneath and outside the cursor lines is cropped away." msgstr "" "Permite recortar los volúmenes quitando de ellos las partes carentes de " "interés. Se abrirá un diálogo con el MIP del plano axial, existiendo unos " "modificadores de dimensión que dibujarán una caja en el MIP, una vez " "seleccionado pulsar Next y aparecerá el MIP coronal, ajustarlo y pulsar Next " "de nuevo aparecerá el MIP sagital, recortando así, el volumen desde los 2 " "planos." #: ../C/amide.xml.translate:2014(title) msgid "Factor Analysis Wizard" msgstr "" #: ../C/amide.xml.translate:2015(para) msgid "" "The factor analysis wizard is currently being developed. It probably won't " "work for you, and is only included in AMIDE for those who might be " "interested in working on it (rather than with it)." msgstr "" #: ../C/amide.xml.translate:2022(title) msgid "Filter Wizard" msgstr "Herramienta de Filtrado" #: ../C/amide.xml.translate:2023(para) ../C/amide.xml.translate:2028(para) #, fuzzy msgid "Nothing written yet..." msgstr "" "#-#-#-#-# es.po (PACKAGE VERSION) #-#-#-#-#\n" "Permite aplicar filtros de Mediana lineal y 3D, y Gaussiano al volumen " "activo.\n" "#-#-#-#-# es.po (PACKAGE VERSION) #-#-#-#-#\n" "Crea un video de los cortes extraidos e cualquiera de los planos, axial, " "coronal o sagital, determinando el corte de inicio y el corte final." #: ../C/amide.xml.translate:2027(title) msgid "Fly Through Wizard" msgstr "Creación de video en una Orientación(Fly Through Wizard)" #: ../C/amide.xml.translate:2029(para) msgid "" "Note, will generally get much better results for fly through if using " "trilinear interpolation." msgstr "Nota, los resultados son mejores si se usa interpolación trilineal." #: ../C/amide.xml.translate:2034(title) msgid "Profile Tool" msgstr "" #: ../C/amide.xml.translate:2035(para) msgid "A complete description of this tool has not yet been written." msgstr "" #: ../C/amide.xml.translate:2037(para) msgid "" "The left and right limits of the gaussian fit can be altered by clicking on " "the profile with the left and right mouse buttons, respectively. The x value " "used for initializing the gaussian fit can be picked by clicking on the " "profile with the middle mouse button." msgstr "" #: ../C/amide.xml.translate:2046(title) msgid "ROI Statistics" msgstr "ROI Estadísticas" #: ../C/amide.xml.translate:2047(para) msgid "" "A description of the ROI statistics tool can be found at: ." msgstr "" "La descripción de la estadísticas del ROI en: ." #: ../C/legal.xml:2(para) msgid "" "Permission is granted to copy, distribute and/or modify this document under " "the terms of the GNU Free Documentation License, " "Version 1.1 or any later version published by the Free Software Foundation " "with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. " "You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to the " "below address." msgstr "" "Se garantiza la copia, distribución y/o modificación de este documento bajo " "los términos de la Licencia de Documentación GNU, Versión 1.1 o posterior " "publicado por la Free Software Foundation Puede obtener una copia de GNU " "Free Documentation License de Free Software Foundation visitando su sitio web o escribiendo a la " "dirección abajo indicada." #: ../C/legal.xml:13(para) msgid "" "This program is free software; you can redistribute it and/or modify it " "under the terms of the GNU General Public License as published by the Free " "Software Foundation; either version 2 of the License, or (at your option) " "any later version." msgstr "" "Este programa es software libre; puede distribuirlo y/o modificarlo bajo los " "términos GNU General Public License publicada por el Free Software " "Foundation; o version 2 de la Licencia, o (bajo su criterio) cualquier " "versión posterior." #: ../C/legal.xml:18(para) msgid "" "This program is distributed in the hope that it will be useful, but WITHOUT " "ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or " "FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for " "more details." msgstr "" "Este programa se distribuye con la esperanza de ser útil, pero SIN NINGUNA " "GARANTIA, sin incluso ninguna garantía MERCANTIL implícita o sin garantizar " "la CONVENIENCIA PARA UN PROPÓSITO PARTICULAR. Véase la Licencia Pública " "General de GNU para más detalles." #: ../C/legal.xml:23(para) msgid "" "You should have received a copy of the GNU General Public License along with " "this program; if not, write to:
The Free Software Foundation, " "Inc., 59 Temple Place - Suite 330, Boston, " "MA02111-1307, USA" msgstr "" "Debería haber recibido una copia de la Licencia Pública General junto con " "este programa. Si no ha sido así, escriba a la Free Software Foundation, " "
The Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-" "1307, USA
" #: ../C/legal.xml:35(para) msgid "" "For more details see the file COPYING in the source distribution of AMIDE." msgstr "Para más detalles vea la copia distribuida con uAMIDE" #. Put one translator per line, in the form of NAME , YEAR1, YEAR2. #: C/amide.xml:0(None) msgid "translator-credits" msgstr "" "Pablo Sau , 2002" amide-1.0.6/amide-current/help/es/figures/000077500000000000000000000000001423227705100203425ustar00rootroot00000000000000amide-1.0.6/amide-current/help/es/figures/amide_main_window.png000066400000000000000000001757071423227705100245430ustar00rootroot00000000000000PNG  IHDRD^~[bKGD pHYs."."ݒtIME &R$ IDATxw@lJRDT h1ib5y)1Xb RT ;:3c6Xݻv9qH;w@A@TVKtKн6Jwt sss{{>I=zWF333h4GV0|}I" % C@@76w(tRclY,QRa8$@5A@O#Z ]_'ϟJ=) o=v] p(BL&TVVZXX==zuzGB~;{섄={tv 1 13kٵjN#wtTƂ*qR[D*jޯ75 J.R$^]' @<<AU_Fk7ݟ(iw!9|0k׮500hmmy#G=/O)wKK˗=zt׮]d2Y*)KeXKko՘LZY%b#\dfa0T*T"w(ZFjra&&v*wPc@eԟ.} b[c]BO-I^p4"QT=z w "ɞcƌR2 So<,WW76JeP&I2j5ܡPj DR6C*TQR؀K}GbkekD(ß, Ci'*_V'mhf{ܵ?/UƱ߾};LfͽrѣRt: (:u w8҅ OZlBPOO/u? 8?-}؀, R---ѣ`0 նDꕑ;RfZ =zs=z3+w=z2P;㥥ZO Ʋ&>hyyR|aohhhkk---#~GT='[ZZRP(wǏ ɓ'3̔ZMPp700dT*ի0 ܿ5..N+JD+MMMR)a4PZZp޽khh T*rN755 ѣGK0 VB0;;[,[n Bcc㼼ﷴ 555T*URS(ETT*}ammmmm- JBۿr\,B!DH$b* ;zt@[&''Ĥ"`V$L&+J*8HW( AA'y h4F)J&)J D"h0 T*FCRr90LRh4BA&&&Jq5JjmmR P.H$_9yT*D<OGd(+zG0 2z^/>>>_|ѣGe@lh|||t+=z,6l1cw}WRRxqDD'٧hoooooݻ~ y}!bbbMMM###ۢ"Bkt FAQ411`ؐHW0%%]w._ 077dA "11ƆD{UƦҥK]((GGT__ߙ3g ²\?Bd2mllRibbZNLLJ> P]YfX,tڵkW\yL6/`Æ 111gdd2:%///+++--Et]?N|x…œ'O>~8F[`+W,--: 8wܺux<ŋϞ=qٳg=zT;uMMܹsKKK|T*=<vvvgΜ;vѣG'NDR_GD8i$77;wr\F}aǷlr!&%K:t?h4[nܫW^O #]N>뛐 \h,XPRR2a„~N,_fgӦM=z/윞r7mtwEDD|7|\._t|򊊊YYYc/ZmԨQ^ggŋSRRFѣF]|K.ݽ{M6>>>妤8;;o۶oJII^땻.駟233_mvʕ+WT:$((yݼys񩩩Ǐwuuݵk׆ /\oܹ;??ݻW\9ui4ڝ;w7mڴbŊ7.\pҤIvss#شiɬx>ގaX~~IJJJƌdbb믿fee]tE牭RVZe˖}-X?_llly"h}?Jw^fMNNΪUf̘ygo7n͛7=<<&L=nܸ144Zlه~9{+֚C޼yW^---ݸqѣcbbNz֭[W^M̾f͚O>ѣSLqppؽ{weeeUUնmV^} X";;AS;v5/**233#[xxϟ?R^땻.Yrʕ+322{P  YbEJϘTYf9Hkڲe###6l nݺj*A&Nj*ghhB W *2dΜ9YYY 766Gr|IbUWW\&,,,??dԡx&[#%%B /^lcc`ǏԬZ&444??xQWP.@ɓ۷osNZZҥKy<^>%%%Ǐ;vldddvvZ>qB0gaooODh7l0dȐt[[[7|А9s#˕wޅ h"H |۷͜9.00p~~~SNh1Rtƍ>T*h4FP`&(ZM6d[[[\~ ӧT5kּ+@RT*mioo766)lmm-[l2@uuunnnZZZNNNeeeotpp3gN/J2耞E13 5ʯ^Z[[O?EEE nb577[XX477kougt@ q(*JRݿ&pRD"aXL6}݅ \bffFp8t:`P(&wwޚFGG߿?::z޼y555X,DV92zhyf.xbzX,@HNN&L&sϞ=[o5tnL;T*?0,55uϞ=ӧO:ujAA}Ba||<@Tы-|auu55jԎ;bqGG?n_'LT*;::^Sr)++fX.\.WRuvvzxxY&M4իӧOoߞ={T*mll400p830.;;;;;;33B7!*>J$smٲ[dIGG37.\啑A/"^zw>Ğ'9sݻ,XÞ{Ϟ={ڵAAA'O xfb2 b֬Y|>U?_|2, x￯Z/^\hٳ׬Y/?󰰰Rs΍xT*6mO?ԵOHHƍ͛Du[[ݻwegg߼y]h^__)b:&;={6&&iǧٳg?/RiBB”)Sƌcmm㸍ͶmBBBd2R֭YYY7o˗/}||f̘AϞ=`YXX>: ˗/{zz%%%;PI_.\?mmm㏎__ߛ7o;99=~gX .444lll0lܹ]G+)) hR4338)))4SNa8!!/((Ç|>ǏE.--x񢡡 ?~ J}}}b3g|>q O&--FM2e8gdd8;;GFFR(˗/]V*:u7 ^92==uȐ!yyy\.>///33'$$$++W{1 KKGTVV2 Rijj gHkk!{fccXQQ`0PebeiiA"@mmmFFFffۦMzkX=ɵkf̘SXXԔ͢GϋSVVrʶw%}-?Eii[\nhhh}=z^ǏgeeQԐW6w=z#G9r/>;a3@ Ȁ2=}JTTwܩkA^e˖準e 2;uw8 By~JVϞ=yK{d8G믿ō{B޾}Futtݽ{`xyyXZZvvvŽ֦&CCÊ ssƎdL͠ @"F^͵*&,ʗk4r^UD"qaÆYYY`g38Dw=H$066:ueϏ㵶BDFAQ#PAa eԨQl6:+++::Z(vM3Tjj:YL*CM-:į  PL&wG5jT{{;A+++svvh7n!S+Jwܙ5k,GVWVV u-˿ .H$9s# z`[[ۢsW0 H/w R^^f5 QM B"'B0 EQ2or޽#G c„ iii刌<Kt-exp\21,6/L͝H$붼8lՄ'''++,Hw]Ajj&3@H$"[Ak"УG B>}#G,XkqU$%%dW? PDǾN#aL& ${Pz޻;wd] 2]"bȐ!8wvv 'y<+/;::ALD'',,L&;w믿~= III&Lе,>TD"( AU(vvv> Bh4HD"( qJ0fU*a&2djD&BT*]7dL&LaaZ h42V{0򔔔+W$zP(S&%%ݻw[K|J '\@*[Ν;p+遁mmmǎ4iRyy\.P(bظ\*BR4P|>a++;w888HRcccH$ҤI^J6E ɓBa}.\ ._f`` ̪삃'x @Cter-N:/@iݻl6`aaannNR---ʪD"4110޽{ݒ`Fb1@RJAA^M'n5J%L0MѴ3>lj҈vW6%%eĉ---ږݻwEQUU5qĶŋs:ŤI"v9996l_P‰'i$**D"?^ׂK ׮]366 |=z4 ׯ1IӝP]]|/ҭ}r>}:a?xZ`.K"f͚eeeH$a??ڮfk'''Tp6nCoooPA+l#TSS3vخAL#F044T(VVVk׮~L&b30_U6ggnHa!ɮ_Nd@#lkIREJP(o߾֭[酅b&bL8QSS.k4be@<&Aojmmmooݚ}sEL`^HׯGEE999.8rDP*l6[{jLFZ(dɒ .,]t񶶶F,cr)T*r9!DNC*J| ̛7> z2tEKR-mܹ\.Z1[ IDAT cСd2p8+++CCCwwwVmmmj}ذa(X,&IPZ^Dbffյ>a[[!Vfff*LPXZZb$1'N\ svvvڢ8o޼9,,L"|wVVVׯ0ݻǏ:˗ӧOgXiiiwl۶rϞ=?vvv.))9s挓SeeLR__q|H evv3^N CQ455Uׂ O&**jǎ;vXti^^5kVZuIkkkSSS/O4tժU#G433ڳwt(0l0SSu}w4ѣGD1cZ_lffޮT*̙cnnnkkoͮ N>}ȑ-[޺u맟~JMM}wƌtݯs^|Y&]v-** & Մ;vBFQ__jooV mmmaaa%dӦM%%%O,o`Ѕ@6^6""9v\.葝G}UUU⧟~ڶmosĉZ;zhJJ 1,Lپ}X,622ںu@ ڼy3ðuֽ---{=w\ffGnݺ}UVnڴiĈNXXX{{;"3g<5\!&L`2ڐ{9ڵk*/R(ߺuٳL&3448ׯUT][lað߸qb7o޼}v71cX,-ޒ;w3>>></55UP"_"ٳ{7꧟~J>|8h9"J $tqq1446lFyA@_gffn۶̬ðYfUUUi +7mmmEEET*[nֆA>|foDEh@wvvn.*Ɉ6cǎ]ѣG o177/))quu=tPEEۻLMM'NӧO6Ç"6vZ"EBa@@(4񆆆roRSLʚ6m$$$^dԨQraX",Z믿tvv}Awttٳ'<<<88ܹs\.w„ [l}"f׬Y#҂aXqqq\\L&s\>ϻ P(t-sQTl6[QP(Z[[-,,t+pqq!ceɓ';w,**3f̚5k̊nܸiӦ۷߼yڵk]58s^zI8uTSSӕ+WH[nD@///H4~/^x.]͝>}\.n⒓/_x/jH$sСӧO BX.5k֘XCCѣG/[,$$=""---111fP(+Vݻ7777%%%66622rϞ=aaa~~~ d:uj޼yWxŋ;׬LT*T*jjj5j5֦q~/tdlmm}B hذaÇtiIIJ*--uttRϟWT3g433q<==J$OOϮI$R///L&ֶ-!!ABsܡC޹sV(>xÇ ֶZ*VTT\v&&&?k5h1bmNNNiiivtt,))h\KVSN-Zhҥ^LVRRuD7nA|>?99y„ ?ǫ"jkk=<N(Ǐo޼NL>ؙ?N{ȑna,(N2%##c?|~~~7n())qww׵,c(T}&2cǎ%,---~~~-b22LV 6ͭf$J;,P(`foG766j4LVVVfhh믿h[XX̚5o3f\uqqy7_l=/޾vZ1+9sfԨQ֭Ӊ#44ƍM B!WOsnggWSSC8KҀbg0*E̤RRlmm}-@5P `DO(p`=xĝQKKˈ#Q___L"^ڷ(J+zW=ZdrqFFFO ܴiӘ1c´i> .zJrɒ%/E+!C}:QjȐ!RT|>„ eeeDƇMmR&YUU~z6lذډ'nѣG8p`׭<Ç*((ӻ #.]211 Keee_5=t萮ey!jN.H&:55ɩ aCCCG||<ԩSĺ@P888 BU*D9'mF377hl6 "Y|ֱEQIN!2g2,bu-cg`bmm}1z뭮tE`` VgΜ9Lj^ZP|'ښM>TOfff_ں!CH$'''"-Akk+a2<ݻ˗//++뚆ԴC.pݻ$0uuu B[ @dWTDP Jmooh4\.\;)5BUDbe d2Y[[H$qLC+3gܹsΝ;###z(~WIIIW֡"7=|pNN kVȞ!R^֭[+++'M Zj5 M0,..HRY[[5y8?RW^>ظʊ{)6oaWW׏>l6[9gϞMOOY}ꨨv]H"._+>B033<08p@5^osmhh(**$''O2۷~hoo?w\nn.㝝 GGܬuojj:p3gJJJK"PO>}x*jH$N>0GGǠ .AСC.]'44EѳgJQ [~2ͿKJj ɓ'CBBt HdddRRRQQD"9sǏSk׮tvv,ںfff?SaaappmLLR/{'v6۷oʕiiiaaa{MOO=\.7n̙3Ǐ__>##c{%>{쒒|:;wnAAcǂ}ƍ۵k3`5kjBuV{{u|>k'?KKKLf}})=zŋՍ=Z]]M4;Vi<@9rcLjpuu!nNRRB fΝ?_dxrW* Ba^D6C`hl|淯v5xeccc;::ZZZ޸qĉ!!!qqq~~~'N7n{]]?L\]]I$ptt\dɝ;wlqΜ9wپ}{ttc}}=OIIqqq ]%--MV;::Qyi̙-]TPd29<<<3g])**ꫯ8 5 2NR/_sA?)ᨨ(SSS#áP(+Vr'OqBd*JhaÆر>3fLXXؔ)Sw!KK˝;wڒH$bUgYZZn޼:(((((crÆ MMM/---?3}f9sE\q}g: 5Aٍ˗/xLDFF`nnڵkhmmy8'N:аk.*zq][ 2N"<<<P(d,ݻ#FpBhh%M:u۶mRtܹ]Ln ;;D8;-[D^d)PG|^)C rJPPЍ7&LP^^+Iv9cƌ/_W/Ȍ3 82ygϞ?q:wdAѣGʽ$uQ,3033KNN7n"a:tӧ~޾D_̋𓉈mmm6lƲlл 2of .6wq_ B9{ݻAddɓ'u";~8͎)((y-Zh>3@p5cccm]?/[L:J;055@@ Oo?8&&fҥuuu~a1q}[]]v%%%EDD\vŋW^MII*u ݻwk[֬YcffGw4(((<<|̙ 2l:=q℥W_}GWȢlJm.\ u8 W*/>z(Q?AQt…ӧOOHH aXUUU<8^TTaaJhu3+ ^RBLZ=p8N]]]jjԩSz^>?gΜbWEEũSEded2ه~ק%UZ '? ͽ /**277?yyZ[[YA92z˗/ٳh5k֌3PYJejjkgg%JrV5SL~>Duuuٳg;wN$/^,,,?~W_}UQQ1sfNH$///>E(r\QɏB- >ڵkcƌpBpppw6`0C$hswwOJJ*++^Ff͚yeR5G1yxf^Tzܹٳg;99SÇ߿?h:]1ȔD"Y~tV###Rir/|ѣGw}566+;99EQtŊƍӺ|Wbd2_~e円ןz{N>GYFjkkܹ},lmmb.2Ȕ;&/3ʽ044|%KL ?}5k9r>`ܹÇonn&dff޻wWƟ3gN>% H?dbb駟ѼO~N˽{Fy>T' 2ABL&uWޯH?=,,֭#Nˍ7]P===KK>lxwtwd]ԘU IDATT;wN[ﭏ`0M Uʽax֭h˖->mhhx뭷zk+.\8qb׽;wW&6l[o+C,ό O1W}ʔ)K.I:3{ӧ"dʝL&O4O|j >zzX@)))MVbH$Ct;v2d?) L2y>] Zl?w{ ]vm߾YS\\\iiiddd8KҁAvXt]/űcǞپm677ލo>K.=Ï?8gΜޚn5>~x&Oh4zޮtvv>-N{TTTDDLbouҚ0aBYYY1 {2rXu^T###AH$?0Cpa úp@q, 0d2ܨœD"p0P8q0!1  &8 A8jHKkTHҲ/l]Cp9J|m0`1,pq 0 (6(ɓ'0AWrL}AGGQS͟Y>!--AIєB!pCD&,Y T~ O*A=Q0 ?X)51`5D`4D"kP5 !a;{Jwt'?uRJ$*R1 Vd2(LCJ2Ti(J)PYFA4 *U8 +UTJ&>"v|+5>=iٽ[0*4l&U*\T#D!V1! T60NEr`1"⪔B@bqܛ>%B&.SbI6S,c8 % $JRIF8F!,pC]$L\@)Q*j!WHp2V1ihF2)A5" aT 3$\Ag0rd%dQ1Lb2$r)ŒKlLR%Mɠe2*tb*fE't{NX-QEj5N$r NH,JՁV)T0d) ,wQ6R*2͖K0FMSPlxF#&v  tF)0  5Br5Cl,d2L$aR;;; HvAfsgٗ.]z^Gbjj @5@-{wy<Ayyymmmﯬ q0ǭy ҄Πt*qw2fHtN!pScڂà,ف^FlH{m&XYc,dP(3-LY.`4#hPD05 #0 (؁ֺRB d (U !.F ` 5DBJRTT&SFC42*52d݄O,G>=RH԰TJ0R1:&IT6(N!R 4H,c0j"3IJAL̬-&u_*Ucd:ȔT* r BHHfsrLfkTfPaT q4H`4*@8*`dKU :MRh,[͋~R QTX)U4 ,+ jdPPLM ERLpBCe!Bf1JJ(8¦"jC1Y,XHj!oktLp %a\a3J2P+:ErLsXtHHej`\ *Pj \*DlWQ2VE~r;Ίl^i[ K"*ADLb%F?-Q%Uc&x QŠҥwX7gv~ {nc]]{3ý<U4>$kpH."8`4MwJH;o}wI˻%y{c w(j[,:7„;A Gl&p p큼1j^S0:_|L58q8&q 4ѴJ)%Hd0cR¼q1QHI ')@4Cc $c2AQ$N<}Bu!b럑p0IB*LRI14F4j NQ88)YBZE#$3 %ŨI\@sf%Nt#*C0$JVT*Z´ZObQ4)ժIEQ& &D[Htb؅*$h>j=0.ۧ_藻?o8ոS˯=|*K8#Su9e @\1!Ô0 p{ٕOYl QE! HF Y00b{!$ubLX{U@єl@IF8$Z(!$Ep=$EI$ y>w FI<¿UV߿߾}ov-Yկ~j*EYfǎN#6mڤ+)?g?g}{;l6?G}QI>QnZ]]Aϗ1clذ{{1 1mڴiӦ]bral޼yҤIk֬mW,3~Ap)۲-FO?!K/1 s׎;{KQSRR^{5EQƍS"b0t666:u*33nAÑ}~'s7l믿7AӧOߺukJJ I~j-++뱼S}{N-Zz׮]rԽ?QSSF]0׿%+}뭷^b)((={_*24wP(֨;HbIHH8qNSn5kVoK֙'NTHEh4x=ĉeYv:IIIg>p`ZpFQv&L7%99yĉEEEO=TBB,˓&M 8Xb%7x$… /q;\s͠FC]~/Ydʔ)0VsFpeYޞGĉO:YuG.mx,,+ 鬱t:rH]]ݜ9skǦMRSSMj|:/6ߓT6(Baw2EtoV% !}˲t.4jQdYos֧ޱchu_p?|p0,(( wɎx|>AÇ?z=mcL,UUU|?oMZ1u26ŞV[Ade@o%n}_|?f !Xjo]ZZZPPE/̙3v5kۜӒG?ϟ?$-[wN:͛gZ{hNmߕ:ᄏm۶ͽxii9ߍ22>\].q/B}P[[9kmm=pgfʔ)H"g܍!,Xn$ͽ-vWܕ* Cw ~O܀߯[G'H磱ǧ E̠{ܿ=*mcBrVUٍG) Eɲ=SGGG[[[Vf :--uR\.eN]]ךQutry?իWLn,ł He˖./gNZp?k׮-8׬Yx }2QT H$qV`ϯ4t:|P(~ԨQ5Jb!V|ǎ4x"0Ox $}i}+fY+=l1-kkO}y4Ǎ,ZZZjkk+++iVN8h4FB>( B'vti JKKcGZg$zt{}bزeKTG[M6=Zq]=zRE SNav|Ipcc#M .t\ʈ,޽{Μ9ݻA(//߼ysQQQnnn;9^BlןL mmm&LHNNnlllhh *޽vD"sf8 wN+w}N|w<~x&=]{Oe9'779--/r NN9=?y r׬z kJlq/{qe*[.33Sr-+W,((سgO0|衇%~#GRRRqhmm}CP/NNN>~xv9w|ٲΝ;y_JYpM`oXJ4&L-?//`ds{3`+>iC"e˖-]4%t;E93gڵ+%%tXTTtR>~իWkZ].z~ҤIp8z(o֒%Kv V, 7|ɓ'-_| ØL&В%KK.MNNVt͛7K(*++[nc=,84ttt( 6L2ݻ7++K%K?!{g}v7'+Vhi_' IDATi1 Gms)S(iFc 0 /Raa_?`8eRSSw1}(lL|eBPoQɄi4\WW\lc3 K* NY랾8h~R8;;`0HQTd&It:Nzd h4 ٖcDz{_f͚|0jx￿cg|6mt'^'4ܟ[( = 8cǎhVK-b۳O<9f̘ΝpBjb |s]lYNN"@Rew$I?>55uƌ&I$/_V;f2;wӧ}>ߨQʔ &(S:s'EB>Atff2t抢8z蒒EB.J70Pi xQ:( (Jɓ'GHK./9k)Ql6[~%hjy8첲`0f͚[o5n_8>/\__'#m\ =ԍ p??n)dZwxo`z׫TKW^+(Бx5{ݗL1 iZwu?н>J۷ۻ$Gj੟yJ{FCHzg͚kjoooh41cFCCŋ7o;;CK6mHOOh4JTsiiUne$kjj8@^y=Ϙ1cXMMMav.7/]277w߾}7pC 6m,+O6 +p(jڴi] ܅'$I2 pT_/Y?8Qn0d_}ѢEo^^>x֯w 8,*T*T8臠}ͪ ]sv$軚^+lqVEG4iRTFF1X&~Û233ۑ5o^ðm=/n^k|n[p2F39{R&^bZ |AeWҨVPLC zO~eK$`yy}ʂJJHH>yB)+++VXo6eWYk";N%I1cnw429##7to߾fYSBm2k֬hصn(#a& 喑$ޕ<qYn΅(Z}466kl||!mK?U* /d AFyk1QKhݪބarַvQVu))) .,[RR 8DG$y-"y~FJJ̱̟~j_zhIO9Q{o(:zΝ;ϟ,DZZZ xջ}' %&&:NQU*UN|} *px(?h/_[R{N|Oʥ &s?6mѽgj5hӧ|#W>貈5 T- 甛]5FvvvCCy (pl+ ٻp7WlvRR((p8)@D9sDQljjSL8A0 KSr>J$Bpt:y6qiyLjі} Wj7 ?0$ 2{C˲|7P\MV̀0b)..ٲ,wɎx? K%B$I%ndɒ~4$)xΖ78#xV l6ZJ%qG#> 0**.(n!C=8Õ-0j8 w۽nݺ QF`f`GZ Mӗm\e1 ^ 6Napzd6w^\h](#殐9ൊl@qFZkllYĉ3` 'h dGrJQ]6mEׂ |'NT$B[lYpa'%cW_}u͚5wsh0m4%$I!΁\YY |>7M޽{`X/ZH;馛/h4o&aj3Bcƌey0*]bp߼yA;vZ~g,c+Ds_I/{r$q^*ρpp_u",c~9c :q+T5r06J( (eGmkkːp W_}u@;{gJzp G}7Mu.*KF`T}FJχc;/ }qSg0L\s͹ [.k_>3_nuZI`0{+Ds}sA_ g|cRW L@xY qNC8!U a1\Dyf5B 'TQSE_p,ƹB/2EQfǓxb JXkkĉq {ѣdc>9-\92kڿӲui l]5mU  9,8Of#h)H!N1JQ8ғus&enpg$|FE}}uƄ4/񧂮ٹ&%o?xɦ$hfMJUm\_n``7nZ^)5gZ~OӲ2 ."xcfch9C;ۯݲwԢ+BHB$+R$ Ig(B(Y60LV8 R H766h2̙s]XQӟ~.׿9SK* <ϯ]x0+)Yo\¶͙C=8atB 0 Tki߿e˖'ND"#Y nܼdpꫯ |4}]wرgig1=z]wݕ>zh>|!Ռ3x Qsrr꫍7s<9Bꜜ>}'?I3|3gNyyO=8:u;_ @Z~/ˊ#G9sFFM>=}]rJ:zhEEŮ]z衋l˔LI"˖-=zcǪjbMMM,gdd?^`0(Iү둭bq>k֬kv٣ \@Qw9^S56(TAY9ooo$I{+jkBQFQtmYU ֌#Inn$INkJJ\c |kkk{.G H5״)1# cǎ,s Ngp\.T8@Fj*a>yLGSSGsk1f5),#8no:uj߮]'m6xxs>hF=nȄ͛JgЖ-[ /nr@:y$˲P__ijp[[=PIo.sDNW_}qqq#GC+YNڟq z,VQW_bl;u-w77.h 70!0Cav[]--AoZ+WGV2(CaÆcǎݻjVUUaH裏|>Rl6_X,$ya;wLKKx<)))^7766JD,#b BFGn" h ôZmtf׿'Nd\uF< ΤjzΝn;X~5כo֩O>}Y:Fϴ^tݶ<(w>w qz~֭ 8ߟZn̙3JgϞt⋔Fܜr-/ K: 51sss_xe_ ,(&BGќ`vTZaƎ [X$"Fn!2π~LZpڼy<Dž{GF QSYQ_9cƏ|z۶mp04}Ŋ<3 GӴ,p ,TH$A(:ŌURR"˲$If؝2eʔ)Speyر8SqEQ5"1LOb6Sxh,aMe8sF0߻& rNy(_bũ˴$ի?zsH%͉93RC!I} ~.r?°szUE{ˠ?NEQeXU樂{VpzΝgTNHcoyChBqƹ^am/$=ڥ6J̼"{M&oa$ǎtҋlK #jo[1$&M I F, B.xÚsjUl4~߲{ #2 ͜ 2'6idPgN#ڰR]=&?+W>€a ydܐ+S*$uttpYYYFǏWR~>ʑ?MMMn[q*(((,,ܹ0!!a./Eb;@QjkKT$yIq݀IqNQg΄|Av;0B8jk;q[o}/N#-$΅9+\(ѣp8;;:::N:mE߷o˲ӟjjj^}՗^zih ^!Ӝuw4*MQ_D1ppFL,;+O쩯yk,q`0jP(T[[{}qwرrCg0rXQcT>] *NQ`PUSSTTdooG"$E) uCDP^p8!c&Lj4b$reef8UQ!sIH:Z[0pyI;']AD!1>˞{Ϧ($C;AUUU)n,_R&k۟~'NX`jwvo?J  Ð$rx뭷-Z4g%"/NeiZM[1f#x^D$C@h42tC! :]Q`1؁ IDATbBD9EPv'Z,khZǩjC@$TQ P(PѰ~(50}9&h cq]9_ 4YCkfLe:sܧJ2$G?3fD?ol?3M?c{xG`ܸq?8 4չZ[&Sݱc*T -v;aiii>EEt9.ܣ 2QE&r\brsʅ^ho?(pK0{܏>V3#q5sʀtңzvhX?NVd0Ӊ'$K\E ٹ$*O\J]XOo4F>jrg(ø rZNlnkmu9&izC@YY'|rA^^\A:\2 s=7Գ3(—(6BKeσ,޷D|Pۍґ$+~i cr?jA{8Cž/Ȃ A1ikj*(( VYfY`6Ru 8(J03s @,e>A fPgKJ @)K iO{l @Ӏ"cX3f IJJNnt8 :f8I"/`qI֮]':uj̘1?ϦN:ԓ#Ѵ-I& Y2B(<Y|(r'2E18t86)17[6-m)H1A9$.$)*STvnѣ$OUV6߾!Ñp6m8,SN4nԩk׮U/^u%I (jb}l~`y^㥧K$j4en΋WTDӴH2:{&(dYEMECq!6`YP(tXxAq +Ͱąq5w]vvڵk~sg=(++S*[.99=111VyeOcJ8l˨ ))D'?zd08 T>u?% j].J;_p'Oq~)S$%%;w>ʧZ6vD%7Ct W1$''씆H$BQd=,@16`tFcFFpI|n7q%%(::JA`uV+qPɓIʢh0-{Y~7W76FDQjmob J$^5jBi)˲--%%#3`(yp yhxרDgq᫶C\$~oٲ_׊+}+9?|0ydJ{kk1c1 3p8%%E߯v{RRӧ322DQʪiZ?0sr2Mϓ$IFG |__\xBpm;|Ø,V;&77Az@6XSLfa\^^JF pYy9M2@k["$)IJV+ N#11LqgHHHX|craj: T*YBA(^:JZ(qDQs8%!!!11gf͛7YIqi=12B!4:R'  4FIh4Jq8P#J۷m#RGܳG$9Ƴ%:8 h4 TRXh,y̙p($, ip!58qz!TYYSO):B~l6fgZl$I$axw:@]b,"ʿk*rff&q<_}UUU4MϜ93 :t$IV;s ,Qi]z^'H0$(JD Bdh4)RB؈fӹl$""0Jh: 657 O@^/mpq5DDn$80\0(r `X  AQ:NRx^>1 8p3g(ӧ'&&^LHOӻ;a„=XuubsP;a3>8~^?7p9s&;~x{Os^yvO "@ Ò H0aHHz@ b yÑVe:P;$aq0.tj&1+Ȓ ;{ dgnL{ Y'LV+aFJ`hs}>U*aђ$$*FIcA}H~v`fFaa; NVRv8U*y Bg0`m8 a|gPf?h1^Ȳ(uuu'NPv+**x%Kߑ={8&$OZAx^a :kIq[V~}Q}:07|s\233+++`GGEQNꫯƌo> #ۯO>WVV;v쩧y@KIV0,$'N3 fD!DiA!^&ht;ή_e{rf&3dRH# A *"Pz\^ r\.(H %4i)LSHdz9gΙkx2%LH$?kF\6"t]%#CDDžAFlWaDJa׻+$I,gҙt*4qJ P˵o}>/ )qx3qaΰ9 (=mk[|꺖2ao`YMnGyl"V EQ2MٹsgvOOqmmmGnMY|y[[ /K/ΝO|8 )b63!дiu}`ԧ>U~?OMӌkwnGrE[nNeG?,n(!(RJ939$!m0ftWyu0BF&=g2DQ4M|*lŢѓ-ydOݶm75k֔F({{>B9}$YΥ^zW_+H( pz==MǏnnj}%u\XaU8YQTt4e `0U(L&͖ө{wpѣGo?N*Adobb(Cx\.M-PQMV+0&p;#T|_~&_?FexzGovFʕ+cz#GYWDZ(>o۵z^/|YƳpWq5+N@4}뭷26Ȱ,q$ m;jU_s6/NfKrp8/I˒K/Ʉ@ `2):Q$d@hxi&CJ@@@!$_(@/bBZƞUXVHAB&SU],8 饗~ Κ5kƙ3mڴ{OSmmkk_,yoБHds,|76lg?nݺ\rIAOOo}W_}W_M$㹄+r}y>藾_T 0bllVŀz3¼}exg>S$% 57f[l6P4ʲL)UTƶFٳgz_}׭[3?e=hT5->ԷI U|]:/}{oh@ Pب,s=W򅞵T|dr'hp8;L>6x~;Ϩ_z?XJ$R)m,^x'߼yy l|O'J^… /_>]ʰcp{ʒdۛ'ٲ9y`n{4'rao.lnGV_?NDQ$*(gKBh…]Ľvڛos=*(@dLs!noXTUuvuu:rnVIb>!پ}>aÆRaұkT g5{CA[_(Ɲ)S߿ .X,.[0u6NT*f'Mbg(J%,|稆l`t%\y'{qjD B7 *UtlQxU)nXCLm}>͖h0 t};g8EK7 ʣHoђc|B#`\!(cx|bOώ-[i--"(>VodvB_q0d;v߸q eE͛7od`ƌ?/ts+/n*ERX,a cr|>_OOvR)mܛZ[[_ ->@eӡ2rJCcwpZk3V mv{2l͓'756_US8X,aBB$AY!E_>$i֭%I XjTnLf74֣e30V,̲a D B),#sL2wx<>oԩ.=HƝi*,B۷oܸq6lz}}իW\|c⊇~xƌ?O/_~yx]!veYJi.kll|ODdi{NeΟ?mt1*!:R3BVݵ-ӦEַߖhά=Z-Pq&YqUUB1%B(5,;Bj,on6q\ s:  ;B=}Gc`dY,prQB^!heY|.-<ZdlYCŸyDQ_~7| q܌3ڏ}cSL)W/g?>ą|Lc_09й 47͔ri`q] +ϣl֤iD.t:^tѶM\3(8NP_==]WUJRJ`)!i!@)%y2 F @:MϝN&3 qD(a'@4DkjXKn߱:e>H*'?T*/>۷oO&Az IDATVXqW\{`p] /6 'Ayve>c֬Sb1{Vg(d8jުˉ  `c[_=(QAZ3RBPss3PP{atJYEP d!%De@):wcS׫}>Yx<3R&a[t%?NHP a!:!D@EQL$Ҵ|2 I&Ef͚5ݥϋ/~vr-V7y^uUO?)z7Rg}ؓL&oW^y!vڟ6mՁ@]͟?KMg{F|;Fpڵn?yÆ b"]. Tfw2W6k,}eM9 BPXV|6r8d8do>H^S8eʡ7z, uÐϝxС}?O\s͆ F288(ʮ]Qڵkʕ+ꪽ{^~FP$Ip\jƍҡ8O,[lw;mڴS~زe˔)SKO<ڵk+}bQS?D͚MЏ~ێl:mQ}ч~W7ovTU=UQ͘bʦ#9 knZF0 0,<1 qc1FQr R)/bQePPY5I,ٳ-elOeɸ61^,iQJ)B&g*Ib.WfE,+0u}swyn={wyu~W>}͛M4n4mΝӧOonn^pa(ի3Lkkk<omm]vm>Jlܼx⁁믿_$IӦM뮻bX}}͛K]} MMMk׮E[n~/5D".S>c\rɽ|{޼yO?4}Y׮]ظb ;Ð/ߺuk}}0o???mذaǎ'O2eJSS믿}/yԧ?O3ɓ/ѣsփ>C+V8-+|7/EŔc5ŋ/Z}۶7~y緻/# /]seFXXgiFEՙL&Ո Ԩ`0F,9,PUMUYu]QUUuT]hkRTU4 !vd9<0 r@Q xWHU5aá"˚ EA麮p8hOx^>1A屔L&w. /}$_/X,t: B-zz-Ͷ|rBH<u_G?h41?gΜ_|^۱cG:={O{{=#>|zꩧ_|t[n%L4iʔ)֭x<ַjkkࠑ)3O~w}H$y槞zQn,Guu__sϞ=o`Y{2|xΝ<>7|skmm]dɤIJiʗ\rg7n8V*Qr-[쮻?~___yB=/$I#qm۶ ό,c 4,Ѱ.S* P,{b,#Kfj.oجYhTfm6[>7[,UPG[[QY&͖~h2VL'FR*I@g]!Bj&K*ITHXVS1V2nGQӅDH0FyøvGAWqRJ% Ah$R骪2uFfe[,s93U]uQ&f kq°DF̺u{tMnnzׯ__իW:th^{m~}-<<̏ӧXbEMM]~~_UnUU<ȱ|:mڴO_}jؿ$IRý^[[.rɉqڵk׭[uW;6H >+W~Ph۶mÖa_yO<į1oYa"رc~:bmLtckE FVR!p1%N( R)6}(3f[5~p'pmb>f}f< !Ju1Dz,ƐRM34C(8HDBfQ `A \Ƒc8@6Qn`9Y8 ,h4Lj0°쮝;cONdtZZZ.og>Jm__gW\^8 -Xnd nnG>0%\288x/X ]qͻ V\lٲt:=d^aÆ /pժU1l/̙s=\ p7e˖]wunᆃ.]tOfڴiUUU=w=cƌ_wuf'?+/~_*`,= Wհ'x[/M9:d*պej%_g/kcYf)!Jd`@eCzp… ;'WyQα,.[d'p83t2N$CCx\!D1JwttwvF Ƭɤ@HR"&44iƚB:=y7GL!eY,TU%P Tyl.ołXxb?Y»7_,j;ڰa /P,WX̟?w}93'|Re' wo}kɒ%{!xvmP讻[,nܸqƍ\.$i1]v١C6oެ(=3k,[nX,??XUUe2w+,X@Ӵ&ܹsTY4=BK#~o{߾}Gɔo yA s4_/q&R)0ɀf/X`wNnH$bX,X0JGޗo<SLٸq?_HI#2 r;sM&xt?AzYeyϾ}C55ar|*"!񁁡!B0v1fYBHU"n'Hm<_eb1r:X==O@vpx~YDMKg2bpy<UUuJ!DQ6s0˦p8,+>lzX,<ܹsOTB^xW_:uc`8q)B̲>eYJ@,m 63~y*Hz ԴGv}vF `_gg4 9ͨYgkN <_XYMihh=n7$$,'H$ !̲TUYU5 Cf!D"ayeys8aX q3񔞦cs+*mǚLp?&P`6!== Hqra֭==6?q8| B{_|?y8^6ՅB MMtF4/\0_|#g_O!% ӚCT Z,xrT>[׾S|0Ela|$CH&VWs6O&6%b8 H3erSSwww>W 9lv=t:D!oig3tƽBnݺuHёdjC@0z s n^fG0gabsyjQQt[{{{{{AK!c̔zVTEPBLt:nj%ѡRק)E)JA qٜd(D(L&:bH#C =YTUR ceIbBq.%Xjj:}z2t­ NX+LzN댉v<Oc 0Ehi!/mXXv뫯8K$82lɹ>jNɠCRJⰙ{g'#$LRUU1˖-;|]:L&EQ̂zi('*PU LJav;k2J|^eͦ(A$I/`Yv0R@J!&yjn*fh;(5zP`];Jܨ/LqP)SO,dt]͛'75UUUxr0ӓHbGGG6!KrVBEQ9'3^hX  ٳ{ AiZ6EAHQ\# uMuf cX0ÐBAd4ETb6V_  a NRo@)Bh64MD1JU (D4n5IrHDeI cM,LŸWprhw xa颪9|avjhIdJ@Y¿' @r\@o__XnoorI-->(!J0,,[ĸiyI~]UM328 BX,|u: &r9P(յVCØw8 !p8ɸ<E(&YѴeRʳlX>E(Hs9PelX!U BzKl6;q# *n N zK'qj}*:K! e3ɤn8zŋmVk&OE=ugDu: =Ȳ %X8 !fsdpdP:/Umh8g1>rh:SaAUUP( ( 6[8fv{ޚh,!$ "J&'lqPTcl,5T*%B6UU"{n8iήh4iq+I$˅bgs~H:x<KUUI5fΙw95<,kZuuW dY,qԟT{ (ggYayeTTR ﯫr%D FQ J riIHB)  ebٽgh<! 1*ǻ_z4RB B&6A@u@XS[ Yj2qX>ʩ ND$)S:,|>oNEΘ1c^U 'b& pRJ)SJ!]/z6J5drN  cBj(JRAAh4 c-K$% B8,x0JpdtEX^$ IDATVas΍ (jYb+z˫'x|BT2L뽽uuu;wgI UU)R0\f(,bQ"<{VX*~{֢iٳ *qYbh2 ?Ծz5p{6F#T8~ )lVE#T`z !]12X4)0Zx&d@$UUuM ^tJ -_ uM~)CȂll㡤 QEM<@YNfSd#tPIRl`+W,b+4BbPJ3gG}}}<EOrrÇK&clCںuX x?>C&)=X 2azlgUm5WϜ9Ssd:[D"aUU%bj_+>UՋSb*Fia;\.M)uy<͓'/YĨL$/>1088PO]EfaB,9].&g^es:|:.R`b*AS1N`0䦛nڻwo>/K,y7|>̙3ftvvΛ7e;vx%K`_z%cX<ώ;^C:;;=oqן+-T>}i?d1<z6ctñ /^׷ap$B( B.iD:-k|ߗ.vib)~28a|>(>__nߟN!AEU *ƽIqYf/d-Z绻Ng ,˯dھ}yb+H|WWv޽{GE<?|ԩS+rgaUXxB_ 4zEal6 mVk: :!BAVUFuMf}K0 7?3+L86oR>|JT.bZQa{*.ޝ)2Ee>DBuJ)!X,E#5Ljn/^l8w\,]jXlVdx2yr*|8qrhHuf0qcH(z=ٜdك9 4[-@f*Ap{Y:;;KILDbӦMbrL˗/ooo8n׮]dX,rϟxB&{+aUU򗿴GѺ`0uVJioo5kH#> x2Db/8ciy4]W5#<2sp@׬YSZ[[k,z!˲ .4"čșo|FBȻ k&Iz 7PJ>)n{͚5!C:{ժU!Êj(dtJ1B!fEQ%P)!!qg{7YUMs{.\[oeYI`st:uβsr tEQu`LNe?Ba!Ff+,fiϛBH)ڪ~U|P1NIUPLAI8)}5XG+իO"*(>TM+̞m64M TdYI&ul6e$@0 ʕ+#Ȇ?IS N%y]A`YB(2X4xX9"YQ0]'0GR͆16<3a8SB8g잮΃c!qp[ovG-Dw!C`Qp˨F@)y۫jZ*&kld7oْX,f@{]wfc5MSŘ[m6@iPuj25-[(D"y_b.dX,ڻo_I{Zl6Bȟ{ IDb+O>_bsnڴ:NTjvժU}}}MR/T/:TfyBd tPPfp P߯(J{{{NB͐a^{-NpxX,ZZZ6V:1.1m^ᤘ5kV8>ns9/ҢEJAX|9tBBBhԩglN.m!ѡΞbyW!pQoQ*r"b.-uT*sǎ(Sϝ?,DB,~() 8.ɤS)vx3땙{FFjV\Y!K3&"-2>hmb!4y1,LDXV+qb!BcnikҏɱBڏ 8a0Ʋ,3i%{(ˉ0 C)˲C9]I)䬣b+;F{;$I,*)^BU#TXx&%]O%۹O:jiMXk `ݮ2bYr,i3kl$,aE6qQ xYTТPU{[KE/Z-W^Xm ( !,gf~̏ܔMD8ghs,OKK8KBXEk+ Ewkd\bmmM 2LOOoĈl=Wj*f͚eaar ---B!:::&&&%566d2ق `uwL&rHUw!P_0yX,SQ jD ҈ X`P,EA[ۀ8;AC}1c( 11ؘմMChb*ܹ˓dyyyl6[*=Z*VWWO6ƍ #..А>|~ nXBQi*OTQB!AX,L(NgQE"Ar gε1 R C.)^T,3t--nj+nk~"x!L&S z`stL6a===CCCE߿?i$sss===w]]]iiikkY(}Z  (@Q_G-|dGGP`\.KBxeA0D<)9A;>2mb_(wo Ci Ν%P8(!F!J$Zx{;!`܈Ja.QV۝O6xR!:@ n,Oߙ4Wi;UzTh(Q|+}̧"? C )8'6{_ kxz{B( *,}x[-S~/rywq oDBӉ]%2h mi=r8=LUY\~k+@[H0Dm~a }h^\\aoHMMW@,0ҥK8_t /8^RRs~QQZ"Q(y =tg @>6ʰ'F@#1Cv{3C`.^III "==Ȋp222lmm߼yS[[{e@@IMMmkkc0G$&&5 Oi4۷ ϟ2@ oc*/W'ˆrV>&C~gՙad;4wH155DTe0!zO0APSԩSYtuuy<Ųhll$jR) 1cGGGpAB>-owO\e@GQ0}`*wI?g:;y/^ T&J;lnA;;;S[[[D2H@ܕT`]+7crjC4wB jwz<ާ/DyoP{Gym@s@ ]Oggۀւ~?`]RIRYX,hZZ,]]z@J566|>_P߃.Wj !Knn@5%H|}}ɚ?~|QQQwW>䓐jkkS!HJ˗/嗟~I.-#uuuAAAiii? .@ׯ'J$G0U0 3g0\nbbB;={l@WW޽{dP+pX@  ;rssq\@ 谏g8u.E_|m2d2wwwի666K---xT*=ztWOI+,44TAsSN& Κ㙙nnnW G666D=7o522|3&2JD"]]V6-H`ﱲ200V(=R^qvv~uSSCAAAg :::...dT*BPOOO l>/Sf̙kee%  !Cjj@N8._~]__ܳL@{EpppuuueeYrrrhh9͛cƌyرcLɓB:tR@KKKZZ̙3>S &LPQQ1rȊ hfffiD.K$FP(y=@޽+}||:\Ň {g#Bhcc󝉈nMdƶzLMAꫯ={Ҫ.//͈#lmme2YIIIss1clll̈!/^y5aP( ٳ '''.+E"kmmm8 *w0bXOO0---6=R\5Fc2D:##;۷oˆ b///D Huuĉ>|HNNNNNNʶ+VJ&&&~~~^裏D"D"144,))󳲲0ٳg b0,ww9sXZZL"ѣǎb <>0ŋ\B EѦ&"X,&T^d}mrABBB:P(r&L466dPmhhNtwUPpܱc\H$3 y!==H[[;0 {Gw ECC)3DR*L&knn9rdmkkS2>Ք孭]p8ƍcX |>_9 055U(//W9T*%CrNwib1q'S2qDz}} __߾܇#WSp999?ez̪CfBaff[:kkW^;B vqԩoI]rǏRf& zM6m۶.=P=;IS"1@k0XQQvڀ*jMMMEEÇoܸАɓFab֭[gϞ~ݻwM9L&aVDT^^NعsǏ.10hаg$}}jSSK.577[[[|ѣGmmmgޔ'OP(bEQ*P(4Y{VV͛5s0Lu}y :pX3-IDATD111MMMD͛---;d29677_tiCCuMM xOKK1SWW^YY}Ov %D\7nDDD۷Owdee233׭[G.9r;dXaؕ+WN8QQQ,>}5k{@<=Ez vL6 @J{{{CCÖX&{nu?~X&wA֭[ C,4$Gdgg^e2QQQ X`'O;vl@@يD")((ɓ'nܸ؛:rH ~N](0HP TVBsӚ*rv sn ՚'a8o۶FfCzHOOH$ӧO5gpYYYxx2ļA?,_MU$X}M͒\>tunbX(?AZ ''>>^yf zqff&q_֢/a0s@}x! 8p@uK* 3gT0H144xS6}-WWW%gdd"ɂ:::r\BCL m4n2H .7n׮]9;oήt",Xk쪧999$477wpɓ'._p`ڵ=ԙ4iҮ]& ~t%Hɓ'! du(PO3ҁ>\pvvyuڑ#Gv>_²2//D$߿ƍ;;;@IC hÈ~7nԐG8q2*eee!!!*j&99CɣG)6d(O?ŋ]^2Vb˖-+V\>jԨ(끼9ԭ[-[!xhmmP\RRf%;v]^g~hk׮QTaG*z7oܽ{WeggwĠaG 4aΝ;wIђÕ$ 9~wYNϟߺuk76"_p vNIIq\*LMM߼yC:HߐVVV]~uuuwrթ [m2r d2߾}61}#֯_s玲\&_zDm&44y!rʺ:5+!rdw}QoYJ q$IPPPLL̓T_tKzNXT%#B߲e`N " ["|,$>H$K.MJJIOO3f ي rNu޼yiiiNBQ4""BJz~I Z`D[Kdp8D&;;J@ ֭[a"AYIPPe;DL6,qppP/_lQSSC<~O?miiQr>4xzz @ABBIP!77I?s5hpXfp<<<VQ .9sf~~~bb"ZH… ƛ7o&[ @sjTVVzzz{zz޸qCGGlE5AR;wT&UM[*m۶|3܇3f̨/7<<<={vY@fffBBlB>t6m:v옦'={PÇ3G/wZZZdk!hC.\燇?~BÔ3f|駯_>|0Z˗o߾HLB Μ9!Ǐ-B2,ȑ#MMMdkQ "22AÇ]vX'&&fÆ 89s/&Yf =`kk矷ÁaS{؜9spg§Q9rl-P(?Iю;F  a|_rydd$ZYfEAhxx#G o޼(ٰa+W>}JA:tJWGaXxxSoݺGCW\.7<<|ԩdk,`>}9!!!ǏOOOW]pN:sNh?$ҠCz`:tm۶(Jg׮]"hӦM'u 322&N2rHA>ݳ2]p|Ϟ=dkDTVVedd̜9ݻ!B|_2l9ɁPuuu֢@sxⅧgff'͛dɒϟ>}l-ݻwƍN S^^뀀K.H TjTTTkk+r ؿ? }5˓'Odk0N>_x4%%͍lE 0hXaÆ#F;򰰰xss{M}bǎdk`N&MMMޗ.]1cݻwV+Jɖn"##QݵkZ>FSSgΜymu2{lJ?y$11qԨQW&[ˇ Q3#5 NHHf .9rg}6a„js88NaGAAUϟg``@"2Ԁn VZ #A Bd>ܹظ~sAg@ GO^TTmhh8mڴׯESWWכ<OyJP077755/|~/*/^ܸq#p>=p5k㄄///@С?k׮> {ѣGO>MRrȘ={kzzzr2^^^\.w_^5Uƍ:D={vŊ555^^^ dӭx<.{ WW˗gee0  r\T*H$7|{nX.D\<߯]v֭{8p@ٸH$R}!BP,Q89r$1~UVƍץ.啔<~8p8#ެT*D/KrEQD@||U0 e˖jB HiiElӧP(TCvvvMMɓ'Ν322b23f Rnӡd2PUx7\pBdgg8P(6mEѬnܸxPPʕ+MLL llmmM:ܼbŊ>lt:¢[lqttlhhq<555))abbd2׮]P(N8`ӧtb c  FPPD"9qŋMLL?'$$$899x<7u䤤$+++:L*BCCGwN7n\tܹsiii˗/oO8d"uBB?;;ym۶>%%%55B$442JǏWKJJ}}}e2T*]`\lپ}f͚uƍWM>}ƌ7oTz喖۷o[~k׮yzzUUUGFF677++0 :~С+֬Ys̙%KzxxL0aʕK. U ξz?Y~uu={222 EA&Nhoo/ ]\\T׭[qFE|}}.\m6777"$?/0lڴimmm0*=P0,55`ȑ/&iii˖-c0yyyeeeM8ʕ+-z*4iR~~>ӧO///olltuu}Izzu딡-*++ܹ#ΝKPڮ\ںhѢѣGzɩ͍&$$ggg777bh---.\5kI[[ԩSGGGT*vZCCڜo޼yٳE"˗e2leeUQQ!H&O[ZZ/Y.ph2,))ŋGgXb8;;>b2ׯ766ð;wO>A KKϟS(q]vϟ?ŋc,--EQtҤIH⢥uɓ'"ۢ"gggX\\\}zSSM,VyaXׯN"1&4j|%KzP(l6 BxfX Ãb):{aGDD>(JVQ%|~VVVaa{WUUw;w޽[)={|Eڵ_~O[kmmm]tX,ӧO/..&O>aɓsssZW([ʿ3b۷̙33f8wܮ]\Ml6`&f)rsscX|>Ã(>pD"jڧzB&.[/^xŊ2gygwܑJ V2xoIFQgϞ]ZZzWΝ;%Pr+**6o' `URRf͚8>OL8qرӟL&8py___Ht/"www'oܸA dX111";wp8fW~WE4ݵ^ɇ%INNݻwCCC+`X/^$>|alJxt|>_Vx<ZNSSS7mڴ~??v[nn)S~8sMF O[[[IUf===[ZZ<==y戈ɓ'}g&MR(~RRR~Cƍ6lX~~kUTT{---=ޯx W@ Xt){Ν+Wxyy-^lkk3(Gt428xNFJ@a`V閖zCӴZvssyNcXuuuT*MOO6dbŊ7nh4߿>P.駟jԉ'FGGGFFn߾]?~|ԨQ&o9EQB8|#GFAFDWT 33ܹsW\𨮮g__߫W޸qӆY+W?w}" u:7|bHWK(ٳ'%%f|aLOyy9EQFRJbX?s@@@[[ϟ={6û \̛7pj*2}gMϟ?c=oʠnh?JZ3f‘#GRR|5W^ ;:Y)4(*::ㅄk\^[[%S} @'YYbfҭGw//cő3HLwů?#vڵO`d/څP/@E?*mӀFh][%ѡƢ(ΣQBkF@ `~#xx !Uܽ@gUutP?+6\4 |@g0T`5ǁk-ZE8 @'ߏ?SP(*pp;j@ : ǀǀ hxM ~ $hqOeC'#h<#0?1G aE@(4+Je'0|3ǀ`$ 9,Ln)߀1΅=`fXj|y@Bk=a|wo@?Qq5 n5f~pw2f <4@^ac1d2{nkPqT 9 5 @<}~ǮX7냀6c׾C+@C/@TC;rw<_ x@eu m ;$.ʹRmpfe{IEuaO9j =_f&pVj.]-[Uߓ׷5eKOhib/2؜I#*6Kwl7q`Z`C U *ʠiPԖ@P CMu&q'x6>Lz NpZ ;7+ڹF NQˉ'.,]/k.ŗv0"ugarB?_zKlwg7D6@V]D F}RiKFue*ꮂ+M@; ځkMӪv揿ly^ʼ}vESZ[UʿϮ0N#z-!6,*忝뺯~ k 5F_c[F4@p=maZx@LR'İ&F5_EeKjzŢ|}x$޿f upԅjެg(6Bο[5-4#@x:,@Mh c"UϏ_ܿvޑ}eIPjlR&| W0J]%௲xgUu ӡXC:Yͫ @ёע> /W!l  0u ~T Pr DOX =loSkrq߽)n͢ /F6xh6͆w0hUS p"8G 1j.n @ @bݍWPR_V)i̸EnaVlN0 M:]`de/܀z1 0mBJ48XxxFx<eh:.5–8g4RVMZnSFs8_=Y,oAnh\+@Y9nEa3ĀP Pm[5 x ՊHIItcǮ)4R~u2nb;OypZ}cngkwd=TZںw#wt|fwы!8`q7)pxD<0 @% /t@gad F@\9.* 2@@+p n(@;0sŸ1N} CW8xzJc @pTCT/6t.3֕  ZP~ M@^տ{,Z6QL١@) `|5 |@ 7 `f5ٰO#"ɾh=  hZ``n,Kzo+:, S09>Εs'0$O7 %GK5:#~$2]qpK`,]]N8D]"KN8B/ 6x-f'ep*G52'8*2B [GA:LKŝ*2q'v.EQǏ7vy7cb:フ߻w)`L( {=}kvO?GY82v-GƎ%?gcnj]\|RYYryi lAuWHDFFN>}߾}C=3>>/0׃><e+Wh.+lr˗/߿?M_|+ o)2x@냂2hKw*P]]^ssa;vlɒ%KKK#""N:lٲr|O`8v9T\֨6G>k֬y1H]` ,Ǫ[NOOOícǎHMM%hWYbիW\bpsŋUʠ*C|o EQaaaϟDgΜhѢ7|!!!.]p 7Zg9 .<}ܹs- A39񈵙V 6Ell͛7{=>lٲ˗O26|322zFH$k֬h4ա7o*_&OBCJѣGi>qDss6RD"ݻiNOO 8s MH.IӴRϟi^裏hPSSCB͚I]m YZ$6oABB_Ԕl2uuuXL\zϠZhf ϴM#+V>}:--mL/"0}.徝69R:wܔ)Sz| m')1 [nEDDܺuK"w\ 6wJu; (ιPHp #c/w0,q vp\;8.1]qq]SWx]):Y} jv3 丹3FT`MWe`O]ζ5t>ʄ .u=3KXkB-[E"QRRk׮őEyzzzzz.Z8O4I,:tԚNРrUY3zmRXXzI5hkk ZxqCCV-//iZ& Ç4]PPpJKK-ϝI] ԕ_~ >ܤ~޽{СCl6ٟuYJ|…V??~ɶ4t[{U62] :w\QQQttرc/\`L9rcCCEQ{ٵk׮]&O,mHe 0X~KP(, B] ښ-{+ cƌ鮬ϙ3'887ިR*.\zjLwܱ9_;cU-l xyyy{{ҦJ0M%%%qqqnnnM+++ "$Iya\􀟺 [bnfmփ]tٝ,_8f ڿ# n+l]h=q vp\;80e'>8N vdJ0[(s F_1Ɨ`L~H8NNNNr hO)u:k[XŠOLW֭[g޿]W𯷿5U ܯ+ JǏ׮]PGeff޽{̘1^^^b899F(o7o[BBN;M{}+&ߝKތodddX'NǨRРw)o HΞ=?|Md l+'01 izԩɓ ɓ'e',/iRvGܟ 6te@D.r9:t(HJJJJJ S*&'(,`iqXB*=:;;Y`y%%%ˋ/h>%%@eebNNK,4iҥK;(L6mٲeqqqӦM8qٳ1}S7ݙ0Z.&M#ls *$x N.ۋV-TE`qN\aؤ$0VչPFEEI$GnԬYf ,PTRfR4v%X*֪TXҟ2d֭\.ƆpڮQ5552L* BВRjD" 0yEFFn۶ӱ{#O81k,///%NgQx뭷zMƤ9>?jCV €07 P"6^D"3{`[K{#{綾^JHH}v{{{AAڵkccc \a[&.-ݬ)3fXdZ&_@~ rdRD"a&E%'' ?W$9salq 7j4֭6lsss Ydɓ{gNZ^D" ޸qmCZS2@RZғʙ$ <̙3DؿjjjJJ?n޼yΝ/6QTw Ɵ>|pzzzHHHll… ̞=ㅇtN;5ۧ*;ilk̆6:::4k3$Ǐ'$$+555r.+._L y͛7GDDL<>4iIxtFvv6o;Hҿonnn޽{ɛ˼[E WPՆPLɅZnhL&KLL 49 $1yHN<uuu 1^%9555'o&D$TLMM54V ֒TJ'0y1SN ݱcV>x/iӦ>`ӦM>u޽{ ,#':jkk 555&uҵ&tRryllD":1MOO ߱cG'nnniiižO?-[l۶Gnnnttό3GmsJzSdK9sP(,**2vy<2"@D|2HD tIDATG&% Lf)hLvqTySN#6@D<2D-祉ҤDXڥ~w: " @T>,++7n,d2R,**(*&&&>>~lW ٵCd0UTTT#0LG Ud1,9 hEWr#.K`Al\Tv#lҝpaa]9@Nm[ęOuNVn^///75Vkc Ɨ1|;F~T\#V}Zqqq9H;Y%%%pHׯ"# [ y젫5rT,bSۙz·tlb^?7㇦-[x{{D$:nڴi{!?'M$:)w͛੧Z~=-3=,P,;رƷ' @YYMӭ(v1k,rL& tSZZj8]C84Mk4DfFS]]yft%`rJ^[͗cg_~ >pƍ;wLNN&1={VR_p履~2x6K:>|ڲeˢE&NwǠdYeBQe_|@Ptܹ۷GGG3&))iVRRرcCBBφ ɓb!wэa 3=CF;kKE 4z醆 =9o޼ydM6=w}wݺu~_W!!!ZСCC 1PXxK2[VVkxtn:lذ{4]YY0d@ HRSSOz瓓̙5| 6GD\-dY;e1S`c#lܲSNv-oμo!E0v#.K`%3Ytpa d9L6q>˙'/9的#t +=zk4Hf lZ=p8c777 xwvlrͼd۳͉1x/%v&۷ߟ[a9wN%O]!T|ݰGR|ڵkzݻw3K,'''ׯϞ=7¿IG.a=K l˂GdddX'Nlhh;wD4M{2hƞ%**@TZ? hWJѣGi>qDsssi ڣDNh,0APbU4mS 5`cU%' 8p؀Ҏ;kq@]N vp\;8.K`%q vp?8,JƳIENDB`amide-1.0.6/amide-current/m4/000077500000000000000000000000001423227705100156575ustar00rootroot00000000000000amide-1.0.6/amide-current/m4/libfame.m4000066400000000000000000000205611423227705100175240ustar00rootroot00000000000000dnl AM_PATH_LIBFAME([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for libfame, and define LIBFAME_CFLAGS and LIBFAME_LIBS dnl Vivien Chappelier 12/11/00 dnl stolen from ORBit autoconf dnl AC_DEFUN([AM_PATH_LIBFAME], [dnl dnl Get the cflags and libraries from the libfame-config script dnl AC_ARG_WITH(libfame-prefix,[ --with-libfame-prefix=PFX Prefix where libfame is installed (optional)], libfame_config_prefix="$withval", libfame_config_prefix="") AC_ARG_WITH(libfame-exec-prefix,[ --with-libfame-exec-prefix=PFX Exec prefix where libfame is installed (optional)], libfame_config_exec_prefix="$withval", libfame_config_exec_prefix="") AC_ARG_ENABLE(libfametest, [ --disable-libfametest Do not try to compile and run a test libfame program], , enable_libfametest=yes) if test x$libfame_config_exec_prefix != x ; then libfame_config_args="$libfame_config_args --exec-prefix=$libfame_config_exec_prefix" if test x${LIBFAME_CONFIG+set} != xset ; then LIBFAME_CONFIG=$libfame_config_exec_prefix/bin/libfame-config fi fi if test x$libfame_config_prefix != x ; then libfame_config_args="$libfame_config_args --prefix=$libfame_config_prefix" if test x${LIBFAME_CONFIG+set} != xset ; then LIBFAME_CONFIG=$libfame_config_prefix/bin/libfame-config fi fi AC_PATH_PROG(LIBFAME_CONFIG, libfame-config, no) min_libfame_version=ifelse([$1], , 0.9.1, $1) AC_MSG_CHECKING(for libfame - version >= $min_libfame_version) no_libfame="" if test "$LIBFAME_CONFIG" = "no" ; then no_libfame=yes else LIBFAME_CFLAGS=`$LIBFAME_CONFIG $libfame_config_args --cflags` LIBFAME_LIBS=`$LIBFAME_CONFIG $libfame_config_args --libs` libfame_config_major_version=`$LIBFAME_CONFIG $libfame_config_args --version | \ sed -e 's,[[^0-9.]],,g' -e 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` libfame_config_minor_version=`$LIBFAME_CONFIG $libfame_config_args --version | \ sed -e 's,[[^0-9.]],,g' -e 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` libfame_config_micro_version=`$LIBFAME_CONFIG $libfame_config_args --version | \ sed -e 's,[[^0-9.]],,g' -e 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_libfametest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $LIBFAME_CFLAGS" LIBS="$LIBFAME_LIBS $LIBS" dnl dnl Now check if the installed LIBFAME is sufficiently new. (Also sanity dnl checks the results of libfame-config to some extent dnl rm -f conf.libfametest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.libfametest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = strdup("$min_libfame_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_libfame_version"); exit(1); } if ((libfame_major_version != $libfame_config_major_version) || (libfame_minor_version != $libfame_config_minor_version) || (libfame_micro_version != $libfame_config_micro_version)) { printf("\n*** 'libfame-config --version' returned %d.%d.%d, but Libfame (%d.%d.%d)\n", $libfame_config_major_version, $libfame_config_minor_version, $libfame_config_micro_version, libfame_major_version, libfame_minor_version, libfame_micro_version); printf ("*** was found! If libfame-config was correct, then it is best\n"); printf ("*** to remove the old version of libfame. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If libfame-config was wrong, set the environment variable LIBFAME_CONFIG\n"); printf("*** to point to the correct copy of libfame-config, and remove the file config.cache\n"); printf("*** before re-running configure\n"); } #if defined (LIBFAME_MAJOR_VERSION) && defined (LIBFAME_MINOR_VERSION) && defined (LIBFAME_MICRO_VERSION) else if ((libfame_major_version != LIBFAME_MAJOR_VERSION) || (libfame_minor_version != LIBFAME_MINOR_VERSION) || (libfame_micro_version != LIBFAME_MICRO_VERSION)) { printf("*** libfame header files (version %d.%d.%d) do not match\n", LIBFAME_MAJOR_VERSION, LIBFAME_MINOR_VERSION, LIBFAME_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", libfame_major_version, libfame_minor_version, libfame_micro_version); } #endif /* defined (LIBFAME_MAJOR_VERSION) ... */ else { if ((libfame_major_version > major) || ((libfame_major_version == major) && (libfame_minor_version > minor)) || ((libfame_major_version == major) && (libfame_minor_version == minor) && (libfame_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of libfame (%d.%d.%d) was found.\n", libfame_major_version, libfame_minor_version, libfame_micro_version); printf("*** You need a version of libfame newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** libfame is always available from http://www-eleves.enst-bretagne.fr/~chappeli/fame\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the libfame-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of libfame, but you can also set the LIBFAME_CONFIG environment to point to the\n"); printf("*** correct copy of libfame-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_libfame=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_libfame" = x ; then AC_MSG_RESULT(yes) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$LIBFAME_CONFIG" = "no" ; then echo "*** The libfame-config script installed by libfame could not be found" echo "*** If libfame was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the LIBFAME_CONFIG environment variable to the" echo "*** full path to libfame-config." else if test -f conf.libfametest ; then : else echo "*** Could not run libfame test program, checking why..." CFLAGS="$CFLAGS $LIBFAME_CFLAGS" LIBS="$LIBS $LIBFAME_LIBS" AC_TRY_LINK([ #include #include ], [ return ((libfame_major_version) || (libfame_minor_version) || (libfame_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding libfame or finding the wrong" echo "*** version of LIBFAME. If it is not finding libfame, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" echo "***" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means libfame was incorrectly installed" echo "*** or that you have moved libfame since it was installed. In the latter case, you" echo "*** may want to edit the libfame-config script: $LIBFAME_CONFIG" ]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi LIBFAME_CFLAGS="" LIBFAME_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(LIBFAME_CFLAGS) AC_SUBST(LIBFAME_LIBS) rm -f conf.libfametest ]) amide-1.0.6/amide-current/macosx/000077500000000000000000000000001423227705100166315ustar00rootroot00000000000000amide-1.0.6/amide-current/macosx/Makefile.am000066400000000000000000000002141423227705100206620ustar00rootroot00000000000000EXTRA_DIST = \ amide.bundle \ amide.icns \ amide.plist.in \ amide.plist \ gtkrc \ launcher.sh DISTCLEANFILES = \ *~ \ amide.plist amide-1.0.6/amide-current/macosx/amide.bundle000066400000000000000000000125571423227705100211150ustar00rootroot00000000000000 ${env:JHBUILD_PREFIX} ${env:HOME}/Desktop ${project}/launcher.sh gtk+-2.0 ${project}/amide.plist ${prefix}/bin/amide ${prefix}/lib/${gtkdir}/modules/*.so ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/engines/*.so ${prefix}/lib/gdk-pixbuf-2.0/${pkg:${gtk}:gtk_binary_version}/loaders/*.so ${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/ ${prefix}/share/locale ${prefix}/share/themes ${project}/amide.icns ${project}/gtkrc ${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/*.so amide-1.0.6/amide-current/macosx/amide.icns000066400000000000000000001165061423227705100205770ustar00rootroot00000000000000icnsFis32 :36547 -*--,/$ 6()40 '888 67 ;:0 !>,0?>1A$#DE&A;?BDDBG>P'EBC@ACJGM=J MR3.FG) .OQM#+WINVO @cSZUi'ACDF'#GJLL@  814315 +(+,*." 3&&0, %30. 0/ 0-& 3$&/. (2102+.010,/*A1./--.1-1,201!"/.  1.-7-143(9.2.9*+ )*++% 9?@@D2 P# 0tM >ۇhm  E+. VS~]usR ;:#cS|~vrq|~~) yD WxDDzo/ Ly_|1]dcb3,]`a`Q s8mk6@<=?3ienZe ̬X1] }ze $B rՠ t` {5iNKVhil32d98>;<:!$7*-+5"1-0/12/1"7031.0+/0//0/3 1./0*2115#$4-1."61442 ;.13#7374:;0456787;,/72600;8:9; D269# @8=:@&>489 >;>9:?!D>C?G(-B9==6,/3519G@DCF=;>=??BGGHHJHDEEFDJD=@?>>=>>??@CDFHEM0 ,D>BCGHIJJKLMHIIKEEABD<' ((&1IJLJQ IBCI GMNLR; 3JBH@ 6SLPPO  6HFGHD! %1MRORPU;'QMIGIIJPNQ=\XVPRS XZ\(LCKJL IQ,IPNRUUV2WQZ(THKJJKKNNVJZSTSTTUUVY\DMQQRRSSQ33LVZ[YT, 76<9:8 $4(*)3!.,/./0-/!4.0/,.*-.--.,/ /,-.'.-,0 #1+.+1+.-, 8+-/ 0+.+07*...,.,/%+/,.)*/,.,. =)./3+/,1$4*-. 1-/-/(//,.)*0-/-02+,02,/,1'3+/.*$'*+'.4,/..+/./03 2././-14,/--,+--./-1#$1-//112 11..//.5-./) "./0-2 4,.1 0/0.1((2,/+ #2.0.0  -3-..,(8/ .0% 73/. /315-953./ .1280*0/0 /-1!,.,/0,05.--./.4)2./.3 .0321$#.120  '$%$'OW{P~~/6U+4>sĿa7 lܺІN^ŽM&yBϹñ~C}̱ȄXh I /~%QƮ t~Kv No8y~1\{Zchker}Xv yvv|}}; [z }_|^34 2>sz 0| a~}F cx]A}i V}g1+S Dm}~K%A~#W~}yHs~~|{}/qw}~||zxwo|%<zh~~yyw x|x#\pvto> 8`pttssttrj1  l8mk fF-j,HV +47ywe?5AGvl r R%{q'MY껹}/\ k:-k ~ju^]^]]`[FDR )>r A;d  gR x{6urԴ|4ө{~>{|~{lH||~{^$@AAAAAB4*@AAAAAAB. it32L~{y~bNY]\ZL@_UN@;?JEOA;HGIJJE% ".@GG@J__\OPRSG$aQJd?EE_88@@:=BB=6=MGIJ9 2CJGGWJ__]RPRST9 aQQdJdR_@:?=??B6BHPIIJK=$/0045JMGGWW@aa]RSTBnn}akakrrdR_@@GEBQQHIRJKLLHHIJMO]dccbafhgfRRSTUR*nakahrrd__ŁɁB?QpKLNRUXXWY\]\]]^ZSTUW7n}akhhrd_ǂmMMRKKLNOPRSTUWXXNn}mkphhrd܂ԂŃɀmLNOPRSTUWXYY#n}mhrрԁńɀaLNOPRSTUWXYZA n}rрԀłɃѵQNNOPRSTUWXYZYR}humhr̆рԀǁɅPOOPRSTUWXYZ\Z*RRZ}huhh̄тԀdžlPRSTUWXYZ\]JRZah̆рԀLj_PPRSTUWXYZ\]^T"RZcch̄р̈RSTTSPRSTUX\]^_\= RZhh̃̈rRRSTG8.),4G]^_LmGRRVVOŹ̸[SST UUO$/R^_aW/mBBGEÒTUWW?0>q$ L_aba:mBOiUWS.,oF!%S_abcM mBOOUW XXLLI+;Xabcee_,__\\B=ɂWX YFd[6=abbceff;__fBMLaWWXYF4xzzyZcefY"^B#3HLXXYZW]݌_efghhO9^#HLL{zdYZ\\[aglH$䭊rqrcefghfYZTt^#3HL|^YZ\]^a]|&$qiefghjkilt_h^^a^dx#3HLYZ\]^_Q'$)meefghjklmKh^^a^kk5++33hhHLdYZ\]^_aaT+$)fghjklmk,pp^^kkpak++5+3hHL=eZ\]^_abbU% $1)ofghjklmg}akkaakԃ,5,,33hH=f\]^_ab ccP#$$1Zghjklmg{OkkOOkkԀ,5,,33h3=f]^_abcF!))1[hjklmg{OkkOOkkԀ,3h:=Cg]^_abcee\).,11==]ijklmj;}}EO33,+303h3:=CiT^_abce aB--11=R\gklmgE zEOOG33:)30:hhdd33: ==rr'FT^abce _P9 $+,=@3DT^glmkcT9zEOԂ:30:d:=CRd 2BEFEEF B* CG+7=2$8GJIA( uE=Ԃ:30:d: ?)$$綍D-. 1BCIY7=<-e7.  uaEaE=:3:d;L=$|y66789BDLb9=$$͔~yxx) 56uaEau=8:d }^$$))$$)EEW 9C)?COj=紓F!80pnpazC8: ;}};;}^$$))$!)RWZFD))<F-588߰J!;2ppnpannh8:^)ERRWTi`SJD!EOQ88 ӳSSBB88B8nann_,::==J^^$))$!)RTpojfc./g\\g- &ccTW,$$ $$0)!))!!ERTpRRpp55@@66ffQahhQ)Ǜ+'p_W,$00))!VOOdVTTWW__Rpp_6;;66ffQaah)&nj+p_zWW,'$00))V TZZW__ZZ__E@@fQhh)&'{km_Wh,$05VTZZ_Z_VVE))$)$& {m_W@,$00$0;GVZ_ZWZ_VV@@$)  :OO{{_O@QQ01,0;0;OVVZ__WW_HV@)=))=  :m^O@QQ00,,$$01'0;8VVZ__WWTHT@)=)$$ &GGO:p^\@;QQ΂,$01'0;8VVZc^^T@@+==,,)$$&1W:p\@;QQ΂3$$$E01'0;8;8=VVZc^^TOTmZ@+,)$$&@1:^^::c\@8@3$==$$E010;8;8=LLZcT88mZZM+,5)$$&@1:c\@8Ʉ;==$$=E?1=5;;8=LLZZcO88\\BM+5,,'&@.c\d8Ʌ;3;=E?=Q8LcM88?@+5,'&&&@.1.h\dxdxE8;3;=EL=Q8Lc^^G88?@@?3+5,$&&..1.h{{d{EQEGL;6;=EELGhQTLc^^8?@@?33+5$@3hhdQEG66=ELhQddsdZZ?@?0+))$)$&Ά3^^HQQHHG86RsOO?@?0+$&8635^HQQ:z06ss?@?0+$)$863^HQQ:306,,?@0++$##863\HH:3:0,?65$#&&6653^m:H3:3:0mW65$#!T6TJTJ3c:;;:3:zԂ0W665$#&THJHJH^^c :;3:3::3zzԀ8W5$#&THJHddcRRcc:3::35=nWW5)$;&TTHJTJBBc3;3;?ހW500$51;&TTHmc353355;;ހ̆‰L500151;&&CCH\35;?Ԁ¿̃5B5B:0151;.HBB\356?܄΄ɃƒTBG:885;,.B\3566܅рѿɃƒBGBGGOH::;.,.B\35==ۆѿ̃ɂOGGOGHOHEE;;'.,.,\u5==@?ۆ̅cGGOHO3E'.,.,\u5=?ۇ؀ԁcGGO3'B.,uh5B@@LaфcGJO''BH,u hJG=B@B@B@@LB؆OHO##QTu JEBB@B@B@@BBO+O'#JQ_QcuQB@B@?B_WW+''JQ_Qc}ss}uhBB@B@?BB)uW+''#f_^}ZGBB@B?B??BB)BB‚u@+''#dJfHH}}ZEEBB):B:B5u11+'#ddfddHHfZZ_ZEE11):B€̈C11+##ddfddZfZEE11))B€̈C11+''dZML1))B‰1+)ddZkLZ11BC1+11++ZdkkZL:B1zZLBQCpzɄQ^RR̀ɁQQR̀­̖̖̖̂̂̀{zv}aKWZYXJ?^SL=88aD;897zz}}}:n8n6BQ=87*..;898"LE?EE:86BM@8,../7-7893JJOOE?EE:=86BM@8-..1;W$94QJJ@OOER:B:=B6ED;8. ./4CY\f69, QJJZOOE:B:=B6JD8$ .07OFGfJ_091aQJd?E:B:=:68$ ".@GG@J__V98#aQJd?EE_88@@:=BB=6q$ ;)mBOS9(,oF!%:;7mBOO94LI+1;!__\\B=ɂt9 /d[67=;+__fBMLG914xzzvB;^B#3HL厇9:U{~}݌L;2.^#HLLjcbH9p%$KA;:q$ U{<mBODzy1,oF!%ZV"mBOOſ_MI+;hq-__\\B=ɂĶ Jd[6?r@__fBMLI5xzz{og$^B#3HL md݌|_ "F^#HLL ¿ V$Ѿ z^#3HL&$ ௫ _h^^a^dx#3HL Ϳa($)쬧}Kh^^a^kk5++33hhHLb,$),pp^^kkpak++5+3hHL=a% $1)}akkaakԃ,5,,33hH= Z#$$1w{OkkOOkkԀ,5,,33h3= L!))1s z{OkkOOkkԀ,3h:=Cs*.,11==p{<}}EO33,+303h3:=C|l}J--11=Vf~J zEOOG33:)30:hhdd33: ==rr(Pkz yb= $+,=@3E]q}va=zEOԂ:30:d: =CRd"3GL KKE- CG+7=2%8ILKKA( uE=Ԃ:30:d:?)$$綎D-00. 1BCIY7=<-e7/00.  uaEaE=:3:d;L=$|y66789BDLb9=$$͔~yxx) 56uaEau=8:d }^$$))$$)EEW 9C)?COj=紓F!80pnpazC8: ;}};;}^$$))$!)RWZFD))<F-588߰J!;2ppnpannh8:^)ERRWTi`SJD!EOQ88 ӳSSBB88B8nann_,::==J^^$))$!)RTpojfc./g\\g- &ccTW,$$ $$0)!))!!ERTpRRpp55@@66ffQahhQ)Ǜ+'p_W,$00))!VOOdVTTWW__Rpp_6;;66ffQaah)&nj+p_zWW,'$00))V TZZW__ZZ__E@@fQhh)&'{km_Wh,$05VTZZ_Z_VVE))$)$& {m_W@,$00$0;GVZ_ZWZ_VV@@$)  :OO{{_O@QQ01,0;0;OVVZ__WW_HV@)=))=  :m^O@QQ00,,$$01'0;8VVZ__WWTHT@)=)$$ &GGO:p^\@;QQ΂,$01'0;8VVZc^^T@@+==,,)$$&1W:p\@;QQ΂3$$$E01'0;8;8=VVZc^^TOTmZ@+,)$$&@1:^^::c\@8@3$==$$E010;8;8=LLZcT88mZZM+,5)$$&@1:c\@8Ʉ;==$$=E?1=5;;8=LLZZcO88\\BM+5,,'&@.c\d8Ʌ;3;=E?=Q8LcM88?@+5,'&&&@.1.h\dxdxE8;3;=EL=Q8Lc^^G88?@@?3+5,$&&..1.h{{d{EQEGL;6;=EELGhQTLc^^8?@@?33+5$@3hhdQEG66=ELhQddsdZZ?@?0+))$)$&Ά3^^HQQHHG86RsOO?@?0+$&8635^HQQ:z06ss?@?0+$)$863^HQQ:306,,?@0++$##863\HH:3:0,?65$#&&6653^m:H3:3:0mW65$#!T6TJTJ3c:;;:3:zԂ0W665$#&THJHJH^^c :;3:3::3zzԀ8W5$#&THJHddcRRcc:3::35=nWW5)$;&TTHJTJBBc3;3;?ހW500$51;&TTHmc353355;;ހ̆‰L500151;&&CCH\35;?Ԁ¿̃5B5B:0151;.HBB\356?܄΄ɃƒTBG:885;,.B\3566܅рѿɃƒBGBGGOH::;.,.B\35==ۆѿ̃ɂOGGOGHOHEE;;'.,.,\u5==@?ۆ̅cGGOHO3E'.,.,\u5=?ۇ؀ԁcGGO3'B.,uh5B@@LaфcGJO''BH,u hJG=B@B@B@@LB؆OHO##QTu JEBB@B@B@@BBO+O'#JQ_QcuQB@B@?B_WW+''JQ_Qc}ss}uhBB@B@?BB)uW+''#f_^}ZGBB@B?B??BB)BB‚u@+''#dJfHH}}ZEEBB):B:B5u11+'#ddfddHHfZZ_ZEE11):B€̈C11+##ddfddZfZEE11))B€̈C11+''dZML1))B‰1+)ddZkLZ11BC1+11++ZdkkZL:B1zZLBQCpzɄQ^RR̀ɁQQR̀­̖̖̖̂̂̀t8mk@ (ClT8 p#n'8f nh< nc< nt[$Vl= tXV|f-XpN Lw_Bl{~~܈j=&Vox{sV,O_mے~b&ZoEayS ٌ̅d.(~pBj~sxVހ|h]i2~yW"zqJ}rEKw^ h1j6rTzc%nJv\҄g0qO{\ڍk9uJ _(l;tQyd)nCv[g/pO x_ލlDtYȁc"oAxSe1pAY!D.Z')dLyn{~~|{rjY: icnV Bamide-1.0.6/amide-current/macosx/amide.plist.in000066400000000000000000000021141423227705100213700ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable AMIDE CFBundleGetInfoString @VERSION@, Copyright 2000-2017 Andreas Loening http://amide.sf.net CFBundleIconFile amide.icns CFBundleIdentifier net.sf.amide CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleShortVersionString @VERSION@ CFBundleSignature ???? CFBundleVersion @VERSION@ NSHumanReadableCopyright Copyright 2000-2017 Andreas Loening, GNU General Public License. LSMinimumSystemVersion 10.4 amide-1.0.6/amide-current/macosx/gtkrc000066400000000000000000000000671423227705100176710ustar00rootroot00000000000000gtk-icon-theme-name = "Tango" gtk-enable-mnemonics = 0 amide-1.0.6/amide-current/macosx/launcher.sh000077500000000000000000000131741423227705100207770ustar00rootroot00000000000000#!/bin/sh if test "x$GTK_DEBUG_LAUNCHER" != x; then set -x fi if test "x$GTK_DEBUG_GDB" != x; then EXEC="gdb --args" else EXEC=exec fi name=`basename "$0"` tmp="$0" tmp=`dirname "$tmp"` tmp=`dirname "$tmp"` bundle=`dirname "$tmp"` bundle_contents="$bundle"/Contents bundle_res="$bundle_contents"/Resources bundle_lib="$bundle_res"/lib bundle_bin="$bundle_res"/bin bundle_data="$bundle_res"/share bundle_etc="$bundle_res"/etc export DYLD_LIBRARY_PATH="$bundle_lib" export XDG_CONFIG_DIRS="$bundle_etc"/xdg export XDG_DATA_DIRS="$bundle_data" export GTK_DATA_PREFIX="$bundle_res" export GTK_EXE_PREFIX="$bundle_res" export GTK_PATH="$bundle_res" export GTK2_RC_FILES="$bundle_etc/gtk-2.0/gtkrc" export GTK_IM_MODULE_FILE="$bundle_etc/gtk-2.0/gtk.immodules" export GDK_PIXBUF_MODULE_FILE="$bundle_etc/gtk-2.0/gdk-pixbuf.loaders" export PANGO_LIBDIR="$bundle_lib" export PANGO_SYSCONFDIR="$bundle_etc" APP=name I18NDIR="$bundle_data/locale" # Set the locale-related variables appropriately: unset LANG LC_MESSAGES LC_MONETARY LC_COLLATE # Has a language ordering been set? # If so, set LC_MESSAGES and LANG accordingly; otherwise skip it. # First step uses sed to clean off the quotes and commas, to change - to _, and change the names for the chinese scripts from "Hans" to CN and "Hant" to TW. APPLELANGUAGES=`defaults read .GlobalPreferences AppleLanguages | sed -En -e 's/\-/_/' -e 's/Hant/TW/' -e 's/Hans/CN/' -e 's/[[:space:]]*\"?([[:alnum:]_]+)\"?,?/\1/p' ` if test "$APPLELANGUAGES"; then # A language ordering exists. # Test, item per item, to see whether there is an corresponding locale. for L in $APPLELANGUAGES; do #test for exact matches: if test -f "$I18NDIR/${L}/LC_MESSAGES/$APP.mo"; then export LANG=$L break fi #This is a special case, because often the original strings are in US #English and there is no translation file. if test "x$L" == "xen_US"; then export LANG=$L break fi #OK, now test for just the first two letters: if test -f "$I18NDIR/${L:0:2}/LC_MESSAGES/$APP.mo"; then export LANG=${L:0:2} break fi #Same thing, but checking for any english variant. if test "x${L:0:2}" == "xen"; then export LANG=$L break fi; done fi unset APPLELANGUAGES L # If we didn't get a language from the language list, try the Collation preference, in case it's the only setting that exists. # AML doesn't seem to exist # APPLECOLLATION=`defaults read .GlobalPreferences AppleCollationOrder` # if test -z ${LANG}; then # if test -a -n $APPLECOLLATION; then # if test -f "$I18NDIR/${APPLECOLLATION:0:2}/LC_MESSAGES/$APP.mo"; then # export LANG=${APPLECOLLATION:0:2} # fi # fi #fi if test ! -z $APPLECOLLATION; then export LC_COLLATE=$APPLECOLLATION fi unset APPLECOLLATION # Continue by attempting to find the Locale preference. APPLELOCALE=`defaults read .GlobalPreferences AppleLocale` if test -f "$I18NDIR/${APPLELOCALE:0:5}/LC_MESSAGES/$APP.mo"; then if test -z $LANG; then export LANG="${APPLELOCALE:0:5}" fi elif test -z $LANG -a -f "$I18NDIR/${APPLELOCALE:0:2}/LC_MESSAGES/$APP.mo"; then export LANG="${APPLELOCALE:0:2}" fi #Next we need to set LC_MESSAGES. If at all possilbe, we want a full #5-character locale to avoid the "Locale not supported by C library" #warning from Gtk -- even though Gtk will translate with a #two-character code. if test -n $LANG; then #If the language code matches the applelocale, then that's the message #locale; otherwise, if it's longer than two characters, then it's #probably a good message locale and we'll go with it. if test $LANG == ${APPLELOCALE:0:5} -o $LANG != ${LANG:0:2}; then export LC_MESSAGES=$LANG #Next try if the Applelocale is longer than 2 chars and the language #bit matches $LANG elif test $LANG == ${APPLELOCALE:0:2} -a $APPLELOCALE > ${APPLELOCALE:0:2}; then export LC_MESSAGES=${APPLELOCALE:0:5} #Fail. Get a list of the locales in $PREFIX/share/locale that match #our two letter language code and pick the first one, special casing #english to set en_US elif test $LANG == "en"; then export LC_MESSAGES="en_US" else LOC=`find $PREFIX/share/locale -name $LANG???` for L in $LOC; do export LC_MESSAGES=$L done fi else #All efforts have failed, so default to US english export LANG="en_US" export LC_MESSAGES="en_US" fi CURRENCY=`echo $APPLELOCALE | sed -En 's/.*currency=([[:alpha:]]+).*/\1/p'` if test "x$CURRENCY" != "x"; then #The user has set a special currency. Gtk doesn't install LC_MONETARY files, but Apple does in /usr/share/locale, so we're going to look there for a locale to set LC_CURRENCY to. if test -f /usr/local/share/$LC_MESSAGES/LC_MONETARY; then if test -a `cat /usr/local/share/$LC_MESSAGES/LC_MONETARY` == $CURRENCY; then export LC_MONETARY=$LC_MESSAGES fi fi if test -z "$LC_MONETARY"; then FILES=`find /usr/share/locale -name LC_MONETARY -exec grep -H $CURRENCY {} \;` if test -n "$FILES"; then export LC_MONETARY=`echo $FILES | sed -En 's%/usr/share/locale/([[:alpha:]_]+)/LC_MONETARY.*%\1%p'` fi fi fi #No currency value means that the AppleLocale governs: if test -z "$LC_MONETARY"; then LC_MONETARY=${APPLELOCALE:0:5} fi #For Gtk, which only looks at LC_ALL: export LC_ALL=$LC_MESSAGES unset APPLELOCALE FILES LOC if test -f "$bundle_lib/charset.alias"; then export CHARSETALIASDIR="$bundle_lib" fi # Extra arguments can be added in environment.sh. EXTRA_ARGS= if test -f "$bundle_res/environment.sh"; then source "$bundle_res/environment.sh" fi # Strip out the argument added by the OS. if /bin/expr "x$1" : '^x-psn_' > /dev/null; then shift 1 fi $EXEC "$bundle_contents/MacOS/$name-bin" "$@" $EXTRA_ARGS amide-1.0.6/amide-current/man/000077500000000000000000000000001423227705100161125ustar00rootroot00000000000000amide-1.0.6/amide-current/man/Makefile.am000066400000000000000000000001351423227705100201450ustar00rootroot00000000000000AUTOMAKE_OPTIONS = gnu man_MANS = \ amide.1 EXTRA_DIST = $(man_MANS) DISTCLEANFILES = *~ amide-1.0.6/amide-current/man/amide.1000066400000000000000000000020411423227705100172500ustar00rootroot00000000000000.ad l .TH AMIDE 1 2012-09-20 AMIDE .SH "NAME" amide \- AMIDE's a Medical Image Data Examiner .SH "SYNOPSIS" .IX Header "SYNOPSIS" amide \fIinfile\fR ... .SH "DESCRIPTION" .IX Header "DESCRIPTION" AMIDE is a program intended for viewing and analyzing 3D medical imaging data sets. In addition to the program's own internal format (XML Image Format=XIF), the program can read in a variety of standard medical file formats using the MedCon medical imaging conversion library. For a list of the file formats that MedCon supports, please see its manual page. For additional information on AMIDE, please view the AMIDE help documentation, or go to the AMIDE web page: <\fBhttp://amide.sourceforge.net\fR>. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIgpl\fR\|(7), \&\fImedcon\fR\|(1), \fIxmedcon\fR\|(1) .SH "BUGS" .IX Header "BUGS" Bugs can be reported to the amide user's list (amide-users@lists.sourceforge.net). .SH "AUTHOR" .IX Header "AUTHOR" AMIDE was written by Andreas Loening. For a list of additional contributors, please see the AUTHORS file. amide-1.0.6/amide-current/man/evince000066400000000000000000000000001423227705100172740ustar00rootroot00000000000000amide-1.0.6/amide-current/pixmaps/000077500000000000000000000000001423227705100170205ustar00rootroot00000000000000amide-1.0.6/amide-current/pixmaps/Makefile.am000066400000000000000000000025231423227705100210560ustar00rootroot00000000000000 pixmapdir = $(datadir)/pixmaps pixmap_DATA = \ amide_logo.png \ amide_file_logo.png EXTRA_DIST = $(pixmap_DATA) pixbuf_csource=$(GDK_PIXBUF_CSOURCE) BUILT_SOURCES = \ align_pt.h \ amide_logo.h \ fuse_type_blend.h \ fuse_type_overlay.h \ interpolation_nearest_neighbor.h \ interpolation_trilinear.h \ layout_linear.h \ layout_orthogonal.h \ panels_linear_x.h \ panels_linear_y.h \ panels_mixed.h \ roi_box.h \ roi_cylinder.h \ roi_ellipsoid.h \ roi_isocontour_2d.h \ roi_isocontour_3d.h \ roi_freehand_2d.h \ roi_freehand_3d.h \ study.h \ target.h \ threshold_style_min_max.h \ threshold_style_center_width.h \ thresholding.h \ thresholding_per_slice.h \ thresholding_per_frame.h \ thresholding_interpolate_frames.h \ thresholding_global.h \ three_compartment.h \ transfer_function.h \ two_compartment.h \ view_transverse.h \ view_coronal.h \ view_sagittal.h \ view_single.h \ view_linked.h \ view_linked3.h \ window_abdomen.h \ window_brain.h \ window_extremities.h \ window_liver.h \ window_lung.h \ window_pelvis_soft_tissue.h \ window_skull_base.h \ window_spine_a.h \ window_spine_b.h \ window_thorax_soft_tissue.h ## window_bone_icon.h \ ## window_soft_tissue_icon.h \ .png.h: $(pixbuf_csource) --raw --extern --name=$(subst .png,,$<) $< > $@ CLEANFILES = $(BUILT_SOURCES) DISTCLEANFILES = *~ amide-1.0.6/amide-current/pixmaps/align_pt.png000066400000000000000000000022561423227705100213300ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME c;IDATxKTQ?/Lbh%pkBE&H!Vc.jQ #P'(P-i?vA)8cs_<}<{ Dw=snGK&?PAB`8WvQq @Xv%I<l_|eV>W|0-M0*GsU_<0d<|Z0Ighπg~FࡅFRh0>{ o^O NM`8FP_mɂ `(C&>.4',؝F^ԿfsMz|l ;W|l w٤,]*F 0y(?-v {7]aΆAˑ0e`o# R2X_USdit- M1}+2OBaSu{[>9>#2,0<7 gj nZy W^CNp? HRL.%џH30?hǂj0{KyA_H_J_LT_P>xLd`rf)IENDB`amide-1.0.6/amide-current/pixmaps/amide_file_logo.png000066400000000000000000000276271423227705100226420ustar00rootroot00000000000000PNG  IHDR>abKGD pHYs  ~tIME npO IDATxyy?=!BX ccVLB1EQNU.z.[>EJlN5&6q %$EVZjc_OwOLJ@^}Uy~[ 5#esZZ.)^Yh2|+wY]Z􍀻9 i#ƀRjW}Σd25k&G\p7~<ΏJe*-e@} :P U*ēwZ“4pvd˾\.IH3Y$i_^Q<): q7秞ްkW˥Lfq #VW, &xAtt]U#x~ +'̀AL0!J /e1Zۿ*@j%go`s Hʥ'd`AN\+$BrTkͲN@,^X~/=^S3 0c<"GJm;+_[u|Ta=WxlDL&#?`%p@J_:42 G.U~b_aY`9Fx"kO3::}R`hV/Oȱr8 8#@ʳ;:: Xr NzaXfj. 8Ve:Q/KC:t uttl0$,Rsݔ-ONO|,!Iӆ1>Ѵh04$bd 1/Ptne 1H濂TUfg0S,##hC $q AB }k*|0k0>Y0 taH`mPAl.R]Ճdnnv/pxv% j' ZSUmNӴ ]׆5M;RT3S;:"wwAJ+VSQN?L6px2$K@BSlT- (gRUU=i꼦UUgTUWUulpb_Γ eN(ƨ/>`  d1ˊdrSG*Jl8FXFrPS?F멏!H((Gu]˾ 1[i) t @-dP#~Űfg54w/pZ\Hb]B2dTU9q䰢deJ5,D7>5H@H0 v`h+0?T1ܲrg{.\H|j󷊡UAFSGjz\Ӵ9MW`&~1Ӈ1DPRGxŪX,֏arlX;Aé ɳ%j+/33w$iIjQ;Rjl/F!L .fN]$ŀN I$8mbdd8\F%etdTd4dЪ2TfndRROJM&kl%Xq ລ3 &VRo%:fO,k6i0ry.W(+15b7DXca$DF"843 җR53[YFt:诐MWa1 L.PԜ\/p wGVu/Yy$I _{z#3~?}4Rݳ骪8ikNTUT*,׬>_wCG8Q^udiu](J3Nv+(_Jt5qx-*Lٙϡ$jFA&L:$+0ˁb8Mx]h`U5(J,ٱx` }jE!Nbc؎}z ">9ɲiرul"nsYQLKU/. sTE4M吟"®\2 &(HIN*J#V=X &T#ff7M n:2###[W#G׳|6nj^'!كi|h4Gb;BJ]MƌyJbD7}u]Ν8Vc %[a˖-xꩧ|xffuֱsN.R=;O[@r{ݵkW1۫+srXw7CHQ HzBxIi]  x(˞;OS*(˄B]/Єqn@@X(V$|DxlǞ=tȚ&$IjO]Q !K`YS3L88k6I|7$,fZ;D{ I}]xb5S 騷s=>JWW]D"a!P,br9Jja-JF|_fv拓CA,H(D"dY榛n"q06 (Ӏp&Q bѕ=Vt 4p׍;p%o7ʕlvIeQX٣~u8!jY?Vxi&'߫[o$%$"E<ػ" 1tJ{W*Fd3m^@?8@(= 1,(Qa?Fd2ȲL<'N7Bdcu_g's {=+fggh0 'ڽ6{U> __>IGG+Wd߾}!P&H$BR1ÉpsrMV;C.ٹIdn0jL!6i%*(JMPwag( iհkѳN;NX}g_h|Ic@]0vӳ'w]wb:UXnV/_~tbP(cqoS!S j P*/҆u7of׮]Ю)ڕ@Ҹ=n_cZdazhܗ8;;{ç싶K [ mT*Mcꉷ+Vg g<<,F]wFɡ6]ҊuP @լ Q"J`{D*g6Qeua7nRdX~=6x=4;66\s5m݈j1~B(}eH1"e}C0&1,ͫR-pqxN .;+F$>DnA6NGhY犞sssCr9[ps`ttW^y0l6kzOʷ->Ϛ9}"455eoL˔rM+{y3fppN.G}r,˔kz] U StHE# Fl1ćFoOSsJ|[裏xiON?"um_8g4L3[c~ʆ`5l!Wa=RNE>aXIz;Wҝ]fFt]Nぅ2V/"Hc%|3XuB vNRAuCKU15 K%JQ3l޼d26xdYFQE3yDZc8YfU(5߿SøzBоRԃ: `[o%417mt5#=BuN9[EvUu3׊ 6pg7 <;Xf zUbђSoAzF8;x.sq=wpОiN2(; Cݱ$@7KrH2+'׵L >Kk299:*dIXF5πPU&_PV(J *Җ1CѓmzHv4*eL10:#ips ~mEd1Ќؖ BV(1èJ<7}$j`0hS8x9֦|nPcO躖'V7i@|]n˿uH$mo߾7LSP)g(MvEBqF CL&Q N&nJ3E`]tpj;e9\}/ڏJ[ }f`/|5;;;5t׮]l޼GUn1H^x!gַ-Y<1P"8ܱ7(S 3> yFh$I .:!#$cˉ'H&ځV_<$'94yJDZ`; b;ӓ ٬ݞv"o޽ i/B?'ME FXG[MeNΜd2C&c{b&wyFFF`kEEu^9IK,DlyfTebϷ%* ;wz7[nn[RA&&&Xl~ۘy~g0 ꉵnIt3f T_tE Z}~{6Q7nȊ+6@(Zq F_fdY3C1`CuQ-[f Vh+/_ݻYv-7YYj[pS="U[T*6m"N mٞ|IZ0x׻k1 B8Gcjj M8q`p1&~zY,صk, Yj[q6m⥗^Z2>>N>7} 34|]f;&ӟ#8N\.ַuAӾoU{088h^TU%JQ(f 2hzׯoXo>a3>n Ie uYٳ`0lzgy'>@Db):zYa}P{~aOK.T*>ɘLivvD"a ] [Q*ü- afm:<.Z:.R*|[wÉHN$M3EYf,WH Stuu p 745q҆M%8 }}{:::dZPBS|hb þ 8cDw2v5IDAT>ѲT*M `*q|O~:1'IBKhU 4v De0tu|xMNŲbU(^fݟ韺7t fhXae`q~UUe9>td|)|_m:hdť^ʖ-[\ l=v;e`˖-3m`0E$1tT4r6d2*ι>HR{ndYnSn駟6]|ž%jSp/ j@׍B II7zp&,OMMٜU 4sd57L"h&''mfu+8'Eq;Fx3xPT"L$iĉI.PebHQ +VX0~&&&̶~m%]zmp月b7}ek;B B.4*wdzzu]333.[o0|3)pkn27Wsk\J!Ŭ#wÆ K/y#V^\f\.MOv,dpKO~`6|Z,:#)ax*J/6nȏ~-K/y{mضx{?|>V= ~ F_O+}ӝ ,[8yYOuvvLP(Y bͭfFȯVUK޿{'ЪOduy'+3ܔ-7[E(MG 9|rqmPU| J?<Cl6K$TNnƆ> 7tSkh$5y9mS 4R!!˲7Jrgr (fUlL 6pViZ[hjVֵHd9~gOvnq;n? 8[<@'gq=Q,䡇j2F+$I4sVunk Z6_Q{\FsrÇ1>nS!ٹs+K B(4BaZaڴ_&h8npuwwWF+/N47ǓiB!v<^XUr_rH[uS86 BOy{[Z@aer3!#HFez^-L@,i`[=h/B!I.rSaz-V8R)/ /drrI[R0Œ tjVX fW\o~sdͱ|rt]oj։e +FH1_yh|h}k(2תJߝp6]2Zr>P(9v~>X,Jd2i uE^.JL1?뜧J/b{~+F򑏘B wpPB\~L7q^k *̭[^V guq,?9BL`5 f!"IӓiH6o EQ|VW\E%!aVW04N&Nb*4?`H^s`Quh^;7 СCLOO-~k;ԕ1ӢtȡἈm{ 5 j}99e[}ժMG>bzD"?m9/N"ĶFO@%>66Fww7H$~Xd֭dYpr9OQl!M\|Bٳ> (7tb:/ӷ$^ ` u]|5iAB9x<CD/>3,Nw~΋ z9 inR+37+sfuxFRد`r]TǴ+ hU*ݺvwo~3>V&8x rJӑZSy¶Si6ڽ +Y"v@@X-=?' ܹb𪪺&R,5]1e]kB|8o<k0߆ᅥ(~-z$d'7 }{֌7z`ַ-^ćV4eo$4!:N/z)Z8xC[E-Rtb_NkO^Ն7ʅ ]Fb7/<? ^ w.ѸIENDB`amide-1.0.6/amide-current/pixmaps/amide_logo.png000066400000000000000000000126661423227705100216400ustar00rootroot00000000000000PNG  IHDRZZ8AbKGDW0x Ŵ: pHYs  d_tIME-NCIDATx{l$]?5gڻw(rAE(`A" !r P^(W"@gB\ Q@#ޭw7z5]ݞ?DhRyk_^]t}O>ݧDc]Et$U!\җ9ΎD}i#gePeU5@gWC@ٳO|?ܡΎDyG TVT[Q:I6 i/\pЀ8ŝAM84#.t]ҏ_| va4kNQeZ6Ac @9n6űqH,//n@.dvEq](=CuZo%G^}=ac G6jFQ2v~6pj :Min} .Rx EshA! <@_N%S^5= JODK5WܽEMn1i8\nK8%`8Us.Z6A6 ]bgmcyi C*z 0<=?eʎUޢnL/`Au}Hf$844j_=]. xR~P EF QP- Z˨{lP|hNWOM{ _ Cpt>?}[Deb]q ^PM0%Hcs)_.Ի{b X@qñPD"1b\D} "-6 2*=^86A9׀üV Gkm۶Fl!k W@H)WWu͠0}@A ]U f}{5G7֭lspͺ i7phjSPD-H콀cҜL gQ#<{?Vggwrs'+fVAo̺CZ&9 j :} t-\i<<۶'H^^ Z >' ySwT96?Z-\n vmpɺ3xf^ptCپ (]b:S77sᒃL_TmФMG,>ݱj57T8NcrxK'q;Lѧy`{6< dcЩ˹5XHlHuY.ɜ,@Q5ˆµ :u՗WPV+}3JZR91>`k3/46P ue29~m5nNAdMu}o\i4jZPwbc+se*v]M IN300x:rC#' Xr˲` =w&!$ xL$]t}Xkp&7n_ǶF{jdA8 Ա`X,M06ZgR&R-۶JnHDaBpA ,7c&^AN PGǀK-l9ك)SܜLwP|YфPfxɝ*U0;2}I:)U|i\'1(\(ڛ4K<C:uǀ&w3c-9Ll(o <:뫱\# ʼnzKL?z&?Zϭ!s46ԋ)з A/pif 2`8٣b}vqn/r\@XHI+Q0;">lP?C*6u꾣bЁ'FVbcQYs׈p A^m Ξ ϡֳ[`'d8y kz )znNq,hBn8_W xt7[T2Y!HXǒEJQ*A/ʈ N=9A Yjv,e|$/'P(IB0Czc)\tfW{zWѳ6I[0K HsVWWC< Mt]]迤&-MpA'/dca$ _ ba?#qhZ(lGoo DO#bMyPu~瘋p06ɏ:6[Cl3k[$jvyc&8aDL0蝍LΛ~:6Eu;( dcdţcԩuTЫ}R:PH@?x oW 'I[덲vQ@(9( 9o808Vu aexϠ,arF){ ޻`8{XI"<ąPB2_ƏP;AJREmx`L| H*q^<;JXykqQ?>;ӓK~ MKog4΋PۊubwOq'R~L!ks?L+iVDDSӼ)WG&Xxmgw"lcMBי\+*_g>?/O]x5[?ݧ og?kV֋(y (JI]gwjW+xnO3ڒoe0kVPFV:#jSa7^,4.HI~/-*dձ? 맣;M@جl| w h HSa(F҂mzH=J[Y%T*aB :Ͷow7꒳(]_iBIYO(P(m2(U% \i:V|EhkjfE.30ڛʶBwGN?eլ܉'K =h1ÐtdQkW󬬬8e I@9O OD(#Ѧ# h'O84*s~mOʼnA==m>N$VfSm=kv>#v:Fـפ[ TC<|8oC{xES_:\޶Ã,6(|6gN>1kR1IoV$Jc[(Aq)LWqj6%LB`)FchYBYWˇ+ԭv5ͱkqFDBҒAq PBsڏ ept_Ϡ&|c;$QFM#g7P?CZdRmߧSF ѓi^IENDB`amide-1.0.6/amide-current/pixmaps/amide_logo.txt000066400000000000000000000003471423227705100216640ustar00rootroot00000000000000Made the logo in GIMP as follows New image, 90x90 with transparent background Text: Letter A - courier (bitstream) bold, size 130 Script-Fu -> Alpha to Logo -> Gradient Bevel Then reapplied gradient to get the blue/purple colors amide-1.0.6/amide-current/pixmaps/compartmental_models.eps000066400000000000000000000135021423227705100237430ustar00rootroot00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: compartmental_models.fig %%Creator: fig2dev Version 3.2 Patchlevel 4 %%CreationDate: Mon Feb 2 14:42:22 2004 %%For: loening@prop (Andy Loening) %%BoundingBox: 0 0 187 185 %%Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save newpath 0 185 moveto 0 0 lineto 187 0 lineto 187 185 lineto closepath clip newpath -71.1 239.8 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /DrawEllipse { /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc closepath savematrix setmatrix } def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def $F2psBegin 10 setmiterlimit 0 slj 0 slc 0.06000 0.06000 sc % % Fig objects follow % % % here starts figure with depth 50 /Helvetica-Bold ff 300.00 scf sf 2325 3750 m gs 1 -1 sc (k) col0 sh gr /Helvetica-Bold ff 135.00 scf sf 2430 3795 m gs 1 -1 sc (12) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 2250 2025 m gs 1 -1 sc (k) col0 sh gr /Helvetica-Bold ff 135.00 scf sf 2355 2070 m gs 1 -1 sc (12) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 1950 1125 m gs 1 -1 sc (k) col0 sh gr /Helvetica-Bold ff 135.00 scf sf 2062 1178 m gs 1 -1 sc (21) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 1950 2850 m gs 1 -1 sc (k) col0 sh gr /Helvetica-Bold ff 135.00 scf sf 2062 2903 m gs 1 -1 sc (21) col0 sh gr % Ellipse 15.000 slw n 2687 1513 300 300 0 360 DrawEllipse gs col0 s gr % Ellipse n 1575 3225 300 300 0 360 DrawEllipse gs col0 s gr % Ellipse n 1500 1500 300 300 0 360 DrawEllipse gs col0 s gr % Ellipse n 2775 3225 300 300 0 360 DrawEllipse gs col0 s gr % Ellipse n 3975 3225 300 300 0 360 DrawEllipse gs col0 s gr % Polyline gs clippath 2565 3030 m 2565 2970 l 2364 2970 l 2484 3000 l 2364 3030 l cp eoclip n 1800 3000 m 2550 3000 l gs col0 s gr gr % arrowhead 30.000 slw n 2364 3030 m 2484 3000 l 2364 2970 l col0 s % Polyline 15.000 slw gs clippath 2745 3990 m 2805 3990 l 2805 3789 l 2775 3909 l 2745 3789 l cp eoclip n 2775 3525 m 2775 3975 l gs col0 s gr gr % arrowhead 30.000 slw n 2745 3789 m 2775 3909 l 2805 3789 l col0 s % Polyline 15.000 slw gs clippath 2490 1305 m 2490 1245 l 2289 1245 l 2409 1275 l 2289 1305 l cp eoclip n 1725 1275 m 2475 1275 l gs col0 s gr gr % arrowhead 30.000 slw n 2289 1305 m 2409 1275 l 2289 1245 l col0 s % Polyline 15.000 slw gs clippath 2670 2265 m 2730 2265 l 2730 2064 l 2700 2184 l 2670 2064 l cp eoclip n 2700 1800 m 2700 2250 l gs col0 s gr gr % arrowhead 30.000 slw n 2670 2064 m 2700 2184 l 2730 2064 l col0 s % Polyline 15.000 slw gs clippath 3765 3030 m 3765 2970 l 3564 2970 l 3684 3000 l 3564 3030 l cp eoclip n 3000 3000 m 3750 3000 l gs col0 s gr gr % arrowhead 30.000 slw n 3564 3030 m 3684 3000 l 3564 2970 l col0 s % Polyline 15.000 slw gs clippath 2985 3420 m 2985 3480 l 3186 3480 l 3066 3450 l 3186 3420 l cp eoclip n 3750 3450 m 3000 3450 l gs col0 s gr gr % arrowhead 30.000 slw n 3186 3420 m 3066 3450 l 3186 3480 l col0 s /Helvetica-Bold ff 300.00 scf sf 2700 3300 m gs 1 -1 sc (2) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 1500 3300 m gs 1 -1 sc (1) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 2625 1575 m gs 1 -1 sc (2) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 1425 1575 m gs 1 -1 sc (1) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 3900 3300 m gs 1 -1 sc (3) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 3300 3675 m gs 1 -1 sc (k) col0 sh gr /Helvetica-Bold ff 135.00 scf sf 3405 3720 m gs 1 -1 sc (23) col0 sh gr /Helvetica-Bold ff 300.00 scf sf 3300 2850 m gs 1 -1 sc (k) col0 sh gr /Helvetica-Bold ff 135.00 scf sf 3412 2903 m gs 1 -1 sc (32) col0 sh gr % here ends figure; $F2psEnd rs showpage amide-1.0.6/amide-current/pixmaps/compartmental_models.fig000066400000000000000000000035341423227705100237250ustar00rootroot00000000000000#FIG 3.2 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 2325 3450 2625 3825 4 0 0 50 0 18 20 0.0000 4 285 210 2325 3750 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 2430 3795 12\001 -6 6 2250 1725 2550 2100 4 0 0 50 0 18 20 0.0000 4 285 210 2250 2025 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 2355 2070 12\001 -6 6 1950 825 2250 1200 4 0 0 50 0 18 20 0.0000 4 285 210 1950 1125 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 2062 1178 21\001 -6 6 1950 2550 2250 2925 4 0 0 50 0 18 20 0.0000 4 285 210 1950 2850 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 2062 2903 21\001 -6 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 2687 1513 300 300 2687 1513 2987 1513 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 1575 3225 300 300 1575 3225 1875 3225 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 1500 1500 300 300 1500 1500 1800 1500 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 2775 3225 300 300 2775 3225 3075 3225 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 3975 3225 300 300 3975 3225 4275 3225 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 1800 3000 2550 3000 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 2775 3525 2775 3975 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 1725 1275 2475 1275 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 2700 1800 2700 2250 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 3000 3000 3750 3000 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 3750 3450 3000 3450 4 0 0 50 0 18 20 0.0000 4 270 195 2700 3300 2\001 4 0 0 50 0 18 20 0.0000 4 270 195 1500 3300 1\001 4 0 0 50 0 18 20 0.0000 4 270 195 2625 1575 2\001 4 0 0 50 0 18 20 0.0000 4 270 195 1425 1575 1\001 4 0 0 50 0 18 20 0.0000 4 270 195 3900 3300 3\001 4 0 0 50 0 18 20 0.0000 4 285 210 3300 3675 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 3405 3720 23\001 4 0 0 50 0 18 20 0.0000 4 285 210 3300 2850 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 3412 2903 32\001 amide-1.0.6/amide-current/pixmaps/compartmental_models.fig.bak000066400000000000000000000013311423227705100244520ustar00rootroot00000000000000#FIG 3.2 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 2250 1725 2550 2100 4 0 0 50 0 18 20 0.0000 4 285 210 2250 2025 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 2355 2070 12\001 -6 6 1950 825 2250 1200 4 0 0 50 0 18 20 0.0000 4 285 210 1950 1125 k\001 4 0 0 50 0 18 9 0.0000 4 120 180 2062 1178 21\001 -6 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 1500 1500 300 300 1500 1500 1800 1500 1 3 0 2 0 7 50 0 -1 0.000 1 0.0000 2687 1513 300 300 2687 1513 2987 1513 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 1725 1275 2475 1275 2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 3.00 60.00 120.00 2700 1800 2700 2250 4 0 0 50 0 18 20 0.0000 4 270 195 2625 1575 2\001 4 0 0 50 0 18 20 0.0000 4 270 195 1425 1575 1\001 amide-1.0.6/amide-current/pixmaps/fuse_type.fig000066400000000000000000000010111423227705100215030ustar00rootroot00000000000000#FIG 3.2 Landscape Center Inches Letter 100.00 Single -2 1200 2 2 3 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5 1050 1800 1425 1425 1800 1800 1200 1800 1050 1800 2 3 0 1 0 2 51 0 20 0.000 0 0 -1 0 0 5 1050 1950 1050 2700 1800 2700 1050 1950 1050 1950 2 3 0 1 0 4 52 0 20 0.000 0 0 -1 0 0 5 1275 2700 1800 2700 1800 1950 1050 2700 1275 2700 2 3 0 1 0 2 51 0 20 0.000 0 0 -1 0 0 5 1050 1050 1050 1800 1800 1800 1050 1050 1050 1050 2 3 0 1 0 4 52 0 20 0.000 0 0 -1 0 0 5 1275 1800 1800 1800 1800 1050 1050 1800 1275 1800 amide-1.0.6/amide-current/pixmaps/fuse_type_blend.png000066400000000000000000000027001423227705100226740ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME  sZMIDATxKHTm4,KT>3lE.rAB AinBhݲ "l]W%n*.7l~3Ň̹~39 /[h2V|FYπd/h>hM׈4I^!@L|I^d!"RCat^ 1" @NY .@Z  !!2Okg-!Z9>.<B<';t0 Kw>˿G'@6:t~е|xF@7@w6m ! vBt @@ԹLx{G!˕P|OU \/zrlyэ؈>`[ Dbs;;_ | BG#(9|Jl/KB!>b|.yB| U7`{ہo6û#@DQH¶e"P Q~" P, |0PP{'@OҐ]JAF_[0^ w U`g0?JA}.{+@2 e./kKxyXꡢ¤>ʫ.aQIy9Hk|dٹӀK&f]N ox_+zgoep*1/Pw@CC[2@oF@toYȈ6s9Ws{[6"kЁht4rx+f5Ug}PYAOFSG[7 zyᭌL=[-fbUU %TU%x+"9쇷25ez7dδbP]ւy.E33[1\㙀ۈq41 sՠۮ e;&'݇29i!t57͎'NYΚstq78_Sm/V 55>cY'O2?o-tvPm h-j_WPYWgF@LuzsW@\6-Nx+W./R \4?64$ih0,#llc><@5q uMM#&45!ΛgΠ@ y ?B)iY47|V cZ :bY8xY˹s~ XtaIENDB`amide-1.0.6/amide-current/pixmaps/fuse_type_overlay.png000066400000000000000000000023031423227705100232700ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME +PPIDATxkhVuSn1up (.Bv(( zAЛ"Ȃ"%奚6q:+^@E$"KM8y\e2w=?:.2?.)@`=2_k˄JVԌVIX)hGDb%!:P;kQE"!*#ӡ\BX'T l+8~"V_ xN]uOO|BX/ G@|Bh& lC_m֋ uB0_u$.?p6 ۇ$c{-2] Ѝ)(~ '<@[LSClgB&CC}9-N2OGO-mKYIhzkH'N3J?u| B0Y`/f1~6N&z_x0s*=C&MožiĎ Eh87@C "L؇!7c ]I8 ĮǗ ^aFyDoKQ0#~7{_Zt98KķȬ"}B-4\ ~4_ sba8:_7? 0?}[pHh8-ġ(mhCzԿU9 :fbs4w9[_jm3.$+#c$Omm,<ޙ-^pfmq{r:s0w&UI?1|9~pzO|ə{x+2@q`,><2NלZ3x/s0rn /`yO80/H?"WpfylC5)hcb ˿W=F  bw Epie 4`f6qe*Kaங+q,<#Hi D;@* {@vN xd`[}JXۊ:am+cX <9^z6-Էq zga#͜h0 ζ)c`-ڹOgU -=J9z) dv>*0ft WC ^ \Vp]mp>f܋/O 1&N_ Y  rNzg5]`;m'I|"㧚8C`7qΫ$ c PqȾ?4Δ)Kĸp: X[ܞxBπ+Z'z3f8ApEh h(v?{<W E˱3B1ulf@ H0{K~(h xl:p=t:0c¢G}TX7 P/ƷcL@eq{UmŭZ"-W [HIENDB`amide-1.0.6/amide-current/pixmaps/interpolation_trilinear.png000066400000000000000000000023131423227705100244650ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs-~@L2tIME 'XIDATxkeϚmHH*{a]`"쥔R"H7MDaPD!BB".!)B/XQ֛(Ů^̶gϞYΙuspgf{~3< -\]N묱 QPw`Dʦe@fd1v: opB)€#&pi*Q Fwf8_Ѕ!v4}hPizfލ#+^ ƣwwdeJW7 O؈?v918C9nt]zh*2le2le2le2le2le2leSoi^LjN/9_\ʑoV\=yb,{ ͼ2F`}FsiN#n' C>e7GA"b/qU[9d,2{Y`/v")a;]g[PT?`Icp"!"Sߩw[8N?-bπ= V n^^[ LSO{gLE1o*qx<`PFx],[~\d>EpS·aue1uj3 ~Kٍ\Fakƹ/ *=Mlɸi:,L-R&&3 ;E2кڅ"ؖ "{٢j: j@k1_Jư;C%lSՐĕ|_Kt ;jU}3<#V83ڂa1sЉOpGbY2x(`UpOpnƺM^ZڀqžIm6G{A?y Y*8pv;nX ~.g3j$s*hk1f*NIϨ{?i|$yot쯑q4#n?v$tJ|$ VQɔU,IӐXxl@MV#|$I$I$I$ITF7**5vX|K=΢DmhrUVn>)Fpf\` +9v>&;>'*`cq,*> Xb|\_KqLT\؅Vĝo&vlz™ze6`;.}%^ŧXAX|Gijyޏ؄Nun& 00q}eAp*"h簴࡚7qI1T}JD'-/K ؟\jlDo1 :0~p*RcT{uƏEhoxBw2VŁlg> `-qkK_Fu |N=p&TQ>~GbqՑRn ѧ,XS O8'X"6Ye8= 'ޜi0}Q`~7{@~)qYgrEpZiŋ%6m}v&gI$I$I$I$Iml&IENDB`amide-1.0.6/amide-current/pixmaps/layout_orthogonal.png000066400000000000000000000016261423227705100233040ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME .lk3#IDATx]UU߈M" ~Ѓ9='OC/B(%*A%QCOQ3㐊Zν^=s?؛ݘ_O_Ow/Ŭp&#}U_$(aOT/O}1cv֪t"“o5*̀q~C<^<ߋX^_gQ/Q4!kq|\ bux>rr s^E?0%G\P1?+ن88+qNlL[<`1v;\wؖCfh~(m&" [JS'[ǺX p:Fy~8Nrh bz#t8,zv?Gp ob:XH >(<+mLq;9}\SEΌƪUK1)ڎQ/e)dl'^a"})lh0 /cnhZ8C~(Ӿ]`KN0 9PмOӋZmxlP5Ѭ<"Q+,'4ͣh*bpBiY|V @ H$-$LplRͺl 7ҲlBIIENDB`amide-1.0.6/amide-current/pixmaps/panels_linear_x.png000066400000000000000000000012241423227705100226700ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME 4!IDATx;hTA߮&YHP_ I(XXi e KFA1G" (W Z%wݽ{7B<Lugcw.AAZLc?ȾS 0 î1LǔWW%̵%dϸ#ؔ~ {>/=_ 9&WF#x6s(fYxi5HJ2M.fp? h)6f N~d$vXdZ')~5HӍgi7Y86L3Z w[ҩN'dmZi0m]+8TBn5[)XTp`Wx}P4 3 dw1\WƉt{=-/!962-j>C-6c-捕. ! B@! B@! B@! i>&JI})'YTZdZ ]%-Z AA7̍gIENDB`amide-1.0.6/amide-current/pixmaps/panels_linear_y.png000066400000000000000000000013751423227705100227000ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME 49&ęHIDATxMHTQQ4 ZB)& l,* ܸIp2p)2p!WUآrA)#"-,[8❁yܹs?'\ `IAIq` xL4z`(], m./@L&&U:E'k=+5Rٖ 2sF>{!٪uW7̿xԗI )@&$OYA `^c(@g4B@uST/&mQ(w`:[ڪ%MFyĠBE6*A*a .} 7)Ի OCX & BIk@0x& Z}Gfp@h>=E;nl,/?eMuhDug(lQE J%QwlT.G>8{CTD%I$\<`x)Ku|utدLx@O'x؊[ M b#jo 0G,acK^JĀ6=\d XfjvY`8 } ԟpIENDB`amide-1.0.6/amide-current/pixmaps/panels_mixed.png000066400000000000000000000015571423227705100222060ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME 4wrIDATx]VE~)Ქfi Ha jHA ~DⅠKJMe ⅵ]7^D ]}Pi7jHa Qn3{3sy33g9mrx-o%#8˰oI M/,.M4. Di.E^u謹>, >{Wiu-f*ΉCMtN.PD@" H$D@" jwgG&ygKd 8 as2bW镐P:fX{ +7aDߑU$+x+5)!|g(xx_Jpp24# #mhe:olx]s.lU:>uU^۱;v.h2BgX'|k0Wm Xʵ~usaqG83o _t&! PkFL +Mv\yMk@^Y }gRW" " " " " " ?6:`It[! 3mm[B4,ƭmPZ $>tMIENDB`amide-1.0.6/amide-current/pixmaps/roi_cylinder.png000066400000000000000000000026541423227705100222170ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME R)bp9IDATx[lTERŶ QۺF*Œ7|bb ^|`1ु}ACh P6K E#RQ no>̷l/fo2eC90]=>\,\|6uR@NTO.@x{*;~-$;#φ#w.(+0< .uS=JM: \ \7\H];hج5 lV.5z6 ͐C8l6\@#$ʬ)^5R>~'l4L@?$^8k3& t`H#'bVooeyPߟKE }| TPXs\*y'N0~*2RVUo%z^TWqXDܯ<;m^(юbY[7 \/S&BT@Thqv%!EH-|'.b#S$/;  `MsY\vE*QQ?'0Y" {P"R{L!YcB۳x|}%)Sp:Z{+0&^_l<6~}t;cyuCc%u4bF[%J( P$@Iw(3bYhsNULc#&@=&Aj| 0d6J%N#&1LI` &CVq[zXޛ()NB>"{&919\>Q#7A ݪtv|E^h,Q,nN-K㦪B^+.IqJez vM5!q*LD8 V"C;on3j`ID Q "E4{*QuHcm1;AcbF#>#t-`;\ί-_k"-1| S;mX+ K:՘).~~nńIAmt`+L1Mmp3m/͌?MMys#Jm GuBT!W[4n/aa1N.KMd"V178{-tWuf,buewjLIJ̕ذC7fJ&GpE?Fu?IENDB`amide-1.0.6/amide-current/pixmaps/roi_ellipsoid.png000066400000000000000000000033351423227705100223670ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME  jIDATxݛhUe?۝KjXrBd, lHN-̔ (e"(  iẗ4+#Pt:555Φ|}s9/y>s,R0q@{V jN_248\zN-`dؙJE{}ۀ1(CLۮ3*`hg%(` q1pZ*v [co`YmEX K]P{ vs"`{V> <4]1< T⾦9_i* be': VaDOOT1-V+z,,t5%%;!/Y7m!9ko2xm]!D,ѳwX\2 yݱk-:?#d0mxk9(xgݼ2 KxY]!Df¤ڒlCJ{= 4>|5UchrSKm^!͡`Vҿh/\ |gt+*fi/%"6n^5HEǭi8+Fgx)آ (9ayLA\y >{RsE85ہ71_J"AN,|!6^9"],!nAԤW8'?8 |rKp_ 6v,7WX8%^HpT[bN vkv"RPoW^X[ (nxް]Yw GDKn HS18g]n/ͺj-5Cv`?myG$_6;@$*%"b\YTӑ1jvIXKez%^>hDPսюs0Z>품2jY]t I֟eOJ~G`"0X&%q<8=.+H:%i .>'um0^$.bQIA}d(x!`d$6a݊än0|t9@fIj\o01YJҳAqEM?7! .TاIENDB`amide-1.0.6/amide-current/pixmaps/roi_freehand_2d.png000066400000000000000000000014601423227705100225410ustar00rootroot00000000000000PNG  IHDRw=bKGD pHYs  tIME2IDATHՕKa?ffi0م$D:uTt]HЍi8 L˅P*Ӵmim۞.z]s]?x.Xd@-#Qƾ?ni~:b{Qb:t3 |+Ycl6vj{ &mq>Aʿ 4ŏOꮡP=F F f33@jj&NLDm@`)$RժHZ7>%,sjp$`+`PXeHS ?_K ĚD IENDB`amide-1.0.6/amide-current/pixmaps/roi_freehand_3d.png000066400000000000000000000014531423227705100225440ustar00rootroot00000000000000PNG  IHDRw=bKGD pHYs  tIME4cIDATHՕKQ?|iҋf _Cz)"/ºpBo$S"0- UosmKˑn;]t~Yd>>?ш3o$Tmcx Y3+l5.~zZ{ FKtʏ.7_W"IW< > KpXU@ džC}i\ӘH;sCs؁&l6 ,&AgWw%zmw"v>Sh6]e39xjo|f_lu"=$QY^ "2Iq;j\ҫ1ݸBUtnreY&a30"\qct40!^TUߤ (r]Y@Rn/n'.Rf484cp;pPw+pEJ` 𓅿Uc %,-b}G5lq~ہn)mbMI$VS#2 cL~E7a% ?7B@)p!0tYLTW?L՟t%<-K ^ctjVB7x p*pD,W*4ԡSL4)QϭaBp8T{Huı-,q1Q&1q],bN[ANJǔ/)lL2#`/˨JPe07!ˌ?԰Dqo.BIgR?[H7 W .'[ϫ1 v[?s+(6(-1'`f]i('x&|'jeM|"^} (r, 1%K5ƯbO!Gw _WjaooT)_lXV"Z)1|3wIX-k%><aCr}0Cr(C^ZG*H.jLjbi$}8ordL x[+a{$3 " X[XQ59}kX\7ʍ,wCR*+Ԃ8b;ΗQ(\eȀ9`ܗ%Ϛms\x9 %+ؓ~Jk>6[dG0(ܟ+)=j><ѡaz:[s5\p3Ҳ` ݫ+࿞5gɅx'/4jq>:NrJQG6oB$ٶ^ֆ *-g~jx[p閼O `O 9)8Z8 ]y1NB1x9)!Α._kD pcʯD/'$$MF ӘS)oS: IENDB`amide-1.0.6/amide-current/pixmaps/roi_isocontour_3d.png000066400000000000000000000037751423227705100232050ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME /-7IDATxݛylU-T,Z⎈Vp)*bQ5DF(bL܂FpD[TRTT*`pC0  TKi)qeޛy/}o7svoH=~@W` 6΀ ۪${GS[~t Z6Jb{;u!J`0[c*Y`bt0ank;Ŏc73,ƹ$lGxGlS^ܮ~[w|Yv DR%cq J˶O?ov S9I[x'|IIdR_ou!A o8&A +UDyex8úpȏvv#0Vi̝s0A`*̅[Bc.D[$6G|3rǒ{HTȲI3"`<+eIi ܤA!"o)!yIYIS v&;BcJ 0#]a(1)VvgI~O @MX}~Qxt8xLUe&ѼbFpW$ccpT jb1 b<}c 8oE]$g|HK"-,?5zTµ*{?dN)cEEwc/&ayE]!dV+lGրi$@ŞGڣ8PP<<4m~IBSր?-)%$eR_K$I*T FyYN0.3==k} /ErUX+hBr- )MOg+Th[-W|ψ:Q`xiVN@ .:_D뇎*׊J}nVf{dZ3/]z[ֵs#avZ5q8"ȓG?w};R miλM 51g"«1[]GX<'Pq'a6^9W?{?aSJf$n~jtO6ds#҈i $E'Y)k^_dt+p9iڂ P.lL3끧d-Wq~yŪl ]f?P JnWzRIIzpd+Up"AGAeY>'E2Jd ?zo0J Sc~1%D P^-;3Y n{d>A,SBDL/Q̞}qdZ`6 'I ć3Q1'No qKm ^9٢%IENDB`amide-1.0.6/amide-current/pixmaps/study.png000066400000000000000000000021641423227705100207010ustar00rootroot00000000000000PNG  IHDRo pHYs  d_tIME*7M8IDATxOGڀQt"MLD*ǡ9W4D'4'ri5!: DHAuB~{wgâH4tofS u])Av;  -<í[@{{{SSS߷, 8YUVѿO^Yb;(* !>BoYW1]Ӣ(}_ӴRcc1EQyW׿qҥK1O)e r]P(R$|Ba lllj5 amMUL|qq^?|hX}{kk;wm|NOO/,,tn !PX8s|xY\nZ0$fI)BEyc 'ɟ> cL)%$/.^d2ɑX:NRccc===_c,--d6L&igLUUU4M;߿|r&1 1L&ERc<>>NYYYT*N#1!( !uuvRJ9cq*gs큁o]?8qFi|po O h4'ɞe6j.])ߑ/)`&7NIENDB`amide-1.0.6/amide-current/pixmaps/target.png000066400000000000000000000004551423227705100210200ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME  KIDATxA 0Пg=J EWR yfaxFdIMzdW4v&55kzOoNmGyl%#"""^UًJ0U4 U,}`*zA'oJдZwIENDB`amide-1.0.6/amide-current/pixmaps/three_compartment.png000066400000000000000000000061551423227705100232550ustar00rootroot00000000000000PNG  IHDRpZy pHYs``zxEtIME1"$ IDATxO>h.@v#e9iwzr6* G#JUof<$3:!/_gv&F8xm7 X4`2G[{yX,qs"i_U0ƪkYSO*شҠSO~&iP橧S6U!ϳ0<'[2yiv!s^c&|4E11`z]SJ7 .r^tfgYV׵tT1O={$^czN~'/y|ys]ׅn}=gVA+~ߧiM-q_hU{Fꪨ( CX@) ð4uea¤b,lX3Vm>" Բ2D0&(ԲVѥeϲ gE9n!jeV>cE/$Is]7oǩ>m kz<l_h ˗/in60 X܉SU߿Ryc}V #J)4M!H! XڃY}<V ?|7PQqЁsZDmO]p!+#jzu${qQUB,`\ $8F>Qϟ,a;bq٭S*QJ.} \ E޼ ߿{_%Zj4߿A7=؇#2aq/'љJl*y¶0^ D8~a Aʤ|1IPp~C.c"6 yiTuą>uHǼ2vK|舥͍Y+8nisjvA})8Gn|߷No"W ii _~iyݎ@k^'yI+5zLD8, 9c,󻻻Gm׼@Ha㣸bcs|' X~?6ǵ^^ ׀\^ 5 6ׂ{ ^;66ׅ cmL~qnCf{=^/6r,B3ڐ$,%]IENDB`amide-1.0.6/amide-current/pixmaps/threshold_style_center_width.png000066400000000000000000000010601423227705100254760ustar00rootroot00000000000000PNG  IHDRo pHYs99ٓFtIME &҅IDAT8˥19a^ ˂JنD &`4\Y$e:M$e3IDI(ߠ?v>>zƞj|>ozөh gtt:M&vu׫ Hd4r\* 2|$)JIƣqQJ,vl bAfI Ph4bNSV np8jv;& qeYar-t:MD,x<36x\.F$(*sxM!_lh&Iiv785BxDgD$/(, ߁pZp(~B[V3L N3HnkdC:AA6}}Vl.n; V+0].˲0z="/xeT5IENDB`amide-1.0.6/amide-current/pixmaps/threshold_style_min_max.png000066400000000000000000000006451423227705100244570ustar00rootroot00000000000000PNG  IHDRo pHYs99ٓFtIME CDIDAT8c|x򥡡!*عs.ӧٳg#ab ;w.11qh$ 6?~SHS:o<\ 2ɓ'O<Ah" 0MpZZZ] QQQtE,CAX=\ |a4k$s?YA">|455 .]t 8YYلƍ)!edd6lpἼ7o`UClQبcZff怀99/^_C̙3#""d IENDB`amide-1.0.6/amide-current/pixmaps/thresholding.png000066400000000000000000000007701423227705100222240ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME #OIDATxAK@A(BJB%2=H5ySI7%/qZ\[|k7n{4` 0<4'%PV%P 3@$#@Tk 7Ǟw~[gLC+%f @* Y0ܸaB`g<` @I]< lK_@ 4 b,UDŽ}/Z*?Rƞ>l~ME^'Ep8*3 Dn.^.Kl%Dݝ$ Vp9³= t|ihD(ڎy3IENDB`amide-1.0.6/amide-current/pixmaps/thresholding_global.png000066400000000000000000000020201423227705100235320ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME !,o^nIDATxOUU+KTErR*%"z`$!0DE 6Ȩ%X,.Ҥ?w-?.o/8\8g}Zߡ};;0=v`bg`E[/ CcbGa,g\N8V j() |,ެ *jqxf xTM8ۏJb;^ 0װ,b_؉/8o 083pMhm}g܄9skf`wTuO6 KWTq,,|3#9o)Tu Am ط7 ,p]*Qa>Wm Xʵ~usaqG83o _t&! PkFL +Mv\yMk@^Y }gRW" " " " " " ?6:`It[! 3mm[B4,ƭmPZ $>tMIENDB`amide-1.0.6/amide-current/pixmaps/thresholding_interpolate_frames.png000066400000000000000000000027301423227705100261650ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME "'0eIDATx{TU?;muk[bDhR@T$Bd$,AdaӕLv2#5 ݬIv|,3;3wι.{r{>w~8]\_eD@y_WavF}Ol p8IJ` P *WN/=[}zw`ިn3krlYh>Шa1 4eR? .0n nuX/Ъ+= g݇Vk.8`fb`XO )OU?@ācQRpOJ3R~Dp`*x3+i/Ĺ )"f}`pvYP ܩuyӢ-9FY>x3NT׺E`ni5K\-ROvxAXc 'EmHL8^ǡ&4KMmgn{UrZ/gxy2plO*Bv'ںRzd:'( ĔĘ#bLedsɭDi@rx lz6w%=C/ŏonR]T-fZCr n_I`ہLǃ TYk8&Yg `&X<)@͔ĉ =rOR-oN60Ba-^⯘Z `*^hBHVI0Sh &{ݬg-8H0uehicVȏpB\)x`jve"`Me6~?Z2`6pE#x2[.ߍ9 "gdN}AtZed42BA SL-Jl6CK @c;R,f0Yv!\!%10l+ xJYhœCH?bZ?a*#T?c<7%>SiVD SØc.zfeR#.C|^* ?]V"sT՚l.,TܐN" Jv@(rj@FO;8PA >g:W{os:gi.(S?l ápr[ZIENDB`amide-1.0.6/amide-current/pixmaps/thresholding_per_frame.png000066400000000000000000000004031423227705100242350ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME  4eyIDATx۱ ' {eL %:7>tnIz6Α9j$ߤ]IxO՟?bi/G>X6?,RIENDB`amide-1.0.6/amide-current/pixmaps/thresholding_per_slice.png000066400000000000000000000011331423227705100242430ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME !зJIDATx=KA$EHL! b6JJڧ b%Zh#Z; mASAp!|;0Nngۙ% ,LFE 8S Ė sJB`Xߤž<<=V/kn|V :.^IqtbF9 ` T/ewY(yn>Z[V!2(6aE9='mJ߆ʔYpӧ(9pRo0(@$sʼnDl4 >|6n/%d#E%q;@~ r><}v4.HTV(WW~> H#}ْؗvg, [ڍj+v-ѕtÍ @_V= ]C lٷj .`zIENDB`amide-1.0.6/amide-current/pixmaps/transfer_function.png000066400000000000000000000016351423227705100232640ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  tIME m+*IDATxoU-ZT~!H6lAR@1P"1; ]3ag&Qĥ#. VCAS7EVꝙ337'7L=y93niJJ(;k` h-{uMЁݺ\0!R.`J6ZQGFl~B(|{-=XRvBQ7n@=ut8M~o!^cևk /Lzug^܆`f/0N|90/ ~Ia^Lry[ݳmչ'f]uϴy-0[˚AGU+`r? i ' 86~C]CrbGdZwYb"fBl"t$m6`GI؅Kx:b5_pXwG+px:bӰvqmm1:]fEn/:`e~&BՌ&BOxĆ̯27 W)_&ܡ7ıw0Y=%7xS2}-+ )~}hF3ЇSFRC e(~)\IlsF?cm=~is*2dS T1ekȡB[sOlL|I|nPHtm?~;p@JًIcm " Z b5#[pDg{5ݷԐT51lƺyg^Ù(:l"T(??zx IENDB`amide-1.0.6/amide-current/pixmaps/two_compartment.png000066400000000000000000000047061423227705100227570ustar00rootroot00000000000000PNG  IHDRon3;332<< H$P@B.ڋT;ElY)V9t:g| 6c*XEQo6f𠔲mьlV0QRUUB8RJJ5gz||w$$S$,3sRZ !Y/TevYbXY c"cl몪v]{am9ӧO0Gyg"nǑR>"s_J={ͳNO~kk`㬭Gŏe#/ >8 "^AXhNv 1!$>>Lp0 zaTB'0V4i9GREQTU%cp r΍a/VUu8,k4W٨+!1&By?(Z#Po1mQh[Aq\eK)((aʨ:VBnR~ۄZ"c\{ $(((qRJ R^*0sF"*bY@ /K]QA{:EJ?(h{45.4_R^UʲŸN=hYy24ձh`Q}$IL1H:ˏ?^^^~9 l0'dYjeseQY.n$ v@( 8vR:"!߿u]LR8an{~~p_,eD]לsWgRAk&yv,qRg~FEp(3I]&.L+r4fjyR[V{gk郊0ճ3@Q]E,z iah.OU4bY]~9]J U  >r׀K a @4͘!cl,GU~>l%u qu=d>莯u|4;ӴOvv<ͽyD1yu]7mZ =xMNoi'[=kBi)OYi3l /dަ,CEud+ ,צ5Ӆ=ϯ)=iC#*B+[`w,>lkpqȈ'qz&l)qB)=@UU 1}h5iCZ*/»kǫ׌LcL)zgʵ=kI`F,J)L?+b8aRj'L*kޟ](h:Ʌ1ޔN^<U&&}?ҼZ`$mw_{TƘ#CQUUEQݮ4̳m+YAp8jt;%oV9vCsߴ0.pg#5q?T&!l+Yt"MъoGM!nSzQzMhj Fpjll\ԴJ ;'[N~2og +-қTh)c£@O7y1f:I|J8#\@5<}V ~%ٴ_@E !hC z3PMtCO5oˤ7-< p 6q)xWRjE0kʝZ}]v&V}N 付X)ABlRg#tcA7?pˎ'!,#tNW3[{kkx(^u ROOO`xKvVBU$ĻJH=R%$^>RʑKx}*^NRuUUN w65gIxF)+&ܫZc &ј٦ ZM MJ conUW֗aM7EE9*DB$!͚֯rupf <|BTRWI$IQmT`gp8`iXFL9gg)8 ߣ. x$oIW}ѫ(>* $b^ťzWhif$WqiZIU@SHJ *g* W(^E;`#yw4 00`X&%i%~IENDB`amide-1.0.6/amide-current/pixmaps/view_coronal.png000066400000000000000000000015311423227705100222150ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME 'IDATx=hAwJw ")BIEA"(- YDA1(?@A ^ A1z!~,ecfv7.;;o7J^m}Fc8uR]*:hc @9i2 \NZ:LX\:9WGoTցYu plMc.^Z.*m `>`e4ٹہC$ T8$o`g\ñ}65p1! V/F!lp ,L ?"g*\ @ޗRp1uqĦlXon~ª |%!<#R[ J[ UzI8 |>`MBi2M-q7pKVg[/C" x +zK=.Ck!=ad{/.g)Uq3iiW<`‚7p.ϛCo3$  C\?wt$hb7,Vzh&ut޽{UZZQF5}¿fopk.EВ%KAkcP݄7֙+M'c\ WNgΔȦ/áѣG5/NPvy@p+t:Ͷµq ]0D2t!D CB02o<$?$, &Ѻ GZ$n7)tHb#wH"ACq;Bn&CҐ`Zz#kIENDB`amide-1.0.6/amide-current/pixmaps/view_linked3.png000066400000000000000000000035301423227705100221120ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME  giIDATx}lS CEiQ2鼄v&K60*euv[1A dEnhDŨ %,"LR E-nnKGγ?|];%[l畮Wy~}۰u#̢2@y׿cwtpppK7+A@޽{UTTdce4q_-<$) YUUU%M)(^Oli>i`@" ʕ+ڽ{w<0"0du{K==0ᰚk.Zx8$D[ 7FFFt%UVVphΜ96aKD ?<'Hvե)ӎ;TPP`@yFd1]O>OZtNI #fPu 6Ξ=˗Oҹ/g8x^^/gΜ!Lv\2f{l|W0]S龾>8qBlV'[6 !'Go ۫Z9Nedd],$)p'gl/ݸa-ԩS*++Sff&`'pwy菝y螞y<iDp$Ql9(UQ& zt:`x{P"BhϞ=:}N&#t4Pm@ } 3@2͂m߾]˖-5T }>-jj]vM8|#[/̝+UUM\+B!]z5jX M UW[Wú|\.,Ybx3-~C낵?Z z@@r\˳.P| Ռ48Opmxb+~ ӫf7f`x[ tE\.N[Q6/L x<jkkw T Ag1I³5‡o('ǣY ƃ~@GmP4pYWG  GIîXbL`Cc!EvnLa5y/ MÆ0+՞qÖiΝ̲8 VYd) … r\2NIB|s~k۶mjvE`ul:7`%Ǻ߰A[nMJ|XGցpS`0 ᮻ>JlWyy;j$I g@vO.ז-[hѢD`|yKif~*n;lhh͛6  mmmڸqi>G^̟~?uuuٰ5GR@@ MmIENDB`amide-1.0.6/amide-current/pixmaps/view_single.png000066400000000000000000000020161423227705100220400ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME 9jbIDATxkU4օuڑ(ە7BQtJ0KAJ ^ъZXZ 8KѪҋ +ݰmZ7o,4o-=/<9X,b\Idxxtyw]:k_e"ŵo-, HW(BWk,?{!-"\mN?y?S `  )Lj~~^HDmmm^d| <0ƙv=00 7lVsssbjnn*s~z  rlVTJ===jhh"`y@oΟTJed2xq ? J|>\. q~|JeUP9 H:FGG۫@ PB w ~t>pD"nA/"6r\nu7꤫Wuh K^d:s@^>.VtVCaccC###D"jjjn2<< %xė#農quvvz@sPtjjJ^d\Zn2fffޮP(/ 5/VYXX`hhE*"_M/75:~w+|)#Za_]q-݆ﶊ$3EȨPOEwy)$܃kmmU:6fc4/FQc +"3es=>2i{1~L <(+qbX,b9B ^򍎷$>IENDB`amide-1.0.6/amide-current/pixmaps/view_transverse.png000066400000000000000000000023441423227705100227570ustar00rootroot00000000000000PNG  IHDR@@iqbKGD4Fť pHYs  tIME  (GqIDATx}hU?{ܲiSS31g\*J"s`V`g/a nAAQ+0ݒKMŔ̹;<[e=s=s;u~TO_>pM~ǀs䧁u@h]YB_N`DWyD7`uGR1 |h.Ҏ-I SC~ pD1&;(XWm [-|A %'@fa̋L(3n1/˲q 42p;[|F|ϜMKj/ Oi>3?v4c-|\NETyX,~ @8cuM˓^6fX_aZgŸ5foYj{-3X]@!0Sg/1U`+Z; ,ȧK)km-0İ`CH]Wuqzf7I hȐd YMkڀ͆#J4@= +/FE4- JE$cR- ^Oj0S0F$N!O+07c+"9ɫ<~b35YY,gxn@*s e{}nYҁ*`u, 6nuL Hw9"#3C6&|d8CW%`E%<*545Y$=ŚmPWE4\%`)2V')eV〾Oۜ@n)];zi8(J04_%NنRXTz*ժi{>h6`n @Ϊ ۢV2V M$.J1ލ#v:֑bZC]ih?s'*x#ֲΘ2 ,#KoOɦ`^;K) Mc*L*aj&˜n1B%D‚6*hժZE[B&bIPV213j!YH6X=yxY'HTYYBaCCL&pkkkKKKX,Ld0ph4(JM333o6Zmmm-aYYY"222t]]!* |yl6k<g|>i`JޖJUTTI:%x===bz> hll1 Bpttdkkr$KKK߀B!` mkk+))aP]] EEE[[[z2(t: D"nyya]]]2vbV]]  {{{$bg2fff\Vud2~||1yp8zA0-GFuww78/#v;EQptLhnnh4,^;N™06-JVUU8Nt"p8z{{/..@ (JBt:A(R*^7''M D"XF @rlB U*Ih4 ONNF* iNRMMM###'rss Hqq1eee8X,WVV677;;;SEQb8¹9$Qf뫪kjj0 +--}xx`d(Z}xxV[[[ L2pvvVwww-d8&bjjjcc P8 L&x<>??X,fZM&a>o}}+xO boo@ x, A}GH$jtE1 y{{3 f]!L*JurrH$l6RWޓ.IENDB`amide-1.0.6/amide-current/pixmaps/window_bone.png000066400000000000000000000020411423227705100220350ustar00rootroot00000000000000PNG  IHDRw= pHYs  ~tIME2;b IDATxK+]Ɵ{6e% ?*h( bc+VHae VVA?@ bc!~Cظ*ly{77ɽ\ށӜ39 G*Ep!z<100! fqwwK#LT*E?9-..FadYIeituuET,% _UfffI/,,T$*4M,H,8HG,E}E"jjj@ED"@ϴGa.UU<99IPR"mooa]KG*!ɐ㩊NOOn'@$7E&...hvvf 'zMj݇Q0$Q71FPl6'@QZYY![W(FiiiC 5445@euq4͚c_0 lnne]imm%YOiooHY!2$I$IC;;;188%Mhyy$硫|t:v$ByRU~~Nh򪸿GSSq}} QfaY$IneYl0 <666~ 0:CX((J( ( `UHɲBP "^/Rr,*',Ju׳ sy𫟈*9`be<*?r`&v; zzzi À(0, @>=<ZZZt:( &&&)躎GaLOO#!H NWIX9A$b~~---18>>5SՃZCcc#\.!_~G( LRD&AUUǡ^S(#eDOO`ǃ,N$~ pi4󘦉뺨,EVVVX]]~,FLd}}4QU=FGG~:>DV7n I!pIPUA]|Ewޥ MӈF|>֘IJ,Ν;$I^˗/S(h4Xau]$4Q@ǃu<OtMӐF!I~Y{eFFF8q( B<^O>o>z{{)  GGGlll`6zI3quGRVI$coB( DYUUxfe*bjYY__R Im(Jj5:;;$ qX]]Eu9)J bGZR4_˨:p]B@kk+a`6,h4H&Ȏ4 MӨjXNs"\t,jZkp]`0BDGGH!zEQdaa`0ȋ/"Lb&`rLVc6R EQe/_}EQlnn (J>|4mp8,ˤi* D"4M4M @4lm/_099Iggg,}ET*X(IqY$155ȍFq?N8Pǃmb1r߾}0 ǡVi`UUR)<8"KKK\z&($IH%QVqߏ%J188333փh4ٳgy벲6Oa~ .I$HP.}6o޼G$EԩS300@X$˱뺘I<T*.PVt]ܻw *ߋa";wyh4u1==-.\ |>u/4ƙ3g&J>|`nnmlۦV[:ЮIENDB`amide-1.0.6/amide-current/pixmaps/window_extremities.png000066400000000000000000000011401423227705100234530ustar00rootroot00000000000000PNG  IHDRb$bKGD̿ pHYs  tIME &@qIDAT(=jQϙ3פI'ITDtV)|@F}W" Pm.3MrΜ˸Ev?Se1AR2ڂEk-KJ- evwav"v Y26Fr,*afݒN9T6DjZ˺@,V }f*pD +d$^m'@2h2N5̂ท(Σ'>Nur}7[>:.zUsp{cOK #ܾ{toY$s˹ۙBgUqѻU[:%LAY0LJެX71q'7ˣ\ 6oWZv$Y^%18R߉T%dYLRRJ)BB1v6 chh횦dKr$X]]yrYQl6KpΝVKKK|TU r{FtzxxXӴt:-io?~@JaeA},fq!tmonnٶ]Ym[^kE(cccPgu={HŢeY,~%moo7p8˲{m>sLZy!D)eY0}E"лw4Mu]uIJR<MZ}FxOӦi|2LӒ$奥l6۷@ h4|eY+ Bj5HIaY+i?Tu]0xavvaO>}jYr=e?ޅBիWaABx||͛}j1sss 333_yK \rG9~;*ӧ.^7L倫J8‚?(R̺lIENDB`amide-1.0.6/amide-current/pixmaps/window_lung.png000066400000000000000000000026011423227705100220610ustar00rootroot00000000000000PNG  IHDRo pHYs  tIME u8  IDAT8MkMdlh5?k-顭ЂA/sE o? س'/6[Ic6?&dw23};ݙy|ӆa RJ)HD+")%BÇ>A Lӄ@BJdT?*}(' j5@PBR) CBBh0@-"`RI!8Ϟ=;88 PJ/^HRB(t:qdΝ;733*.Cȑ#i޾}۲,a$Alllp-s)rX, HJ)|߿ qAѿCiZ0 $m}WJRjssZ8H)E)SgSJJ7of|>q˗/탔r{{[J9PJ HӚq(ǎ[ZZr'Ʉa m4Inv8ﺮcO4 ӧwvvi !> !DQA(F nZ}-cL]ժjPfsBj ϟ?q[qJ)4erJNgff(ztZm6QA@)B4$IPB8C-㜟={ʕ+ׯ__XX0Ms^*~00F1y^Z-cL[XXX[[;x`kknk*RTXDia9׌ڶtȷo|ߧqϧR)ҞmR/?cMMMBR9sfbb19RNMMAoic{{{A8N1Ɔaͅa8^]]Byp87^e8I_28h/=z`0@Q]|ٶm0 B1!d8{Nysyav\&<}߸qP(:u˗/njh$IR͛7_`!zҒyÎ㬭` kQj8?~t 4r|%!ċ/^zr>f~n+H[]]]^^j# (nݺp႞<0bF~?bzAR< J=|p^_r0 UU+aBzP(*JVRj:(>>^V~_(8w:UU|BelB,فlRr9XZSymǏo6bq\X,JGQq\պ{.& DQA!c1>88p]w>0 0ye 0(b1!,˲,[VөׅBApx߿mNӔRA`E(Bxy~gg!Jis]7~O&`zvaB@!d2hqkf$I߿m[Eq ØL&qkf,ˍFa  y!Dql$Ij4W^%qy~:˗/[V.l6 0 1B!$ !|h4VBn?;;3MX,AP,9f3`0X׍Fc|yyih&2BӧON'PJE!dr(J:<ϟXu?|0,~6t꺮ao߾uu0 !n^zUӴn+r<q\;<<آ(zSIRaWVu]x<f2˲_$|iy0"<\B6IENDB`amide-1.0.6/amide-current/pixmaps/window_skull_base.png000066400000000000000000000027541423227705100232510ustar00rootroot00000000000000PNG  IHDRo pHYs  tIME !$MSIDAT8}OMgwmmuP m@cWhH`Dq@@M{leeeJftX$ID"sNJD4?@NsddC477*Ia(ʲ p&0qrQV,#HVgΜa`4M&A0,IR8nhOÇ^j?X,6p8.,8$jZ(l6۷OT*U^*AHfW\|l.+$ٸΉ'z,˿ I\.WRR޽{$I.--]~}ffyjT* (`0pPiAQyzzz%Ix<;vسgOkkʊpBSSɓ' Bat:=;; ]v577,eYvxxiׯ_Z-A,LzCAnD.e酅$#G}jXqx8;::Wk#ryhh󓓓oiisNTs?gW$IENDB`amide-1.0.6/amide-current/pixmaps/window_soft_tissue.png000066400000000000000000000027421423227705100234710ustar00rootroot00000000000000PNG  IHDRw= pHYs  ~tIME2+IDATxO[?3N;i  X X!PY "ѥ хI7ĽKo`B\]HQ1IBaZ:v-s=+ʿ-jƉ'aYZ 0(  e7UUr /_S*T*j5Wцa{xC4EP(p]3}}}D"$I" xOD" hmmŋ;;;d2fgg9y$J%nݺǏgwwqdssSN177Ӣd2'L( 333,,,B8KKK'0113g0 ;w48b(,FY^^& Ny9`Y"ΧOmyz{{jJ%ri[$BB|ql&H ۶a hkk#9rG>X,[[[477c&ضM 8nIp\S(x M(dYض(@4dccEQ$N>M$AQlqvvvX[[cyym#IbbHZZRTPz{{)uattQe!$5 ˗/FuPa,V(ݨ$IN0$J5,;^/ǏgeeO>0 ,..ڊTUdM4 ˲d2< ,iǎC߿G4"^V,iۼ|۶%w˲mJB:0 zzzH$QUU\,FKK ,// BH0Ne* _f}}A]eYvÇ^!"r#j~T*N+r_*$Ittt7nY;ض-BqD.ׯ_,/*.]"J100@KK ^UUaw0Ç*pnjjp88|rL\foowAIENDB`amide-1.0.6/amide-current/pixmaps/window_spine_a.png000066400000000000000000000020371423227705100225350ustar00rootroot00000000000000PNG  IHDRo pHYs  tIME `5IDAT8ˍTK:_wqquLE/-"[Mms*hצEFE(* J^cԜBݽps>EEEA$#奻㣣X,' nmm*"IR.yfJӴN[ZZ ÿدabbȲq$I4M jTUq??9+My iA2 IdjօOrLni鶶6e2Д"EDQFjFqP(JN3Bi˲kkkEtNMQ4MW*aۃ`cE,8ADB{{{766zZ4MRZ6NGQpZb$I$xL&l0,HD"⿽ Ò$iZAyaӦ^/EQ 0 aXWW((dPT* 4IRlvpp`0@{zzTU8?11x*béq_ $]lnnBP($u:OOO^ej,$IbhOzIENDB`amide-1.0.6/amide-current/pixmaps/window_spine_b.png000066400000000000000000000020131423227705100225300ustar00rootroot00000000000000PNG  IHDRo pHYs  tIME :QSIDAT8ˍMH:]o6Mcb_C."?6RBmڴ Wm]ZA˖BjSmMTH!XNBKMGcq !^z|V.wsb(R(AXVNd|>`ٙT*h>d2PT*<_*I$~y{^*Id0q|{{,~$777=_jnANFSDzq\O#WgY(lIVU*jlfYak*)Fj5Fl6!RT0 7M\.8i]Y,TJl^^^&BP<8qj:Ht:ߺh.h4z> Q% -D"գl6N(EQs%@,cVzr:AW~feppeYWU~2N|:fF&u:\ yA5axrrRP8NJT*Z`@QiVӼ^Ԕq DJeR) ("l6&z&iaaeٱ1@&y{{cv(* ":99l6LV*h0 yccnrOl6d/"Ymr9 ]]]1 CQ\. =#h t7YaG"@PVbH$q0V,rv/@ h4V`0RT *g᜞EL&lV{Z,777l2,˿@<D"FeJ?>>nZ_I, MBIENDB`amide-1.0.6/amide-current/pixmaps/window_thorax_soft_tissue.png000066400000000000000000000025111423227705100250500ustar00rootroot00000000000000PNG  IHDRo pHYs  tIME f[IDAT8˭OhOή][v`tĒA<*7)ADz^$ЃXċE("E ZE`&?6MJiڤN;; 37ޛ?tvtt IEɩy0 Ν  @=q:$ΎBw :u*=zfy\.k.EQDQvE&_l7nPJ 866)H$B)}AOOO({<_AP֭[ !EQ$IIUUz@R:44TWWUUMǎ V\. Ǐ;w |wvvirZ[[NCZ[[=i:>r޽{Ä6UUA@v8q!t:(jfX!1eMMM Qg:::X$I:s޽{{{{`jjɓW*px&&&ZZZvv5M[]]B 466޿||j2Q!&q0::it< ?~ٳ'=zե%Q^/0 ׯ_'&& BMMׯKFQU5H-VBG~083 cvv6Hxbnn;r˗//]tL&STJÇ|طo_(zyc~kעȎ;6!۷o޽rGGGYommmSJ߽{͛0"lll_|RzV1>xٳg777u]O&MMM|>J>}o:4 !bi?j^L`IENDB`amide-1.0.6/amide-current/po/000077500000000000000000000000001423227705100157555ustar00rootroot00000000000000amide-1.0.6/amide-current/po/POTFILES.in000066400000000000000000000016761423227705100175440ustar00rootroot00000000000000etc/amide.desktop.in src/alignment.c src/amide.c src/amitk_canvas.c src/amitk_color_table.c src/amitk_data_set.c src/amitk_data_set_variable_type.c src/amitk_filter.c src/amitk_object.c src/amitk_object_dialog.c src/amitk_point.c src/amitk_progress_dialog.c src/amitk_raw_data.c src/amitk_roi.c src/amitk_roi_variable_type.c src/amitk_space_edit.c src/amitk_study.c src/amitk_threshold.c src/amitk_xif_sel.c src/dcmtk_interface.cc src/libecat_interface.c src/libmdc_interface.c src/tb_export_data_set.c src/tb_math.c src/tb_profile.c src/ui_gate_dialog.c src/analysis.c src/fads.c src/image.c src/mpeg_encode.c src/raw_data_import.c src/render.c src/tb_alignment.c src/tb_crop.c src/tb_fads.c src/tb_filter.c src/tb_fly_through.c src/tb_roi_analysis.c src/ui_common.c src/ui_preferences_dialog.c src/ui_render.c src/ui_render_dialog.c src/ui_render_movie.c src/ui_series.c src/ui_study.c src/ui_study_cb.c src/ui_study_menus.c src/ui_time_dialog.c src/xml.c amide-1.0.6/amide-current/po/zh_CN.po000066400000000000000000003137041423227705100173260ustar00rootroot00000000000000# Simplified Chinese translation for Amide. # Copyright (C) . # # Wales Wang , 2003. # #: ../src/amitk_study.c:984 ../src/amitk_study.c:1053 msgid "" msgstr "" "Project-Id-Version: Amide 0.7.11\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2007-08-05 00:29+0200\n" "PO-Revision-Date: 2003-06-16 14:21+0800\n" "Last-Translator: Wales Wang \n" "Language-Team: zh_CN \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../etc/amide.desktop.in.h:1 msgid "A Medical Image Data Examiner" msgstr "高级医学图像察看器" #: ../etc/amide.desktop.in.h:2 msgid "Amide" msgstr "高级医学图像察看器" #: ../etc/amide.desktop.in.h:3 msgid "Medical Image Examiner" msgstr "医学图像察看器" #: ../src/alignment.c:164 #, c-format msgid "Cannot perform an alignment with %d points, need at least 3" msgstr "所作的 %1$d 像素关联无法实行,至少为3" #: ../src/alignment.c:209 #, c-format msgid "points lists not completely used in %s at %d" msgstr "%1$s 像素列表中 %2$d 未完全用完" #: ../src/alignment.c:225 ../src/fads.c:148 ../src/fads.c:292 #, c-format msgid "SV decomp returned error: %s" msgstr "SV 解码出错: %1$s " #: ../src/alignment.c:231 #, c-format msgid "transpose returned error: %s" msgstr "转换出错: %1$s " #: ../src/alignment.c:237 #, c-format msgid "LU decomp returned error: %s" msgstr "LU 解码出错: %1$s " #: ../src/amide.c:44 #, fuzzy msgid "transverse" msgstr "横断面(_T)" #: ../src/amide.c:45 #, fuzzy msgid "coronal" msgstr "头断面(_C)" #: ../src/amide.c:46 #, fuzzy msgid "sagittal" msgstr "竖断面(_S)" #: ../src/amide.c:50 #, fuzzy msgid "_Study" msgstr "新项目(_N)" #: ../src/amide.c:51 #, fuzzy msgid "Selected _Data Sets" msgstr "选择数据集" #: ../src/amide.c:52 msgid "Selected _ROIs" msgstr "" #: ../src/amide.c:53 msgid "Selected _Alignment Points" msgstr "" #: ../src/amide.c:58 ../src/tb_roi_analysis.c:104 msgid "Min" msgstr "最小" #: ../src/amide.c:59 ../src/tb_roi_analysis.c:105 msgid "Max" msgstr "最大" #: ../src/amide.c:62 ../src/amitk_object_dialog.c:750 #: ../src/amitk_threshold.c:1304 msgid "Center" msgstr "中心" #: ../src/amide.c:63 ../src/amitk_threshold.c:1305 msgid "Width" msgstr "" #. N_("Bone"), #. N_("Soft Tissue") #: ../src/amide.c:70 msgid "Abdomen" msgstr "" #: ../src/amide.c:71 msgid "Brain" msgstr "" #: ../src/amide.c:72 msgid "Extremities" msgstr "" #: ../src/amide.c:73 msgid "Liver" msgstr "" #: ../src/amide.c:74 msgid "Lung" msgstr "" #: ../src/amide.c:75 msgid "Pelvis, soft tissue" msgstr "" #: ../src/amide.c:76 msgid "Skull Base" msgstr "" #: ../src/amide.c:77 msgid "Spine A" msgstr "" #: ../src/amide.c:78 msgid "Spine B" msgstr "" #: ../src/amide.c:79 msgid "Thorax, soft tissue" msgstr "" #: ../src/amide.c:405 #, fuzzy, c-format msgid "%s does not exist" msgstr "%1$s 图像分析项目不存在" #: ../src/amide.c:409 #, c-format msgid "Failed to load in as XIF file: %s" msgstr "" #: ../src/amide.c:428 #, fuzzy, c-format msgid "%s is not an AMIDE study or importable file type" msgstr "%1$s 不是一个可支持的图像分析项目或文件" #: ../src/amide.c:430 #, fuzzy, c-format msgid "%s is not an AMIDE XIF Directory" msgstr "%1$s 不是一个可支持的图像分析项目或文件" #: ../src/amitk_canvas.c:73 msgid "A" msgstr "" #: ../src/amitk_canvas.c:73 msgid "P" msgstr "" #: ../src/amitk_canvas.c:73 msgid "L" msgstr "" #: ../src/amitk_canvas.c:73 msgid "R" msgstr "" #: ../src/amitk_canvas.c:73 msgid "S" msgstr "" #: ../src/amitk_canvas.c:73 msgid "I" msgstr "" #: ../src/amitk_canvas.c:728 msgid "ROI Depth Selection" msgstr "ROI深度选择" #: ../src/amitk_canvas.c:742 msgid "Please pick depth of ROI (mm):" msgstr "请选择 ROI 深度 (mm)" #: ../src/amitk_canvas.c:844 msgid "Parent of isocontour not currently displayed, can't draw isocontour" msgstr "" #: ../src/amitk_canvas.c:861 msgid "No data set found to draw isocontour on" msgstr "" #: ../src/amitk_canvas.c:878 #, c-format msgid "designated voxel not in data set %s" msgstr "" #. pop up dialog to let user pick isocontour values, etc. and for any warning messages #: ../src/amitk_canvas.c:892 msgid "Isocontour Value Selection" msgstr "" #: ../src/amitk_canvas.c:914 #, c-format msgid "" "Multiple data frames are currently being shown from: %s\n" "The isocontour will only be drawn over frame %d" msgstr "" #: ../src/amitk_canvas.c:926 #, c-format msgid "" "Multiple gates are currently being shown from: %s\n" "The isocontour will only be drawn over gate %d" msgstr "" #. the spin buttons #: ../src/amitk_canvas.c:946 #, fuzzy msgid "Min:" msgstr "最小" #: ../src/amitk_canvas.c:962 #, fuzzy msgid "Max:" msgstr "最大" #. radio buttons to choose the isocontour type #: ../src/amitk_canvas.c:981 msgid "Above Min" msgstr "" #: ../src/amitk_canvas.c:982 msgid "Below Max" msgstr "" #: ../src/amitk_canvas.c:983 msgid "Between Min/Max" msgstr "" #: ../src/amitk_canvas.c:1049 msgid "Parent of roi not currently displayed, can't draw freehand roi" msgstr "" #: ../src/amitk_canvas.c:1066 msgid "No data set found to draw freehand roi on" msgstr "" #. pop up dialog to let user pick isocontour values, etc. and for any warning messages #: ../src/amitk_canvas.c:1078 msgid "Freehand ROI Parameters" msgstr "" #: ../src/amitk_canvas.c:1097 #, c-format msgid "Voxel Size %s" msgstr "" #: ../src/amitk_canvas.c:1659 ../src/amitk_canvas.c:2220 #: ../src/amitk_canvas.c:2270 ../src/amitk_canvas.c:2278 #, fuzzy msgid "The active data set is not visible" msgstr "无当前数据集可删除" #: ../src/amitk_canvas.c:3226 msgid "Canvas has no style?\n" msgstr "界面没有风格?\n" #: ../src/amitk_color_table.c:38 msgid "black/white linear" msgstr "黑/白线性" #: ../src/amitk_color_table.c:39 msgid "white/black linear" msgstr "白/黑线性" #: ../src/amitk_color_table.c:40 msgid "black/white/black" msgstr "黑/白/黑" #: ../src/amitk_color_table.c:41 msgid "white/black/white" msgstr "白/黑/白" #: ../src/amitk_color_table.c:42 msgid "red temperature" msgstr "红色温度" #: ../src/amitk_color_table.c:43 msgid "inverse red temp." msgstr "红色逆温度" #: ../src/amitk_color_table.c:44 msgid "blue temperature" msgstr "蓝色温度" #: ../src/amitk_color_table.c:45 msgid "inv. blue temp." msgstr "蓝色逆温度" #: ../src/amitk_color_table.c:46 msgid "green temperature" msgstr "绿色温度" #: ../src/amitk_color_table.c:47 msgid "inv. green temp." msgstr "绿色逆温度" #: ../src/amitk_color_table.c:48 msgid "hot metal" msgstr "热金属色" #: ../src/amitk_color_table.c:49 msgid "inv. hot metal" msgstr "热逆金属色" #: ../src/amitk_color_table.c:50 #, fuzzy msgid "hot metal contour" msgstr "热金属色" #: ../src/amitk_color_table.c:51 #, fuzzy msgid "inv. hot metal c." msgstr "热逆金属色" #: ../src/amitk_color_table.c:52 msgid "hot blue" msgstr "热蓝色" #: ../src/amitk_color_table.c:53 msgid "inverse hot blue" msgstr "热逆蓝色" #: ../src/amitk_color_table.c:54 msgid "hot green" msgstr "热绿色" #: ../src/amitk_color_table.c:55 msgid "inverse hot green" msgstr "热逆绿色" #: ../src/amitk_color_table.c:56 msgid "spectrum" msgstr "光谱" #: ../src/amitk_color_table.c:57 msgid "inverse spectrum" msgstr "逆光谱" #: ../src/amitk_color_table.c:58 msgid "NIH + white" msgstr "NIH + 白色" #: ../src/amitk_color_table.c:59 msgid "inv. NIH + white" msgstr "NIH + 逆白色" #: ../src/amitk_color_table.c:60 msgid "NIH" msgstr "NIH" #: ../src/amitk_color_table.c:61 msgid "inverse NIH" msgstr "逆 NIH" #: ../src/amitk_data_set.c:89 msgid "interpolate using nearest neighbhor (fast)" msgstr "" #: ../src/amitk_data_set.c:90 msgid "interpolate using trilinear interpolation (slow)" msgstr "" #. place holder for AMITK_IMPORT_METHOD_GUESS #: ../src/amitk_data_set.c:96 msgid "_Raw Data" msgstr "原始数据(_R)" #: ../src/amitk_data_set.c:98 msgid "_DICOM via dcmtk" msgstr "" #: ../src/amitk_data_set.c:101 msgid "_ECAT 6/7 via libecat" msgstr "ECAT 6/7 通过 libecat(_E)" #: ../src/amitk_data_set.c:111 msgid "Import file as raw data" msgstr "导入原始数据文件" #: ../src/amitk_data_set.c:113 msgid "Import a CTI 6.4 or 7.0 file using the libecat library" msgstr "使用libecat库导入CTI 6.4 或 7.0 数据文件" #: ../src/amitk_data_set.c:116 #, fuzzy msgid "Import a DICOM file or directory file using the DCMTK library" msgstr "使用libecat库导入CTI 6.4 或 7.0 数据文件" #: ../src/amitk_data_set.c:119 #, fuzzy msgid "Import via the (X)medcon library (libmdc)" msgstr "使用(X)medcon(libmdc)库导入" #: ../src/amitk_data_set.c:124 #, fuzzy msgid "Raw Data" msgstr "原始数据(_R)" #: ../src/amitk_data_set.c:132 #, fuzzy msgid "Export file as raw data" msgstr "导入原始数据文件" #: ../src/amitk_data_set.c:134 #, fuzzy msgid "Export via the (X)medcon library (libmdc)" msgstr "使用(X)medcon(libmdc)库导入" #: ../src/amitk_data_set.c:139 msgid "Direct" msgstr "直接" #: ../src/amitk_data_set.c:140 msgid "%ID/g" msgstr "" #: ../src/amitk_data_set.c:141 msgid "SUV" msgstr "" #: ../src/amitk_data_set.c:145 msgid "MBq" msgstr "" #: ../src/amitk_data_set.c:146 msgid "mCi" msgstr "" #: ../src/amitk_data_set.c:147 msgid "uCi" msgstr "" #: ../src/amitk_data_set.c:148 msgid "nCi" msgstr "" #: ../src/amitk_data_set.c:152 msgid "Kg" msgstr "公斤" #: ../src/amitk_data_set.c:153 msgid "g" msgstr "" #: ../src/amitk_data_set.c:154 msgid "lbs" msgstr "磅" #: ../src/amitk_data_set.c:155 msgid "ounces" msgstr "盎司" #: ../src/amitk_data_set.c:159 msgid "MBq/cc/Image Units" msgstr "MBq/cc/像素" #: ../src/amitk_data_set.c:160 msgid "Image Units/(MBq/CC)" msgstr "像素/(MBq/CC)" #: ../src/amitk_data_set.c:161 msgid "mCi/cc/Image Units" msgstr "mCi/cc/像素" #: ../src/amitk_data_set.c:162 msgid "Image Units/(mCi/cc)" msgstr "像素/(mCi/cc)" #: ../src/amitk_data_set.c:163 msgid "uCi/cc/Image Units" msgstr "uCi/cc/像素" #: ../src/amitk_data_set.c:164 msgid "Image Units/(uCi/cc)" msgstr "像素/(uCi/cc)" #: ../src/amitk_data_set.c:165 msgid "nCi/cc/Image Units" msgstr "nCi/cc/像素" #: ../src/amitk_data_set.c:166 msgid "Image Units/(nCi/cc)" msgstr "像素/(nCi/cc)" #: ../src/amitk_data_set.c:170 msgid "Single Scale Factor" msgstr "" #: ../src/amitk_data_set.c:171 msgid "Per Frame Scale Factor" msgstr "" #: ../src/amitk_data_set.c:172 msgid "Per Plane Scale Factor" msgstr "" #: ../src/amitk_data_set.c:173 msgid "Single Scale Factor with Intercept" msgstr "" #: ../src/amitk_data_set.c:174 msgid "Per Frame Scale Factor with Intercept" msgstr "" #: ../src/amitk_data_set.c:175 msgid "Per Plane Scale Factor with Intercept" msgstr "" #: ../src/amitk_data_set.c:897 ../src/libmdc_interface.c:444 msgid "" "Voxel size X was read as 0, setting to 1 mm. This may be an " "internationalization error." msgstr "" #: ../src/amitk_data_set.c:901 ../src/libmdc_interface.c:448 msgid "" "Voxel size Y was read as 0, setting to 1 mm. This may be an " "internationalization error." msgstr "" #: ../src/amitk_data_set.c:905 ../src/libmdc_interface.c:452 msgid "" "Voxel size Z was read as 0, setting to 1 mm. This may be an " "internationalization error." msgstr "" #: ../src/amitk_data_set.c:944 msgid "" "internal scaling factor returned NULL... either file is corrupt, or AMIDE " "has a bug" msgstr "" #: ../src/amitk_data_set.c:1011 msgid "wrong type found on internal scaling, converting to double" msgstr "" #: ../src/amitk_data_set.c:1016 #, fuzzy msgid "Couldn't allocate memory space for the new scaling factors" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:1308 #, fuzzy msgid "couldn't allocate memory space for the data set structure to hold data" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:1316 msgid "raw_data_read_file failed returning NULL data set" msgstr "" #: ../src/amitk_data_set.c:1323 #, fuzzy msgid "couldn't allocate memory space for the frame duration info" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:1419 #, c-format msgid "" "File has incorrect permissions for reading\n" "Can I try changing access permissions on:\n" " %s?" msgstr "" #: ../src/amitk_data_set.c:1431 ../src/amitk_data_set.c:1438 msgid "failed to change read permissions, you're probably not the owner" msgstr "" #: ../src/amitk_data_set.c:1445 msgid "" "failed to change read permissions on raw data file, you're probably not the " "owner" msgstr "" #. unrecognized file type #: ../src/amitk_data_set.c:1499 #, c-format msgid "" "Extension %s not recognized on file: %s\n" "Guessing File Type" msgstr "" #: ../src/amitk_data_set.c:1640 #, fuzzy msgid "Couldn't allocate memory space for row_data" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:1646 #, fuzzy, c-format msgid "couldn't open file for writing: %s" msgstr "无法读取 %1$s 的值,代定为%2$d" #: ../src/amitk_data_set.c:1652 #, c-format msgid "" "Exporting Raw Data for:\n" " %s" msgstr "" #: ../src/amitk_data_set.c:1676 ../src/libmdc_interface.c:1106 #, c-format msgid "Error in generating resliced data, %dx%d != %dx%d" msgstr "" #: ../src/amitk_data_set.c:1701 #, c-format msgid "incomplete save of raw data, wrote %lx (bytes), file: %s" msgstr "" #: ../src/amitk_data_set.c:1797 #, fuzzy msgid "Generating new data set" msgstr "旋转数据集" #: ../src/amitk_data_set.c:1811 #, fuzzy msgid "Could not allocate memory space for volume" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:1844 #, fuzzy msgid "Failed to allocate export data set" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:2340 ../src/amitk_data_set.c:2361 #: ../src/amitk_data_set.c:2383 ../src/amitk_data_set.c:2405 msgid "unknown" msgstr "未知" #: ../src/amitk_data_set.c:3904 #, c-format msgid "" "Generating projections of:\n" " %s" msgstr "" #: ../src/amitk_data_set.c:3935 #, c-format msgid "" "couldn't allocate memory space for the projection, wanted %dx%dx%dx%dx%d " "elements" msgstr "" #. set a new name for this guy #: ../src/amitk_data_set.c:4159 #, c-format msgid "%s, cropped" msgstr "" #: ../src/amitk_data_set.c:4170 ../src/amitk_data_set.c:4177 #, fuzzy msgid "" "couldn't allocate memory space for the cropped internal scaling structure" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:4183 #, c-format msgid "" "Generating cropped version of:\n" " %s" msgstr "" #: ../src/amitk_data_set.c:4363 #, fuzzy msgid "couldn't allocate memory space for the cropped raw data set structure" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:4491 msgid "Filtering: Failed to allocate wavetable and workspace" msgstr "" #: ../src/amitk_data_set.c:4498 #, fuzzy msgid "couldn't allocate memory space for the subset structure" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:4518 #, fuzzy msgid "Couldn't allocate memory space for the subset data" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:4527 ../src/amitk_data_set.c:4709 #, fuzzy, c-format msgid "Filtering Data Set: %s" msgstr "过滤处理当前数据集(_F)" #: ../src/amitk_data_set.c:4680 msgid "data set z dimension to small for kernel, setting kernel dimension to 1" msgstr "" #: ../src/amitk_data_set.c:4684 msgid "data set y dimension to small for kernel, setting kernel dimension to 1" msgstr "" #: ../src/amitk_data_set.c:4688 msgid "data set x dimension to small for kernel, setting kernel dimension to 1" msgstr "" #: ../src/amitk_data_set.c:4701 #, fuzzy msgid "couldn't allocate memory space for the internal raw data" msgstr "无法为时间数据分配空间" #. set a new name for this guy #: ../src/amitk_data_set.c:4888 #, c-format msgid "%s, %s filtered" msgstr "" #: ../src/amitk_data_set.c:4896 #, fuzzy msgid "couldn't allocate memory space for the filtered raw data set structure" msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set.c:4923 msgid "failed to calculate 3D gaussian kernel" msgstr "" #: ../src/amitk_data_set.c:5341 #, fuzzy msgid "couldn't allocate memory space for the output_ds data set structure" msgstr "无法为时间数据分配空间" #. set a new name for this guy #: ../src/amitk_data_set.c:5357 #, c-format msgid "Result: %s %s %s" msgstr "" #: ../src/amitk_data_set.c:5392 #, fuzzy msgid "couldn't generate slices from the data set..." msgstr "无法为时间数据分配空间" #: ../src/amitk_data_set_variable_type.c:56 #, c-format msgid "" "Calculating Max/Min Values for:\n" " %s" msgstr "" #: ../src/amitk_data_set_variable_type.c:136 msgid "" "couldn't allocate memory space for the data set structure to hold " "distribution data" msgstr "" #: ../src/amitk_data_set_variable_type.c:144 #, c-format msgid "" "Generating distribution data for:\n" " %s" msgstr "" #: ../src/amitk_data_set_variable_type.c:259 #, fuzzy, c-format msgid "couldn't allocate memory space for the slice, wanted %dx%dx%d elements" msgstr "无法为时间数据分配空间" #: ../src/amitk_filter.c:61 #, fuzzy msgid "couldn't allocate memory space for the kernel structure" msgstr "无法为时间数据分配空间" #: ../src/amitk_filter.c:73 #, fuzzy msgid "Couldn't allocate memory space for the kernel data" msgstr "无法为时间数据分配空间" #: ../src/amitk_object.c:602 msgid "AMIDE xml file doesn't appear to have a root." msgstr "" #: ../src/amitk_object_dialog.c:156 #, c-format msgid "Copy of %s" msgstr "" #: ../src/amitk_object_dialog.c:236 msgid "Basic Info" msgstr "基本信息" #: ../src/amitk_object_dialog.c:244 msgid "Data Set Name:" msgstr "" #: ../src/amitk_object_dialog.c:246 #, fuzzy msgid "Name:" msgstr "时间:" #. widgets to change the object's type #: ../src/amitk_object_dialog.c:266 msgid "Type:" msgstr "" #. widgets to change the date of the scan name #: ../src/amitk_object_dialog.c:331 msgid "Scan Date:" msgstr "" #. widgets to change the object's modality #: ../src/amitk_object_dialog.c:344 msgid "Modality:" msgstr "" #. widget to change the interpolation #: ../src/amitk_object_dialog.c:373 msgid "Interpolation Type" msgstr "" #. widgets to change the subject name associated with the data #: ../src/amitk_object_dialog.c:426 msgid "Subject Name:" msgstr "" #. widgets to change the id associated with the data #: ../src/amitk_object_dialog.c:440 msgid "Subject ID:" msgstr "" #. widgets to change the subject's date of birth #: ../src/amitk_object_dialog.c:453 msgid "Subject DOB:" msgstr "" #. widgets to change the subject's orientation #: ../src/amitk_object_dialog.c:467 msgid "Subject Orientation:" msgstr "" #. widget to change the scaling factor #: ../src/amitk_object_dialog.c:507 msgid "Conversion Type:" msgstr "" #: ../src/amitk_object_dialog.c:541 msgid "Scaling Factor:" msgstr "" #. injected dose #: ../src/amitk_object_dialog.c:568 msgid "Injected Dose:" msgstr "" #. subject weight #: ../src/amitk_object_dialog.c:613 msgid "Subject Weight:" msgstr "" #. cylinder factor #: ../src/amitk_object_dialog.c:658 msgid "Cylinder Factor:" msgstr "" #. widgets to change the study's creation date #: ../src/amitk_object_dialog.c:708 msgid "Creation Date:" msgstr "" #: ../src/amitk_object_dialog.c:748 msgid "View Center" msgstr "察看中心" #: ../src/amitk_object_dialog.c:757 msgid "View Center (mm from origin)" msgstr "" #: ../src/amitk_object_dialog.c:759 msgid "Center Location (mm from origin)" msgstr "" #: ../src/amitk_object_dialog.c:814 msgid "Voxel Size" msgstr "" #: ../src/amitk_object_dialog.c:818 msgid "Voxel Size (mm)" msgstr "" #: ../src/amitk_object_dialog.c:872 msgid "Dimensions" msgstr "尺寸" #. widgets to change the dimensions of the objects (in object's space) #: ../src/amitk_object_dialog.c:877 msgid "Dimensions (mm) wrt to ROI" msgstr "" #: ../src/amitk_object_dialog.c:922 msgid "Rotate" msgstr "旋转" #: ../src/amitk_object_dialog.c:937 msgid "Colormap/Threshold" msgstr "" #. start making the page to adjust time values #: ../src/amitk_object_dialog.c:954 msgid "Time" msgstr "时间" #. scan start time..... #: ../src/amitk_object_dialog.c:962 msgid "Scan Start Time (s)" msgstr "" #. frame duration(s).... #: ../src/amitk_object_dialog.c:988 ../src/tb_roi_analysis.c:95 msgid "Frame" msgstr "" #: ../src/amitk_object_dialog.c:993 ../src/tb_roi_analysis.c:96 msgid "Duration (s)" msgstr "" #: ../src/amitk_object_dialog.c:1052 ../src/ui_preferences_dialog.c:376 msgid "ROI/View Preferences" msgstr "" #. AMITK_IS_DATA_SET #: ../src/amitk_object_dialog.c:1054 msgid "Windowing Preferences" msgstr "" #: ../src/amitk_object_dialog.c:1139 msgid "Immutables" msgstr "不可变的" #: ../src/amitk_object_dialog.c:1145 msgid "Max-Min Voxel Dim" msgstr "" #: ../src/amitk_object_dialog.c:1161 msgid "Isocontour Min Specified Value" msgstr "" #: ../src/amitk_object_dialog.c:1174 msgid "Isocontour Max Specified Value" msgstr "" #: ../src/amitk_object_dialog.c:1215 msgid "Memory Used (GB):" msgstr "" #: ../src/amitk_object_dialog.c:1218 msgid "Memory Used (MB):" msgstr "" #: ../src/amitk_object_dialog.c:1221 msgid "Memory Used (KB):" msgstr "" #: ../src/amitk_object_dialog.c:1225 msgid "Memory Used (bytes):" msgstr "" #. widget to tell you the internal data format #: ../src/amitk_object_dialog.c:1244 msgid "Data Format:" msgstr "" #. widget to tell you the scaling format #: ../src/amitk_object_dialog.c:1267 msgid "Scale Format:" msgstr "" #. widgets to display the data set dimensions #: ../src/amitk_object_dialog.c:1290 msgid "Data Set Dimensions (voxels)" msgstr "" #: ../src/amitk_object_dialog.c:2404 #, c-format msgid "Modification Dialog: %s\n" msgstr "" #: ../src/amitk_point.c:90 #, c-format msgid "Couldn't read value for %s, substituting [%5.3f %5.3f %5.3f]" msgstr "" #: ../src/amitk_point.c:180 #, fuzzy, c-format msgid "Couldn't read value for %s, substituting [%d %d %d %d %d]" msgstr "无法读取 %1$s 的值,代定为%2$d" #: ../src/amitk_point.c:188 #, fuzzy, c-format msgid "Couldn't read gate value for %s, substituting %d" msgstr "无法读取 %1$s 的值,代定为%2$d" #: ../src/amitk_point.c:192 #, c-format msgid "Couldn't read frame value for %s, substituting %d" msgstr "" #: ../src/amitk_progress_dialog.c:165 msgid "Progress Dialog" msgstr "进度对话框" #: ../src/amitk_raw_data.c:51 ../src/amitk_raw_data.c:130 msgid "Unsigned Byte (8 bit)" msgstr "" #: ../src/amitk_raw_data.c:52 ../src/amitk_raw_data.c:131 msgid "Signed Byte (8 bit)" msgstr "" #: ../src/amitk_raw_data.c:53 msgid "Unsigned Short (16 bit)" msgstr "" #: ../src/amitk_raw_data.c:54 msgid "Signed Short (16 bit)" msgstr "" #: ../src/amitk_raw_data.c:55 msgid "Unsigned Integer (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:56 msgid "Signed Integer (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:57 msgid "Float (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:58 msgid "Double (64 bit)" msgstr "" #: ../src/amitk_raw_data.c:132 msgid "Unsigned Short, Little Endian (16 bit)" msgstr "" #: ../src/amitk_raw_data.c:133 msgid "Signed Short, Little Endian (16 bit)" msgstr "" #: ../src/amitk_raw_data.c:134 msgid "Unsigned Integer, Little Endian (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:135 msgid "Signed Integer, Little Endian (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:136 msgid "Float, Little Endian (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:137 msgid "Double, Little Endian (64 bit)" msgstr "" #: ../src/amitk_raw_data.c:138 msgid "Unsigned Short, Big Endian (16 bit)" msgstr "" #: ../src/amitk_raw_data.c:139 msgid "Signed Short, Big Endian (16 bit)" msgstr "" #: ../src/amitk_raw_data.c:140 msgid "Unsigned Integer, Big Endian (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:141 msgid "Signed Integer, Big Endian (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:142 msgid "Float, Big Endian (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:143 msgid "Double, Big Endian (64 bit)" msgstr "" #: ../src/amitk_raw_data.c:144 msgid "Unsigned Integer, PDP (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:145 msgid "Signed Integer, PDP (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:146 msgid "Float, PDP/VAX (32 bit)" msgstr "" #: ../src/amitk_raw_data.c:147 msgid "ASCII (8 bit)" msgstr "" #: ../src/amitk_raw_data.c:350 #, c-format msgid "Reading: %s" msgstr "" #: ../src/amitk_raw_data.c:359 #, fuzzy msgid "couldn't allocate memory space for the raw data set structure" msgstr "无法为时间数据分配空间" #: ../src/amitk_raw_data.c:367 ../src/amitk_raw_data.c:372 #, c-format msgid "couldn't open raw data file %s" msgstr "" #. EOF is usually -1 #: ../src/amitk_raw_data.c:385 #, c-format msgid "" "could not step forward %d elements in raw data file:\n" "\treturned error: %d" msgstr "" #: ../src/amitk_raw_data.c:391 #, c-format msgid "could not seek forward %ld bytes in raw data file" msgstr "" #: ../src/amitk_raw_data.c:400 #, fuzzy, c-format msgid "couldn't malloc %zd bytes for file buffer\n" msgstr "无法为时间数据分配空间" #: ../src/amitk_raw_data.c:423 #, c-format msgid "read wrong # of elements from raw data, expected %zd, got %zd" msgstr "" #. EOF = -1 (usually) #: ../src/amitk_raw_data.c:447 #, c-format msgid "" "could not read ascii file after %d elements, file or parameters are erroneous" msgstr "" #: ../src/amitk_raw_data.c:813 #, c-format msgid "couldn't save raw data file: %s" msgstr "" #: ../src/amitk_raw_data.c:841 #, c-format msgid "" "incomplete save of raw data, wrote %zd (bytes), needed %zd (bytes), file: %s" msgstr "" #: ../src/amitk_raw_data.c:915 #, c-format msgid "Raw data xml file doesn't appear to have a root: %s" msgstr "" #: ../src/amitk_raw_data.c:956 ../src/xml.c:672 ../src/xml.c:678 msgid "File to large to read on 32bit platform." msgstr "" #: ../src/amitk_roi.c:44 msgid "_Ellipsoid" msgstr "" #: ../src/amitk_roi.c:45 msgid "Elliptic _Cylinder" msgstr "" #: ../src/amitk_roi.c:46 msgid "_Box" msgstr "" #: ../src/amitk_roi.c:47 msgid "_2D Isocontour" msgstr "" #: ../src/amitk_roi.c:48 msgid "_3D Isocontour" msgstr "" #: ../src/amitk_roi.c:49 msgid "_2D Freehand" msgstr "" #: ../src/amitk_roi.c:50 msgid "_3D Freehand" msgstr "" #: ../src/amitk_roi.c:54 msgid "Add a new elliptical ROI" msgstr "" #: ../src/amitk_roi.c:55 msgid "Add a new elliptic cylinder ROI" msgstr "" #: ../src/amitk_roi.c:56 msgid "Add a new box shaped ROI" msgstr "" #: ../src/amitk_roi.c:57 msgid "Add a new 2D Isocontour ROI" msgstr "" #: ../src/amitk_roi.c:58 msgid "Add a new 3D Isocontour ROI" msgstr "" #: ../src/amitk_roi.c:59 #, fuzzy msgid "Add a new 2D Freehand ROI" msgstr "新增ROI文件" #: ../src/amitk_roi.c:60 #, fuzzy msgid "Add a new 3D Freehand ROI" msgstr "新增ROI文件" #: ../src/amitk_roi_variable_type.c:59 ../src/amitk_roi_variable_type.c:71 msgid "Out of Memory" msgstr "" #. and a display of the current axis #: ../src/amitk_space_edit.c:144 msgid "i" msgstr "" #: ../src/amitk_space_edit.c:147 msgid "j" msgstr "" #: ../src/amitk_space_edit.c:150 msgid "k" msgstr "" #: ../src/amitk_space_edit.c:185 msgid "data set axis:" msgstr "" #. button to apply entries #: ../src/amitk_space_edit.c:191 msgid "apply manual entries" msgstr "" #. button to reset the axis #: ../src/amitk_space_edit.c:199 msgid "reset to identity" msgstr "" #. our AIR buttons #: ../src/amitk_space_edit.c:215 #, fuzzy msgid "AIR Files:" msgstr "文件" #: ../src/amitk_space_edit.c:220 msgid "Apply .AIR" msgstr "" #: ../src/amitk_space_edit.c:227 #, fuzzy msgid "Export .AIR" msgstr "导出视图(_E)" #. first double check that we really want to do this #: ../src/amitk_space_edit.c:361 msgid "" "Do you really wish to manual set the axis?\n" "This may flip left/right relationships" msgstr "" #. first double check that we really want to do this #: ../src/amitk_space_edit.c:391 msgid "" "Do you really wish to reset the axis to identity?\n" "This may flip left/right relationships" msgstr "" #. first double check that we really want to do this #: ../src/amitk_space_edit.c:415 msgid "" "Do you really wish to invert?\n" "This will flip left/right relationships" msgstr "" #: ../src/amitk_study.c:42 msgid "blend all data sets" msgstr "" #: ../src/amitk_study.c:43 msgid "overlay active data set on blended data sets" msgstr "" #: ../src/amitk_study.c:47 msgid "single view" msgstr "" #: ../src/amitk_study.c:48 msgid "linked view, 2 way" msgstr "" #: ../src/amitk_study.c:49 msgid "linked view, 3 way" msgstr "" #: ../src/amitk_study.c:53 msgid "All objects are shown in a single view" msgstr "" #: ../src/amitk_study.c:54 msgid "Objects are shown between 2 linked views" msgstr "" #: ../src/amitk_study.c:55 msgid "Objects are shown between 3 linked views" msgstr "" #: ../src/amitk_study.c:489 #, c-format msgid "inappropriate zoom (%5.3f) for study, reseting to 1.0" msgstr "" #: ../src/amitk_study.c:924 ../src/amitk_study.c:1025 #: ../src/amitk_study.c:1157 #, fuzzy, c-format msgid "Couldn't open file %s\n" msgstr "不能转换文件名" #: ../src/amitk_study.c:985 msgid "The above warnings may arise because portions of the XIF" msgstr "" #: ../src/amitk_study.c:986 msgid "file were corrupted." msgstr "" #: ../src/amitk_study.c:1019 msgid "Couldn't change directories in loading study" msgstr "" #: ../src/amitk_study.c:1037 msgid "" "File is corrupt. The file may have been incompletely saved. You can " "attempt recovering the file by using the recover function under the file " "menu." msgstr "" #: ../src/amitk_study.c:1054 msgid "The above warnings most likely indicate changes to the" msgstr "" #: ../src/amitk_study.c:1055 msgid "XIF file format, please resave the data as soon as possible." msgstr "" #: ../src/amitk_study.c:1067 ../src/amitk_study.c:1171 msgid "Couldn't return to previous directory in load study" msgstr "" #: ../src/amitk_study.c:1107 ../src/amitk_study.c:1119 #, c-format msgid "Couldn't unlink file: %s" msgstr "" #: ../src/amitk_study.c:1113 #, c-format msgid "Couldn't remove directory: %s" msgstr "" #: ../src/amitk_study.c:1124 #, c-format msgid "Unrecognized file type for file: %s, couldn't delete" msgstr "" #: ../src/amitk_study.c:1138 #, c-format msgid "Couldn't create amide directory: %s" msgstr "" #: ../src/amitk_study.c:1152 msgid "Couldn't change directories in writing study, study not saved" msgstr "" #: ../src/amitk_threshold.c:49 msgid "per slice" msgstr "" #: ../src/amitk_threshold.c:50 msgid "per frame" msgstr "" #: ../src/amitk_threshold.c:51 msgid "interpolated between frames" msgstr "" #: ../src/amitk_threshold.c:52 msgid "global" msgstr "" #: ../src/amitk_threshold.c:56 msgid "" "threshold the images based on the max and min values in the current slice" msgstr "" #: ../src/amitk_threshold.c:57 msgid "" "threshold the images based on the max and min values in the current frame" msgstr "" #: ../src/amitk_threshold.c:58 msgid "" "threshold the images based on max and min values interpolated from the " "reference frame thresholds" msgstr "" #: ../src/amitk_threshold.c:59 msgid "" "threshold the images based on the max and min values of the entire data set" msgstr "" #: ../src/amitk_threshold.c:63 #, fuzzy msgid "Min/Max" msgstr "最小" #: ../src/amitk_threshold.c:64 #, fuzzy msgid "Center/Width" msgstr "中心" #: ../src/amitk_threshold.c:68 msgid "threshold by setting min and max values - Nuclear Medicine Style" msgstr "" #: ../src/amitk_threshold.c:69 msgid "theshold by setting a window center and width - Radiology Style" msgstr "" #: ../src/amitk_threshold.c:302 msgid "Percent" msgstr "" #: ../src/amitk_threshold.c:366 msgid "Color Table:" msgstr "" #: ../src/amitk_threshold.c:368 #, c-format msgid "Color Table %d:" msgstr "" #: ../src/amitk_threshold.c:388 msgid "enable color table" msgstr "" #: ../src/amitk_threshold.c:389 msgid "" "if not enabled, the primary color table will be used for this set of views" msgstr "" #. threshold type selection #: ../src/amitk_threshold.c:404 msgid "Threshold Type" msgstr "" #. threshold type selection #: ../src/amitk_threshold.c:447 ../src/ui_preferences_dialog.c:486 msgid "Threshold Style" msgstr "" #. color table selector #: ../src/amitk_threshold.c:506 msgid "ref. frame 0:" msgstr "" #. show/hide taken care of by threshold_update_layout #: ../src/amitk_threshold.c:511 msgid "ref. frame 1:" msgstr "" #: ../src/amitk_threshold.c:541 msgid "distribution" msgstr "" #: ../src/amitk_threshold.c:549 msgid "full" msgstr "" #. show/hide taken care of by threshold_update_layout #: ../src/amitk_threshold.c:555 msgid "scaled" msgstr "" #: ../src/amitk_threshold.c:766 msgid "Threshold has no style?\n" msgstr "" #: ../src/amitk_threshold.c:1309 msgid "Max Threshold" msgstr "" #: ../src/amitk_threshold.c:1310 msgid "Min Threshold" msgstr "" #: ../src/amitk_threshold.c:1367 msgid "Absolute" msgstr "" #. reset the title #: ../src/amitk_threshold.c:2182 ../src/amitk_threshold.c:2238 #, c-format msgid "Data Set: %s\n" msgstr "" #: ../src/amitk_threshold.c:2217 ../src/amitk_threshold.c:2358 msgid "Threshold Dialog" msgstr "" #: ../src/amitk_xif_sel.c:541 msgid "Filename" msgstr "文件名" #: ../src/amitk_xif_sel.c:542 msgid "The currently selected filename" msgstr "当前选中文件名" #: ../src/amitk_xif_sel.c:548 msgid "Show file operations" msgstr "显示文件操作" #: ../src/amitk_xif_sel.c:549 msgid "Whether buttons for creating/manipulating files should be displayed" msgstr "" #: ../src/amitk_xif_sel.c:556 msgid "Select multiple" msgstr "多选" #: ../src/amitk_xif_sel.c:557 msgid "Whether to allow multiple files to be selected" msgstr "" #: ../src/amitk_xif_sel.c:712 msgid "Folders" msgstr "目录" #: ../src/amitk_xif_sel.c:716 msgid "Fol_ders" msgstr "目录(_d)" #: ../src/amitk_xif_sel.c:748 #, fuzzy msgid "XIF Files" msgstr "文件" #: ../src/amitk_xif_sel.c:752 #, fuzzy msgid "XIF _Files" msgstr "文件(_F)" #: ../src/amitk_xif_sel.c:834 ../src/amitk_xif_sel.c:2237 #, c-format msgid "Folder unreadable: %s" msgstr "" #: ../src/amitk_xif_sel.c:936 #, c-format msgid "Error getting dropped filename: %s\n" msgstr "" #: ../src/amitk_xif_sel.c:965 #, c-format msgid "" "The file \"%s\" resides on another machine (called %s) and may not be " "available to this program.\n" "Are you sure that you want to select it?" msgstr "" #: ../src/amitk_xif_sel.c:1018 #, c-format msgid "Error getting filename: %s\n" msgstr "" #: ../src/amitk_xif_sel.c:1096 msgid "_New Folder" msgstr "创建目录(_N)" #: ../src/amitk_xif_sel.c:1106 msgid "De_lete File" msgstr "删除文件(_l)" #: ../src/amitk_xif_sel.c:1116 msgid "_Rename File" msgstr "重命名文件(_R)" #: ../src/amitk_xif_sel.c:1412 #, c-format msgid "" "The folder name \"%s\" contains symbols that are not allowed in filenames" msgstr "" #: ../src/amitk_xif_sel.c:1414 #, c-format msgid "" "Error creating folder \"%s\": %s\n" "%s" msgstr "" #: ../src/amitk_xif_sel.c:1415 ../src/amitk_xif_sel.c:1652 msgid "You probably used symbols not allowed in filenames." msgstr "" #: ../src/amitk_xif_sel.c:1423 #, c-format msgid "Error creating folder \"%s\": %s\n" msgstr "" #: ../src/amitk_xif_sel.c:1456 msgid "New Folder" msgstr "新目录" #: ../src/amitk_xif_sel.c:1471 msgid "_Folder name:" msgstr "目录名(_F)" #: ../src/amitk_xif_sel.c:1496 msgid "C_reate" msgstr "新建(_r)" #: ../src/amitk_xif_sel.c:1541 #, c-format msgid "The filename \"%s\" contains symbols that are not allowed in filenames" msgstr "" #: ../src/amitk_xif_sel.c:1544 #, c-format msgid "" "Error deleting file \"%s\": %s\n" "%s" msgstr "" #: ../src/amitk_xif_sel.c:1546 ../src/amitk_xif_sel.c:1666 msgid "It probably contains symbols not allowed in filenames." msgstr "" #: ../src/amitk_xif_sel.c:1555 #, c-format msgid "Error deleting file \"%s\": %s" msgstr "" #: ../src/amitk_xif_sel.c:1598 #, c-format msgid "Really delete file \"%s\" ?" msgstr "" #: ../src/amitk_xif_sel.c:1602 msgid "Delete File" msgstr "删除文件" #: ../src/amitk_xif_sel.c:1648 ../src/amitk_xif_sel.c:1662 #, c-format msgid "The file name \"%s\" contains symbols that are not allowed in filenames" msgstr "" #: ../src/amitk_xif_sel.c:1650 #, c-format msgid "" "Error renaming file to \"%s\": %s\n" "%s" msgstr "" #: ../src/amitk_xif_sel.c:1664 #, c-format msgid "" "Error renaming file \"%s\": %s\n" "%s" msgstr "" #: ../src/amitk_xif_sel.c:1674 #, c-format msgid "Error renaming file \"%s\" to \"%s\": %s" msgstr "" #: ../src/amitk_xif_sel.c:1720 msgid "Rename File" msgstr "重命名文件" #: ../src/amitk_xif_sel.c:1735 #, c-format msgid "Rename file \"%s\" to:" msgstr "" #: ../src/amitk_xif_sel.c:1765 msgid "_Rename" msgstr "" #: ../src/amitk_xif_sel.c:2217 msgid "_Selection: " msgstr "" #: ../src/amitk_xif_sel.c:3113 #, c-format msgid "" "The filename \"%s\" couldn't be converted to UTF-8 (try setting the " "environment variable G_BROKEN_FILENAMES): %s" msgstr "" #: ../src/amitk_xif_sel.c:3116 msgid "Invalid Utf-8" msgstr "无效的 UTF-8 字符" #: ../src/amitk_xif_sel.c:3991 msgid "Name too long" msgstr "名字太长" #: ../src/amitk_xif_sel.c:3993 msgid "Couldn't convert filename" msgstr "不能转换文件名" #: ../src/dcmtk_interface.cc:131 ../src/dcmtk_interface.cc:1299 #, c-format msgid "could not find dataset in DICOM file %s\n" msgstr "" #: ../src/dcmtk_interface.cc:141 #, c-format msgid "Modality %s is not understood. Ignoring File %s" msgstr "" #: ../src/dcmtk_interface.cc:172 #, c-format msgid "could not find # of columns - Failed to load file %s\n" msgstr "" #: ../src/dcmtk_interface.cc:178 #, c-format msgid "could not find # of rows - Failed to load file %s\n" msgstr "" #: ../src/dcmtk_interface.cc:208 #, c-format msgid "could not find # of bits allocated - Failed to load file %s\n" msgstr "" #: ../src/dcmtk_interface.cc:214 #, c-format msgid "could not find pixel representation - Failed to load file %s\n" msgstr "" #: ../src/dcmtk_interface.cc:233 #, c-format msgid "unsupported # of bits allocated (%d) - Failed to load file %s\n" msgstr "" #: ../src/dcmtk_interface.cc:240 #, c-format msgid "" "Couldn't allocate space for the data set structure to hold DCMTK data - " "Failed to load file %s" msgstr "" #: ../src/dcmtk_interface.cc:253 #, c-format msgid "Could not find the pixel size, setting to 1 mm for File %s" msgstr "" #: ../src/dcmtk_interface.cc:265 #, c-format msgid "Could not find the slice thickness, setting to 1 mm for File %s" msgstr "" #: ../src/dcmtk_interface.cc:498 #, c-format msgid "error reading in pixel data - DCMTK error: %s - Failed to read file" msgstr "" #: ../src/dcmtk_interface.cc:768 #, c-format msgid "" "Cannot evenly divide the number of slices by the number of frames for data " "set %s - ignoring dynamic data" msgstr "" #: ../src/dcmtk_interface.cc:777 #, c-format msgid "" "Cannot evenly divide the number of slices by the number of gates for data " "set %s - ignoring gated data" msgstr "" #: ../src/dcmtk_interface.cc:818 msgid "couldn't allocate space for the frame duration info" msgstr "" #: ../src/dcmtk_interface.cc:898 #, c-format msgid "" "Detected discontinous frames in data set %s - frame start times will be " "incorrect" msgstr "" #: ../src/dcmtk_interface.cc:901 #, c-format msgid "" "Slice thickness (%5.3f mm) not equal to slice spacing (%5.3f mm) in data set " "%s - will use slice spacing for thickness" msgstr "" #: ../src/dcmtk_interface.cc:1031 msgid "Importing File(s) Through DCMTK" msgstr "" #: ../src/dcmtk_interface.cc:1048 msgid "no support for multislice files within DICOM directory format" msgstr "" #: ../src/dcmtk_interface.cc:1306 msgid "Scanning Files to find additional DICOM Slices" msgstr "" #: ../src/dcmtk_interface.cc:1380 msgid "" "Multiple data sets were found in the same directory as the specified file. " "In addition to the dataset corresponding to the specified file, would you " "like to load in these additional datasets?" msgstr "" #: ../src/dcmtk_interface.cc:1577 msgid "" "Could not find a DICOM Data Dictionary. Reading may fail. Consider " "defining the environmental variable DCMDICTPATH to the dicom.dic file." msgstr "" #: ../src/dcmtk_interface.cc:1582 #, c-format msgid "could not read DICOM file %s, dcmtk returned %s" msgstr "" #: ../src/libecat_interface.c:35 msgid "Unknown Data Type" msgstr "" #. UnknownMatDataType #: ../src/libecat_interface.c:36 msgid "Byte" msgstr "" #. ByteData #: ../src/libecat_interface.c:37 msgid "Short (16 bit), Little Endian" msgstr "" #. VAX_Ix2 #: ../src/libecat_interface.c:38 msgid "Integer (32 bit), Little Endian" msgstr "" #. VAX_Ix4 #: ../src/libecat_interface.c:39 msgid "VAX Float (32 bit)" msgstr "" #. VAX_Rx4 #: ../src/libecat_interface.c:40 msgid "IEEE Float (32 bit)" msgstr "" #. IeeeFloat #: ../src/libecat_interface.c:41 msgid "Short (16 bit), Big Endian" msgstr "" #. SunShort #: ../src/libecat_interface.c:42 msgid "Integer (32 bit), Big Endian" msgstr "" #: ../src/libecat_interface.c:87 #, c-format msgid "Can't open file %s using libecat" msgstr "" #: ../src/libecat_interface.c:111 #, c-format msgid "Don't know how to handle this CTI file type: %d" msgstr "" #: ../src/libecat_interface.c:121 #, c-format msgid "Libecat can't get header info at matrix %x in file %s" msgstr "" #: ../src/libecat_interface.c:143 #, c-format msgid "No support for importing CTI files with data type of: %d (%s)" msgstr "" #: ../src/libecat_interface.c:175 #, fuzzy msgid "" "Couldn't allocate memory space for the data set structure to hold CTI data" msgstr "无法为时间数据分配空间" #. handle corrupted cti files #: ../src/libecat_interface.c:281 msgid "" "Detected corrupted CTI file, will try to continue by guessing voxel_size" msgstr "" #: ../src/libecat_interface.c:284 msgid "" "Detected zero voxel size in CTI file, will try to continue by guessing " "voxel_size" msgstr "" #. handle corrupted cti files #: ../src/libecat_interface.c:294 msgid "Detected corrupted CTI file, will try to continue by guessing offset" msgstr "" #: ../src/libecat_interface.c:323 #, c-format msgid "" "Importing CTI File:\n" " %s" msgstr "" #: ../src/libecat_interface.c:428 #, c-format msgid "" "Libecat returned %d blank planes... corrupted data file? Use data with " "caution." msgstr "" #: ../src/libmdc_interface.c:53 msgid "(_X)MedCon Guess" msgstr "" #: ../src/libmdc_interface.c:54 msgid "_GIF 87a/89a" msgstr "" #: ../src/libmdc_interface.c:55 msgid "Acr/_Nema 2.0" msgstr "" #: ../src/libmdc_interface.c:56 msgid "_Concorde/microPET" msgstr "" #: ../src/libmdc_interface.c:57 msgid "ECAT _6 via (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:58 msgid "ECAT _7 via (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:59 msgid "_InterFile 3.3" msgstr "" #: ../src/libmdc_interface.c:60 msgid "_Analyze (SPM)" msgstr "" #: ../src/libmdc_interface.c:61 msgid "_DICOM 3.0 via (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:62 msgid "_NIFTI via (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:66 msgid "let (X)MedCon/libmdc guess file type" msgstr "" #: ../src/libmdc_interface.c:67 msgid "Import a file stored as GIF" msgstr "" #: ../src/libmdc_interface.c:68 msgid "Import a Acr/Nema 2.0 file" msgstr "" #: ../src/libmdc_interface.c:69 msgid "Import a file from the Concorde microPET" msgstr "" #: ../src/libmdc_interface.c:70 msgid "Import a CTI/ECAT 6 file through (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:71 msgid "Import a CTI/ECAT 7 file through (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:72 msgid "Import a InterFile 3.3 file" msgstr "" #: ../src/libmdc_interface.c:73 msgid "Import an Analyze file" msgstr "" #: ../src/libmdc_interface.c:74 msgid "Import a DICOM 3.0 file through (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:75 msgid "Import a NIFTI file through (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:89 msgid "Acr/Nema 2.0" msgstr "" #: ../src/libmdc_interface.c:90 msgid "Concorde/microPET" msgstr "" #: ../src/libmdc_interface.c:91 msgid "ECAT 6 via (X)MedCon" msgstr "" #: ../src/libmdc_interface.c:92 msgid "InterFile 3.3" msgstr "" #: ../src/libmdc_interface.c:93 msgid "Analyze (SPM)" msgstr "" #: ../src/libmdc_interface.c:94 msgid "DICOM 3.0" msgstr "" #: ../src/libmdc_interface.c:95 msgid "NIFTI" msgstr "" #: ../src/libmdc_interface.c:99 msgid "Export a Acr/Nema 2.0 file" msgstr "" #: ../src/libmdc_interface.c:100 msgid "Export a Concorde format file" msgstr "" #: ../src/libmdc_interface.c:101 msgid "Export a CTI/ECAT 6 file" msgstr "" #: ../src/libmdc_interface.c:102 msgid "Export a InterFile 3.3 file" msgstr "" #: ../src/libmdc_interface.c:103 msgid "Export an Analyze file" msgstr "" #: ../src/libmdc_interface.c:104 msgid "Export a DICOM 3.0 file" msgstr "" #: ../src/libmdc_interface.c:105 #, fuzzy msgid "Export a NIFTI file" msgstr "导入文件" #: ../src/libmdc_interface.c:288 #, c-format msgid "Can't open file %s with libmdc/(X)MedCon" msgstr "" #: ../src/libmdc_interface.c:295 #, c-format msgid "Can't read file %s with libmdc/(X)MedCon" msgstr "" #. 9 #. 8 #. 11 #. 12 #. 13 #. 1 #: ../src/libmdc_interface.c:376 #, c-format msgid "" "Importing data type %d file through (X)MedCon unsupported in AMIDE, trying " "anyway" msgstr "" #: ../src/libmdc_interface.c:390 ../src/libmdc_interface.c:612 #, c-format msgid "Couldn't read plane %d in %s with libmdc/(X)MedCon" msgstr "" #: ../src/libmdc_interface.c:396 #, fuzzy, c-format msgid "libmdc returned error: %s" msgstr "SV 解码出错: %1$s " #: ../src/libmdc_interface.c:435 msgid "" "Couldn't allocate memory space for the data set structure to hold (X)MedCon " "data" msgstr "" #: ../src/libmdc_interface.c:561 msgid "" "(X)MedCon returned no duration information. Frame durations will be " "incorrect" msgstr "" #: ../src/libmdc_interface.c:570 #, c-format msgid "" "Importing File Through (X)MedCon:\n" " %s" msgstr "" #: ../src/libmdc_interface.c:742 msgid "(X)MedCon couldn't convert to a float... out of memory?" msgstr "" #: ../src/libmdc_interface.c:778 #, c-format msgid "" "(X)MedCon returned %d blank planes... corrupted data file? Use data with " "caution." msgstr "" #: ../src/libmdc_interface.c:890 #, c-format msgid "Unsupported export file format: %d\n" msgstr "" #: ../src/libmdc_interface.c:1041 #, c-format msgid "" "Exporting File Through (X)MedCon:\n" " %s" msgstr "" #: ../src/tb_export_data_set.c:111 #, fuzzy msgid "couldn't allocate memory space for tb_export_t" msgstr "无法为时间数据分配空间" #: ../src/tb_export_data_set.c:222 ../src/tb_export_data_set.c:381 msgid "No Data Sets are current visible" msgstr "" #. the rest of this function runs the file selection dialog box #: ../src/tb_export_data_set.c:253 ../src/ui_study_cb.c:507 #, fuzzy msgid "Export to File" msgstr "导入文件" #: ../src/tb_export_data_set.c:571 #, fuzzy, c-format msgid "%s: Export Data Set Dialog" msgstr "弹出数据集对话框" #: ../src/tb_export_data_set.c:592 #, fuzzy msgid "Exporting Data Sets" msgstr "裁减当前数据集(_C)" #: ../src/tb_export_data_set.c:599 #, fuzzy msgid "Export:" msgstr "导出视图(_E)" #. tooltip N_("Export the data set in its original orientation (unresliced)") #: ../src/tb_export_data_set.c:604 #, c-format msgid "Original Orientation - %s" msgstr "" #. tooltip N_("Export the data set in its current orientation (resliced)") #: ../src/tb_export_data_set.c:615 #, c-format msgid "Resliced Orientation - %s" msgstr "" #: ../src/tb_export_data_set.c:627 msgid "All Visible Data Sets (resliced)" msgstr "" #: ../src/tb_export_data_set.c:652 msgid "export format:" msgstr "" #. widgets to change the voxel size of the data set #: ../src/tb_export_data_set.c:717 msgid "voxel size (mm) [x,y,z]:" msgstr "" #. gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_buttons[0]),FALSE); #. gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_buttons[0]), FALSE); #. gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_buttons[0]), GTK_UPDATE_ALWAYS); #: ../src/tb_export_data_set.c:741 msgid "bounding box:" msgstr "" #: ../src/tb_math.c:36 msgid "" "There is only one data set in this study. There needs to be at least two " "data sets to perform mathematical operations" msgstr "" #: ../src/tb_math.c:40 msgid "" "Welcome to the data set math wizard, used for performaing mathematical " "operations between medical image data sets.\n" "\n" "Note - you will get more pleasing results if the data sets in question are " "set to trilinear interpolation mode." msgstr "" #: ../src/tb_math.c:207 msgid "" "A new data set will be created with the math operation, press Finish to " "calculate this data set, or Cancel to quit." msgstr "" #: ../src/tb_math.c:296 msgid "Math operation failed - results not added to study" msgstr "" #: ../src/tb_math.c:385 #, fuzzy msgid "couldn't allocate memory space for tb_math_t" msgstr "无法为时间数据分配空间" #: ../src/tb_math.c:472 msgid "Data Set 1:" msgstr "" #: ../src/tb_math.c:495 msgid "Data Set 2:" msgstr "" #: ../src/tb_math.c:511 #, fuzzy msgid "Operation Selection" msgstr "ROI深度选择" #: ../src/tb_math.c:529 msgid "Math Operation" msgstr "" #: ../src/tb_math.c:544 ../src/tb_alignment.c:667 msgid "Conclusion" msgstr "" #: ../src/tb_profile.c:218 #, fuzzy msgid "couldn't allocate memory space for tb_profile_t" msgstr "无法为时间数据分配空间" #: ../src/tb_profile.c:251 #, c-format msgid "# Profiles on Study: %s\tGenerated on: %s" msgstr "" #: ../src/tb_profile.c:256 #, c-format msgid "" "#\n" "# Profile on: %s\n" msgstr "" #: ../src/tb_profile.c:260 msgid "# Gaussian Fit: b + p * e^(-0.5*(x-c)^2/s^2)\n" msgstr "" #: ../src/tb_profile.c:261 #, c-format msgid "#\titerations used %d, status %s\n" msgstr "" #: ../src/tb_profile.c:264 ../src/tb_profile.c:269 ../src/tb_profile.c:835 #: ../src/tb_profile.c:838 msgid "(fixed)" msgstr "" #: ../src/tb_profile.c:280 msgid "# x\tvalue\n" msgstr "" #: ../src/tb_profile.c:328 #, fuzzy msgid "Export Profile" msgstr "导出视图(_E)" #: ../src/tb_profile.c:378 #, c-format msgid "couldn't open: %s for writing profiles" msgstr "" #. write out the gaussian equation #: ../src/tb_profile.c:790 msgid "fit = b + p * e^(-0.5*(x-c)^2/s^2)" msgstr "" #: ../src/tb_profile.c:824 #, c-format msgid "" "\n" "\n" "gaussian fit on: %s\n" "iterations used %d, status %s\n" "b = %.5g +/- %.5g %s\n" "p = %.5g +/- %.5g\n" "c = %.5g +/- %.5g mm %s\n" "s = %.5g +/- %.5g\n" "fwhm = %.5g +/- %.5g mm\n" "fwtm = %.5g +/- %.5g mm" msgstr "" #. start setting up the widget we'll display the info from #: ../src/tb_profile.c:1192 #, c-format msgid "%s Profile Tool: Study %s" msgstr "" #. which view do we want the profile on #: ../src/tb_profile.c:1226 msgid "Line Profile on:" msgstr "" #. changing the angle #: ../src/tb_profile.c:1257 msgid "Angle (degrees):" msgstr "" #: ../src/ui_gate_dialog.c:43 #, fuzzy msgid "Gate #" msgstr "帧 #" #: ../src/ui_gate_dialog.c:340 #, fuzzy, c-format msgid "%s: Gate Dialog" msgstr "%1$s:时间对话框" #: ../src/ui_gate_dialog.c:361 #, fuzzy msgid "Start Gate" msgstr "开始(秒)" #: ../src/ui_gate_dialog.c:378 msgid "End Gate" msgstr "" #: ../src/analysis.c:221 #, fuzzy, c-format msgid "couldn't allocate memory space for data array for frame %d/gate %d" msgstr "无法为时间数据分配空间" #: ../src/analysis.c:291 #, fuzzy, c-format msgid "couldn't allocate memory space for roi analysis of frame %d/gate %d" msgstr "无法为时间数据分配空间" #: ../src/analysis.c:426 #, fuzzy msgid "couldn't allocate memory space for roi analysis of frames" msgstr "无法为时间数据分配空间" #: ../src/analysis.c:457 #, c-format msgid "ROI: %s appears not to have been drawn" msgstr "" #: ../src/analysis.c:513 #, fuzzy msgid "couldn't allocate memory space for roi analysis of volumes" msgstr "无法为时间数据分配空间" #: ../src/analysis.c:585 #, fuzzy msgid "couldn't allocate memory space for roi analyses" msgstr "无法为时间数据分配空间" #. N_("Steepest Descent"), #: ../src/fads.c:40 msgid "Fletcher-Reeves conjugate gradient" msgstr "" #: ../src/fads.c:41 msgid "Polak-Ribiere conjugate gradient" msgstr "" #: ../src/fads.c:47 msgid "Principle Component Analysis" msgstr "" #: ../src/fads.c:48 msgid "Penalized Least Squares Factor Analysis" msgstr "" #: ../src/fads.c:49 msgid "2 compartment model" msgstr "" #: ../src/fads.c:53 msgid "Priniciple Component Analysis based on singular value decomposition." msgstr "" #: ../src/fads.c:56 msgid "" "Principle component analysis with positivity constraints and a penalized " "least squares objective, an adaptation of Sitek, et al., IEEE Trans. Med. " "Imag., 2002. If beta is set to zero, this is normal factor analysis, " "similar to Di Paola, et al., IEEE Trans. Nuc. Sci., 1982" msgstr "" #: ../src/fads.c:62 msgid "Standard 2 compartment model" msgstr "" #: ../src/fads.c:109 msgid "need dynamic data set in order to perform factor analysis" msgstr "" #: ../src/fads.c:115 ../src/fads.c:120 ../src/fads.c:271 #, c-format msgid "Failed to allocate %dx%d array" msgstr "" #: ../src/fads.c:125 ../src/fads.c:276 #, c-format msgid "Failed to allocate %d vector" msgstr "" #: ../src/fads.c:157 #, c-format msgid "Failed to allocate %d factor array" msgstr "" #: ../src/fads.c:266 #, c-format msgid "failed to alloc matrix, size %dx%d" msgstr "" #: ../src/fads.c:311 ../src/fads.c:338 #, c-format msgid "failed to alloc matrix size %dx%d" msgstr "" #: ../src/fads.c:325 #, c-format msgid "failed to alloc vector size %d" msgstr "" #: ../src/fads.c:400 ../src/fads.c:1209 ../src/fads.c:2180 msgid "failed to allocate new_ds" msgstr "" #: ../src/fads.c:431 #, c-format msgid "couldn't open: %s for writing PCA analyses" msgstr "" #: ../src/fads.c:943 msgid "failed forward error malloc" msgstr "" #: ../src/fads.c:950 msgid "failed weight malloc" msgstr "" #: ../src/fads.c:957 msgid "failed equality constraint alpha malloc" msgstr "" #: ../src/fads.c:963 msgid "failed equality constraint blood curve malloc" msgstr "" #: ../src/fads.c:969 ../src/fads.c:1940 msgid "failed malloc for equality lagrange multiplier - alpha" msgstr "" #: ../src/fads.c:977 ../src/fads.c:1948 msgid "failed malloc for equality lagrange multiplier - blood curve" msgstr "" #: ../src/fads.c:985 ../src/fads.c:1956 msgid "failed malloc for inequality lagrange multiplier - alpha" msgstr "" #: ../src/fads.c:994 msgid "failed malloc for inequailty lagrange multiplier - factors" msgstr "" #: ../src/fads.c:1011 ../src/fads.c:2003 msgid "failed to allocate multidimensional minimizer" msgstr "" #: ../src/fads.c:1082 #, c-format msgid "" "Calculating Penalized Least Squares Factor Analysis:\n" " %s" msgstr "" #: ../src/fads.c:1225 #, c-format msgid "factor %d" msgstr "" #: ../src/fads.c:1243 ../src/fads.c:2218 #, c-format msgid "couldn't open: %s for writing fads analyses" msgstr "" #: ../src/fads.c:1892 msgid "failed to allocate intermediate data storage for tissue components" msgstr "" #: ../src/fads.c:1898 msgid "failed to allocate intermediate data storage for forward error" msgstr "" #: ../src/fads.c:1904 msgid "failed to allocate frame start array" msgstr "" #: ../src/fads.c:1910 msgid "failed to allocate frame end array" msgstr "" #: ../src/fads.c:1916 msgid "failed to allocate frame midpt array" msgstr "" #: ../src/fads.c:1928 msgid "failed malloc for equality constraint on alpha" msgstr "" #: ../src/fads.c:1934 msgid "failed malloc for equality constraint on blood curve" msgstr "" #: ../src/fads.c:1964 msgid "failed malloc for inequailty lagrange multiplier - blood curve" msgstr "" #: ../src/fads.c:1972 msgid "failed malloc for inequailty lagrange multiplier - k12" msgstr "" #: ../src/fads.c:1980 msgid "failed malloc for inequailty lagrange multiplier - k21" msgstr "" #: ../src/fads.c:2011 msgid "failed to allocate initial vector" msgstr "" #: ../src/fads.c:2041 #, c-format msgid "" "Calculating Two Compartment Factor Analysis:\n" " %s" msgstr "" #: ../src/fads.c:2161 #, c-format msgid "Minimum found after %d iterations\n" msgstr "" #: ../src/fads.c:2163 msgid "terminated minization \n" msgstr "" #: ../src/fads.c:2165 #, c-format msgid "No minimum found after %d iterations, exited with: %s\n" msgstr "" #: ../src/fads.c:2199 #, c-format msgid "tissue type %d: k12 %g k21 %g" msgstr "" #: ../src/fads.c:2201 msgid "blood fraction" msgstr "" #: ../src/image.c:181 msgid "couldn't allocate memory for rgba_data for roi image" msgstr "" #: ../src/image.c:223 msgid "couldn't allocate memory for rgb_data for blank image" msgstr "" #: ../src/image.c:255 msgid "couldn't allocate memory for image from 8 bit data" msgstr "" #: ../src/image.c:304 msgid "" "couldn't allocate memory for rgba16_data for transferring rendering to image" msgstr "" #: ../src/image.c:381 msgid "couldn't allocate memory for char_data for rendering image" msgstr "" #: ../src/image.c:428 msgid "couldn't allocate memory for rgba_data for bar_graph" msgstr "" #: ../src/image.c:503 msgid "couldn't allocate memory for rgb_data for color_strip" msgstr "" #: ../src/image.c:558 msgid "couldn't allocate memory for rgba_data for projection image" msgstr "" #: ../src/image.c:609 msgid "couldn't allocate memory for rgba_data for slice image" msgstr "" #: ../src/mpeg_encode.c:109 #, fuzzy msgid "couldn't allocate memory space for context_t" msgstr "无法为时间数据分配空间" #: ../src/mpeg_encode.c:121 #, fuzzy msgid "couldn't allocate memory space for fame parameters" msgstr "无法为时间数据分配空间" #: ../src/mpeg_encode.c:128 msgid "Unable to allocate memory space for mpeg encoding buffer" msgstr "" #: ../src/mpeg_encode.c:135 msgid "Unable to allocate yuv struct" msgstr "" #: ../src/mpeg_encode.c:143 msgid "Unable to allocate yuv buffer" msgstr "" #: ../src/mpeg_encode.c:162 msgid "unable to open output file for mpeg encoding" msgstr "" #: ../src/raw_data_import.c:290 msgid "read offset (entries):" msgstr "" #: ../src/raw_data_import.c:293 msgid "read offset (bytes):" msgstr "" #: ../src/raw_data_import.c:307 msgid "total entries to read through:" msgstr "" #: ../src/raw_data_import.c:322 msgid "total bytes to read through:" msgstr "" #: ../src/raw_data_import.c:415 #, c-format msgid "%s: Raw Data Import Dialog\n" msgstr "" #. widgets to change the roi's name #: ../src/raw_data_import.c:429 msgid "name:" msgstr "" #. widgets to change the object's modality #: ../src/raw_data_import.c:467 msgid "modality:" msgstr "" #. widgets to change the raw data file's data format #: ../src/raw_data_import.c:509 msgid "data format:" msgstr "" #. how many bytes we can read from the file #: ../src/raw_data_import.c:550 msgid "file size (bytes):" msgstr "" #. labels for the x, y, and z components #: ../src/raw_data_import.c:597 ../src/ui_render.c:1007 msgid "x" msgstr "" #: ../src/raw_data_import.c:600 ../src/ui_render.c:981 msgid "y" msgstr "" #: ../src/raw_data_import.c:603 ../src/ui_render.c:989 msgid "z" msgstr "" #: ../src/raw_data_import.c:606 msgid "gates" msgstr "" #: ../src/raw_data_import.c:609 msgid "frames" msgstr "" #. widgets to change the dimensions of the data set #: ../src/raw_data_import.c:616 msgid "dimensions (# voxels)" msgstr "" #. widgets to change the voxel size of the data set #: ../src/raw_data_import.c:637 msgid "voxel size (mm)" msgstr "" #. scale factor to apply to the data #: ../src/raw_data_import.c:660 msgid "scale factor" msgstr "" #: ../src/raw_data_import.c:697 #, fuzzy msgid "" "Couldn't allocate memory space for raw_data_info structure for raw data " "import" msgstr "无法为时间数据分配空间" #: ../src/raw_data_import.c:709 #, c-format msgid "Couldn't get stat's on file %s for raw data import" msgstr "" #: ../src/render.c:46 msgid "Highest Quality and Slowest" msgstr "" #: ../src/render.c:47 msgid "High Quality and Medium Speed" msgstr "" #: ../src/render.c:48 msgid "Medium Quality and Fast" msgstr "" #: ../src/render.c:49 msgid "Low Quality and Fastest" msgstr "" #: ../src/render.c:52 msgid "Opacity" msgstr "" #: ../src/render.c:53 msgid "Grayscale" msgstr "" #: ../src/render.c:150 #, fuzzy msgid "couldn't allocate memory space for rendering context" msgstr "无法为时间数据分配空间" #: ../src/render.c:201 msgid "" "\"Per Slice\" thresholding illogical for conversion to volume rendering, " "using \"Global\" thresholding " msgstr "" #: ../src/render.c:214 #, fuzzy msgid "couldn't allocate memory space for density ramp x" msgstr "无法为时间数据分配空间" #: ../src/render.c:219 #, fuzzy msgid "couldn't allocate memory space for density ramp y" msgstr "无法为时间数据分配空间" #: ../src/render.c:230 #, fuzzy msgid "couldn't allocate memory space for gradient ramp x" msgstr "无法为时间数据分配空间" #: ../src/render.c:235 #, fuzzy msgid "couldn't allocate memory space for gradient ramp y" msgstr "无法为时间数据分配空间" #: ../src/render.c:254 msgid "Error Setting the Rendering Density Ramp" msgstr "" #: ../src/render.c:264 msgid "Error Setting the Rendering Gradient Ramp" msgstr "" #: ../src/render.c:272 #, c-format msgid "Error Setting the Rendering Voxel Size (%s): %s" msgstr "" #: ../src/render.c:282 #, c-format msgid "Error Specifying the Rendering Voxel Fields (%s, NORMAL): %s" msgstr "" #: ../src/render.c:289 #, c-format msgid "Error Specifying the Rendering Voxel Fields (%s, DENSITY): %s" msgstr "" #: ../src/render.c:297 #, c-format msgid "Error Specifying the Rendering Voxel Fields (%s, GRADIENT): %s" msgstr "" #: ../src/render.c:307 #, c-format msgid "Error Setting the Rendering Classifier Table (%s, DENSITY): %s" msgstr "" #: ../src/render.c:317 #, c-format msgid "Error Setting the Classifier Table (%s, GRADIENT): %s" msgstr "" #: ../src/render.c:415 #, c-format msgid "Error Setting the Context Size (%s): %s" msgstr "" #: ../src/render.c:428 #, fuzzy, c-format msgid "Could not allocate memory space for density data for %s" msgstr "无法为时间数据分配空间" #: ../src/render.c:440 #, c-format msgid "Could not allocate memory space for rendering context volume for %s" msgstr "" #: ../src/render.c:452 #, c-format msgid "Converting for rendering: %s" msgstr "" #: ../src/render.c:654 #, c-format msgid "Error Computing the Rendering Normals (%s): %s" msgstr "" #: ../src/render.c:682 #, c-format msgid "Error Setting Rendering Octree Threshold (%s, DENSITY): %s" msgstr "" #: ../src/render.c:688 #, c-format msgid "Error Setting Rendering Octree Threshold (%s, GRADIENT): %s" msgstr "" #: ../src/render.c:695 #, c-format msgid "Error Generating Octree (%s): %s" msgstr "" #: ../src/render.c:722 #, c-format msgid "Error Setting the Rendering Material (%s, SHINYNESS): %s" msgstr "" #: ../src/render.c:732 #, c-format msgid "Error Setting the Rendering Shader (%s): %s" msgstr "" #: ../src/render.c:740 #, c-format msgid "Error Shading Table for Rendering (%s): %s" msgstr "" #: ../src/render.c:775 #, c-format msgid "Error Setting The Item To Rotate (%s): %s" msgstr "" #: ../src/render.c:780 #, c-format msgid "Error Rotating Rendering (%s): %s" msgstr "" #: ../src/render.c:858 #, c-format msgid "Error Setting Rendering Max Ray Opacity (%s): %s" msgstr "" #: ../src/render.c:864 #, c-format msgid "Error Setting the Min Voxel Opacity (%s): %s" msgstr "" #: ../src/render.c:893 #, fuzzy, c-format msgid "Could not allocate memory space for Rendering Image for %s" msgstr "无法为时间数据分配空间" #: ../src/render.c:901 #, c-format msgid "Error Switching the Rendering Image Pixel Return Type (%s): %s" msgstr "" #: ../src/render.c:913 #, c-format msgid "Error Setting the Rendering Depth Cue (%s): %s" msgstr "" #: ../src/render.c:930 #, c-format msgid "Error Enabling Rendering Depth Cueing (%s): %s" msgstr "" #: ../src/render.c:960 #, c-format msgid "Error Classifying the Volume (%s): %s" msgstr "" #: ../src/render.c:966 #, c-format msgid "Error Rendering the Classified Volume (%s): %s" msgstr "" #: ../src/render.c:972 #, c-format msgid "Error Rendering the Volume (%s): %s" msgstr "" #: ../src/tb_alignment.c:39 msgid "" "There is only one data set in this study. There needs to be at least two " "data sets to perform an alignment" msgstr "" #: ../src/tb_alignment.c:43 msgid "" "In order to perform an alignment, each data set musthave at least three " "objects with the same name asthe corresponding three objects in the other " "data set\n" "Please see the help documentation for a longerexplanation as to how " "alignments can be done." msgstr "" #: ../src/tb_alignment.c:51 msgid "" "Welcome to the data set alignment wizard, used for aligning one medical " "image data set with another. \n" "Currently, only registration using fiducial marks has been implemented " "inside of AMIDE." msgstr "" #: ../src/tb_alignment.c:294 #, c-format msgid "" "The alignment has been calculated, press Finish to apply, or Cancel to " "quit.\n" "\n" "The calculated fiducial reference error is: %5.5f mm/point" msgstr "" #: ../src/tb_alignment.c:502 #, fuzzy msgid "couldn't allocate memory space for tb_alignment_t" msgstr "无法为时间数据分配空间" #: ../src/tb_alignment.c:589 msgid "Align Data Set: (moving)" msgstr "" #: ../src/tb_alignment.c:612 msgid "Align Data Set: (fixed)" msgstr "" #: ../src/tb_alignment.c:628 msgid "Fiducial Marks Selection" msgstr "" #: ../src/tb_alignment.c:654 msgid "Points for Alignment" msgstr "" #: ../src/tb_alignment.c:680 msgid "Alignment Error" msgstr "" #: ../src/tb_crop.c:41 msgid "Data Set Cropping Wizard" msgstr "" #: ../src/tb_crop.c:44 msgid "" "When the apply button is hit, a new data set will be created\n" "and placed into the study's tree, consisting of the appropriately\n" "cropped data\n" msgstr "" #. the zoom selection #: ../src/tb_crop.c:185 msgid "zoom" msgstr "" #: ../src/tb_crop.c:206 #, fuzzy msgid "gate" msgstr "旋转" #: ../src/tb_crop.c:227 msgid "frame" msgstr "" #: ../src/tb_crop.c:283 #, c-format msgid "%s range:" msgstr "" #: ../src/tb_crop.c:311 msgid "(mm)" msgstr "" #. widget to tell you the internal data format #: ../src/tb_crop.c:376 msgid "Current Data Format:" msgstr "" #. widget to tell you the scaling format #: ../src/tb_crop.c:389 msgid "Current Scale Format:" msgstr "" #. widget to tell you the internal data format #: ../src/tb_crop.c:408 msgid "Output Data Format:" msgstr "" #. widget to tell you the scaling format #: ../src/tb_crop.c:437 msgid "Output Scale Format:" msgstr "" #: ../src/tb_crop.c:1081 #, fuzzy msgid "couldn't allocate memory space for tb_crop_t" msgstr "无法为时间数据分配空间" #: ../src/tb_crop.c:1125 ../src/tb_filter.c:539 ../src/ui_study_cb.c:55 msgid "No data set is currently marked as active" msgstr "" #: ../src/tb_fads.c:41 msgid "Factor Analysis Wizard" msgstr "" #: ../src/tb_fads.c:46 msgid "" "This page allows the computation of the singular value decomposition for the " "data set in question. These values can give you an idea of how many " "important factors the data set has.\n" "\n" "This process can be extremely slow, so skip this page if you already know " "the answer." msgstr "" #: ../src/tb_fads.c:54 msgid "" "When the apply button is hit, the appropriate factor analysis data " "structures will be created, and placed underneath the given data set in the " "study tree\n" msgstr "" #: ../src/tb_fads.c:59 msgid "" "Welcome to the factor analysis of dynamic structures wizard.\n" "None of this code has been validated, and it's probably wrong,so use at your " "own risk" msgstr "" #: ../src/tb_fads.c:66 msgid "" "Welcome to the factor analysis of dynamic structures wizard.\n" "This wizard only works with dynamic studies" msgstr "" #: ../src/tb_fads.c:154 #, c-format msgid "" "%s\n" "Method Picked: %s" msgstr "" #: ../src/tb_fads.c:188 msgid "Filename for Factor Data" msgstr "" #. do I need to compute factors? #: ../src/tb_fads.c:277 msgid "Compute Singular Values?" msgstr "" #. ask for the fads method to use #: ../src/tb_fads.c:313 msgid "FADS Method:" msgstr "" #. ask for the minimizer algorithm to use #: ../src/tb_fads.c:367 msgid "Minimization Algorithm:" msgstr "" #. max # of iterations #: ../src/tb_fads.c:398 msgid "Max. # of iterations:" msgstr "" #. stopping criteria #: ../src/tb_fads.c:413 msgid "Stopping Criteria:" msgstr "" #. stopping criteria #: ../src/tb_fads.c:430 msgid "Beta:" msgstr "" #. how many factors to solve for? #: ../src/tb_fads.c:445 msgid "# of Factors to use" msgstr "" #. k12 criteria #: ../src/tb_fads.c:462 msgid "initial k12 (1/s):" msgstr "" #. k21 criteria #: ../src/tb_fads.c:479 msgid "initial K21 (1/s):" msgstr "" #. A table to add blood sample measurements #: ../src/tb_fads.c:504 msgid "Add Blood Sample" msgstr "" #: ../src/tb_fads.c:544 msgid "Remove Blood Sample" msgstr "" #: ../src/tb_fads.c:794 msgid "failed malloc for frames array" msgstr "" #: ../src/tb_fads.c:799 msgid "failed malloc for vals array" msgstr "" #: ../src/tb_fads.c:935 #, fuzzy msgid "couldn't allocate memory space for tb_fads_t" msgstr "无法为时间数据分配空间" #. mm #. mm #: ../src/tb_filter.c:46 msgid "Data Set Filtering Wizard" msgstr "" #: ../src/tb_filter.c:49 msgid "" "When the apply button is hit, a new data set will be created and placed into " "the study's tree, consisting of the appropriately filtered data\n" msgstr "" #: ../src/tb_filter.c:55 msgid "The Gaussian filter is an effective smoothing filter" msgstr "" #: ../src/tb_filter.c:60 msgid "" "Median filter work relatively well at preserving edges while\n" "removing speckle noise.\n" "\n" "This filter is the 3D median filter, so the neighborhood used for\n" "determining the median will be KSxKSxKS, KS=kernel size" msgstr "" #: ../src/tb_filter.c:67 msgid "" "Median filters work relatively well at preserving edges while\n" "removing speckle noise.\n" "\n" "This filter is the 1D median filter, so the neighboorhood used for\n" "determining the median will be of the given kernel size, and the\n" "data set will be filtered 3x (once for each direction)." msgstr "" #: ../src/tb_filter.c:76 msgid "" "This filter requires support from the GNU Scientific Library (GSL).\n" "This version of AMIDE has not be compiled with GSL support enabled." msgstr "" #: ../src/tb_filter.c:211 msgid "Which Filter" msgstr "" #. the kernel selection #: ../src/tb_filter.c:258 ../src/tb_filter.c:314 msgid "Kernel Size" msgstr "" #: ../src/tb_filter.c:275 msgid "FWHM (mm)" msgstr "" #: ../src/tb_filter.c:513 #, fuzzy msgid "couldn't allocate memory space for tb_filter_t" msgstr "无法为时间数据分配空间" #. the rest of this function runs the file selection dialog box #: ../src/tb_fly_through.c:329 ../src/ui_render_movie.c:258 msgid "Output MPEG As" msgstr "" #: ../src/tb_fly_through.c:498 #, c-format msgid "encoding of frame %d failed" msgstr "" #: ../src/tb_fly_through.c:644 #, fuzzy msgid "couldn't allocate memory space for tb_fly_through_t" msgstr "无法为时间数据分配空间" #: ../src/tb_fly_through.c:705 msgid "Fly Through Generation" msgstr "" #: ../src/tb_fly_through.c:727 msgid "Current Position (mm):" msgstr "" #: ../src/tb_fly_through.c:737 msgid "Start Position (mm):" msgstr "" #: ../src/tb_fly_through.c:752 msgid "End Position (mm):" msgstr "" #: ../src/tb_fly_through.c:767 msgid "Movie Duration (sec):" msgstr "" #: ../src/tb_fly_through.c:785 msgid "Fly through movie generation" msgstr "" #: ../src/tb_fly_through.c:796 msgid "Set Start Position" msgstr "" #: ../src/tb_fly_through.c:801 msgid "Set End Position" msgstr "" #. do we want to make a movie over time or over frames #: ../src/tb_fly_through.c:859 ../src/ui_render_movie.c:722 msgid "Dynamic Movie:" msgstr "" #. the radio buttons #: ../src/tb_fly_through.c:870 ../src/ui_render_movie.c:733 msgid "No" msgstr "" #: ../src/tb_fly_through.c:877 ../src/ui_render_movie.c:738 msgid "over time" msgstr "" #: ../src/tb_fly_through.c:881 ../src/ui_render_movie.c:742 msgid "over frames" msgstr "" #: ../src/tb_fly_through.c:893 ../src/ui_render_movie.c:752 msgid "over frames smoothed" msgstr "" #: ../src/tb_fly_through.c:899 ../src/ui_render_movie.c:756 msgid "over gates" msgstr "" #. widgets to specify the start and end times #: ../src/tb_fly_through.c:919 ../src/ui_render_movie.c:768 msgid "Start Time (s)" msgstr "" #: ../src/tb_fly_through.c:922 ../src/ui_render_movie.c:771 msgid "Start Frame" msgstr "" #: ../src/tb_fly_through.c:949 ../src/ui_render_movie.c:798 msgid "End Time (s)" msgstr "" #: ../src/tb_fly_through.c:952 ../src/ui_render_movie.c:801 msgid "End Frame" msgstr "" #: ../src/tb_fly_through.c:980 ../src/ui_render_movie.c:830 msgid "Display time on image" msgstr "" #: ../src/tb_roi_analysis.c:93 msgid "ROI" msgstr "" #: ../src/tb_roi_analysis.c:94 ../src/ui_time_dialog.c:62 msgid "Data Set" msgstr "" #: ../src/tb_roi_analysis.c:97 #, fuzzy msgid "Midpt (s)" msgstr "结束(秒)" #: ../src/tb_roi_analysis.c:98 #, fuzzy msgid "Gate" msgstr "旋转" #. N_("Total"), #: ../src/tb_roi_analysis.c:100 msgid "Median" msgstr "" #: ../src/tb_roi_analysis.c:101 msgid "Mean" msgstr "" #: ../src/tb_roi_analysis.c:102 msgid "Var" msgstr "" #: ../src/tb_roi_analysis.c:103 msgid "Std Dev" msgstr "" #: ../src/tb_roi_analysis.c:106 msgid "Size (mm^3)" msgstr "" #: ../src/tb_roi_analysis.c:107 msgid "Frac. Voxels" msgstr "" #: ../src/tb_roi_analysis.c:108 msgid "Voxels" msgstr "" #: ../src/tb_roi_analysis.c:169 msgid "Export Statistics" msgstr "" #: ../src/tb_roi_analysis.c:171 msgid "Export ROI Raw Data Values" msgstr "" #: ../src/tb_roi_analysis.c:176 msgid "roi_raw_data" msgstr "" #: ../src/tb_roi_analysis.c:176 #, fuzzy msgid "analysis" msgstr "要素分析(_F)" #: ../src/tb_roi_analysis.c:235 #, fuzzy, c-format msgid "couldn't open: %s for writing roi data" msgstr "无法为时间数据分配空间" #: ../src/tb_roi_analysis.c:241 #, c-format msgid "# %s: ROI Analysis File - generated on %s" msgstr "" #: ../src/tb_roi_analysis.c:243 #, c-format msgid "# Study:\t%s\n" msgstr "" #: ../src/tb_roi_analysis.c:247 #, c-format msgid "# ROI:\t%s\tType:\t%s" msgstr "" #: ../src/tb_roi_analysis.c:252 #, c-format msgid "\tIsocontour Above Value:\t%g" msgstr "" #: ../src/tb_roi_analysis.c:254 #, c-format msgid "\tIsocontour Below Value:\t%g" msgstr "" #. AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX #: ../src/tb_roi_analysis.c:256 #, c-format msgid "\tIsocontour Between Values:\t%g %g" msgstr "" #: ../src/tb_roi_analysis.c:265 #, c-format msgid "# Calculation done with all voxels in ROI\n" msgstr "" #: ../src/tb_roi_analysis.c:268 #, c-format msgid "# Calculation done on %5.3f percentile of voxels in ROI\n" msgstr "" #: ../src/tb_roi_analysis.c:271 #, c-format msgid "" "# Calculation done on voxels >= %5.3f percent of maximum value in ROI\n" msgstr "" #: ../src/tb_roi_analysis.c:274 #, c-format msgid "# Calculation done on voxels >= %g in ROI\n" msgstr "" #: ../src/tb_roi_analysis.c:286 #, c-format msgid "# Data Set:\t%s\tScaling Factor:\t%g\n" msgstr "" #: ../src/tb_roi_analysis.c:293 #, c-format msgid "# Output Data Units: %s\n" msgstr "" #: ../src/tb_roi_analysis.c:295 #, c-format msgid "# Injected Dose: %g [%s]\n" msgstr "" #: ../src/tb_roi_analysis.c:299 #, c-format msgid "# Cylinder Factor: %g [%s]\n" msgstr "" #: ../src/tb_roi_analysis.c:310 #, c-format msgid "# Subject Weight: %g [%s]\n" msgstr "" #: ../src/tb_roi_analysis.c:397 #, c-format msgid "# Stats for Study: %s\tGenerated on: %s" msgstr "" #: ../src/tb_roi_analysis.c:574 msgid "ROI Statistics" msgstr "" #. tell us the type #: ../src/tb_roi_analysis.c:586 msgid "type:" msgstr "" #: ../src/tb_roi_analysis.c:790 msgid "No Data Sets selected for calculating analyses" msgstr "" #: ../src/tb_roi_analysis.c:802 msgid "No ROI's selected for calculating analyses" msgstr "" #. start setting up the widget we'll display the info from #: ../src/tb_roi_analysis.c:816 #, c-format msgid "%s Roi Analysis: Study %s" msgstr "" #: ../src/tb_roi_analysis.c:1004 #, c-format msgid "%s: ROI Analysis Initialization Dialog" msgstr "" #: ../src/tb_roi_analysis.c:1023 msgid "Calculate:" msgstr "" #: ../src/tb_roi_analysis.c:1026 msgid "All ROIS:" msgstr "" #: ../src/tb_roi_analysis.c:1029 msgid "Selected ROIS:" msgstr "" #: ../src/tb_roi_analysis.c:1034 msgid "On All Data Sets:" msgstr "" #: ../src/tb_roi_analysis.c:1052 msgid "On Selected Data Sets:" msgstr "" #. do we want to calculate over a subfraction #: ../src/tb_roi_analysis.c:1091 msgid "Calculate over all voxels (normal):" msgstr "" #. do we want to calculate over a subfraction #: ../src/tb_roi_analysis.c:1102 #, c-format msgid "Calculate over % highest voxels:" msgstr "" #. do we want to calculate over a percentage of max #: ../src/tb_roi_analysis.c:1126 #, c-format msgid "Calculate for voxels >= % of Max:" msgstr "" #. do we want to calculate over a percentage of max #: ../src/tb_roi_analysis.c:1150 msgid "Calculate for voxels >= Value:" msgstr "" #. do we want more accurate quantitation #: ../src/tb_roi_analysis.c:1190 msgid "More Accurate Quantitation (Slow)" msgstr "" #: ../src/ui_common.c:87 msgid "Solid" msgstr "" #: ../src/ui_common.c:88 msgid "On/Off" msgstr "" #: ../src/ui_common.c:89 msgid "Double Dash" msgstr "" #: ../src/ui_common.c:122 ../src/ui_common.c:200 #, c-format msgid "Inappropriate filename: %s" msgstr "" #: ../src/ui_common.c:137 #, c-format msgid "Overwrite file: %s" msgstr "" #: ../src/ui_common.c:303 msgid "AMIDE's a Medical Image Data Examiner\n" msgstr "" #: ../src/ui_common.c:305 msgid "Email bug reports to: " msgstr "" #: ../src/ui_common.c:308 msgid "Compiled with support for the following libraries:\n" msgstr "" #: ../src/ui_common.c:311 msgid "libecat: CTI File library by Merence Sibomona\n" msgstr "" #: ../src/ui_common.c:314 msgid "libgsl: GNU Scientific Library by the GSL Team (version " msgstr "" #: ../src/ui_common.c:317 msgid "libmdc: Medical Imaging File library by Erik Nolf (version " msgstr "" #: ../src/ui_common.c:320 msgid "" "libdcmdata: OFFIS DICOM Toolkit DCMTK (C) 1993-2004, OFFIS e.V. (version " msgstr "" #: ../src/ui_common.c:323 msgid "libvolpack: Volume Rendering library by Philippe Lacroute (version " msgstr "" #: ../src/ui_common.c:326 msgid "libfame: Fast Assembly Mpeg Encoding library by the FAME Team (version " msgstr "" #: ../src/ui_common.c:332 msgid "Copyright (c) 2000-2007 Andy Loening" msgstr "" #. widgets to change the roi's size #: ../src/ui_common.c:541 msgid "ROI Width (pixels)" msgstr "" #. widgets to change the roi's line style #. Anti-aliased canvas doesn't yet support this #. also need to remove #ifndef for relevant lines in amitk_canvas_object.c #: ../src/ui_common.c:598 msgid "ROI Line Style:" msgstr "" #. do we want to fill in isocontour roi's #: ../src/ui_common.c:629 msgid "Draw Isocontours/Freehands Filled:" msgstr "" #: ../src/ui_common.c:649 msgid "Canvas Layout:" msgstr "" #: ../src/ui_common.c:684 msgid "Multiple Canvases Layout:" msgstr "" #. do we want the size of the canvas to not resize #: ../src/ui_common.c:735 msgid "Maintain view size constant:" msgstr "" #. widgets to change the amount of empty space in the center of the target #: ../src/ui_common.c:748 msgid "Target Empty Area (pixels)" msgstr "" #: ../src/ui_common.c:952 msgid "Request Dialog" msgstr "" #: ../src/ui_preferences_dialog.c:42 msgid "" "These preferences are used only for new studies. \n" "Use the study modification dialog to change these \n" "parameters for the current study." msgstr "" #: ../src/ui_preferences_dialog.c:47 msgid "" "These preferences are used only for new data sets. \n" "Use the data set modification dialog to change these \n" "parameters for the current data set." msgstr "" #: ../src/ui_preferences_dialog.c:349 #, c-format msgid "%s: Preferences Dialog" msgstr "" #: ../src/ui_preferences_dialog.c:465 msgid "Thresholding" msgstr "" #: ../src/ui_preferences_dialog.c:529 msgid "Default Color Tables" msgstr "" #. color table selector #: ../src/ui_preferences_dialog.c:536 #, c-format msgid "default %s color table:" msgstr "" #: ../src/ui_preferences_dialog.c:573 msgid "Miscellaneous" msgstr "" #: ../src/ui_preferences_dialog.c:577 msgid "Send Warning Messages to Console:" msgstr "" #: ../src/ui_preferences_dialog.c:593 msgid "Don't Prompt for \"Save Changes\" on Exit:" msgstr "" #: ../src/ui_preferences_dialog.c:608 msgid "Save .XIF file as directory:" msgstr "" #: ../src/ui_preferences_dialog.c:624 msgid "Default Directory on Startup:" msgstr "" #: ../src/ui_render.c:386 ../src/ui_render_movie.c:546 #: ../src/ui_study_cb.c:448 msgid "Canvas failed to return a valid image\n" msgstr "" #: ../src/ui_render.c:392 ../src/ui_series.c:206 ../src/ui_study_cb.c:250 #: ../src/ui_study_cb.c:458 #, c-format msgid "Failure Saving File: %s" msgstr "" #: ../src/ui_render.c:415 ../src/ui_series.c:228 msgid "Export File" msgstr "" #: ../src/ui_render.c:519 msgid "_Export Rendering" msgstr "" #: ../src/ui_render.c:520 msgid "Export the rendered image" msgstr "" #: ../src/ui_render.c:524 msgid "_Create Movie" msgstr "" #: ../src/ui_render.c:525 msgid "Create a movie out of a sequence of renderings" msgstr "" #: ../src/ui_render.c:535 msgid "_Rendering Parameters" msgstr "" #: ../src/ui_render.c:536 msgid "Adjust parameters pertinent to the rendered image" msgstr "" #: ../src/ui_render.c:569 msgid "Monoscopic rendering" msgstr "" #: ../src/ui_render.c:571 msgid "Stereoscopic rendering" msgstr "" #: ../src/ui_render.c:577 msgid "Opacity and density transfer functions" msgstr "" #. add the zoom widget to our toolbar #: ../src/ui_render.c:597 ../src/ui_study_menus.c:520 msgid "zoom:" msgstr "" #: ../src/ui_render.c:610 msgid "specify how much to magnify the rendering" msgstr "" #: ../src/ui_render.c:705 #, fuzzy msgid "couldn't allocate memory space for ui_render_t" msgstr "无法为时间数据分配空间" #: ../src/ui_render.c:928 msgid "Rendering Window" msgstr "" #. button to reset the axis #: ../src/ui_render.c:1018 msgid "Reset Axis" msgstr "" #: ../src/ui_render.c:1107 #, c-format msgid "%s: Rendering Initialization Dialog" msgstr "" #. do we want to strip values #: ../src/ui_render.c:1142 msgid "Set values greater than max. threshold to zero?" msgstr "" #. do we want to converse memory #: ../src/ui_render.c:1150 msgid "Accelerate Rendering? Increases memory use ~3x" msgstr "" #. do we want the initial opacities to be only density dependent #: ../src/ui_render.c:1158 msgid "Initial opacity functions only density dependent?" msgstr "" #: ../src/ui_render_dialog.c:350 #, fuzzy msgid "couldn't allocate memory space for ramp x" msgstr "无法为时间数据分配空间" #: ../src/ui_render_dialog.c:355 #, fuzzy msgid "couldn't allocate memory space for ramp y" msgstr "无法为时间数据分配空间" #: ../src/ui_render_dialog.c:446 msgid "Failed to Allocate Memory for Ramp" msgstr "" #: ../src/ui_render_dialog.c:496 #, c-format msgid "%s: Rendering Parameters Dialog" msgstr "" #. widgets to change the quality versus speed of rendering #: ../src/ui_render_dialog.c:519 msgid "Speed versus Quality" msgstr "" #. allow rendering to be click and drag #: ../src/ui_render_dialog.c:552 msgid "update without button release" msgstr "" #. widget for the stereo eye angle #: ../src/ui_render_dialog.c:567 msgid "Stereo Angle" msgstr "" #. widget for the stereo eye width #: ../src/ui_render_dialog.c:581 msgid "Eye Width (mm)" msgstr "" #. the depth cueing enabling button #: ../src/ui_render_dialog.c:603 msgid "enable/disable depth cueing" msgstr "" #: ../src/ui_render_dialog.c:611 msgid "Front Factor" msgstr "" #: ../src/ui_render_dialog.c:624 msgid "Density" msgstr "" #: ../src/ui_render_dialog.c:669 #, c-format msgid "%s: Transfer Function Dialog" msgstr "" #. widgets to change the returned pixel type of the rendering #: ../src/ui_render_dialog.c:695 msgid "Return Type" msgstr "" #. color table selector #: ../src/ui_render_dialog.c:725 msgid "color table:" msgstr "" #: ../src/ui_render_dialog.c:757 msgid "" "Density\n" "Dependent\n" "Opacity" msgstr "" #. gradient classification #: ../src/ui_render_dialog.c:759 msgid "" "Gradient\n" "Dependent\n" "Opacity" msgstr "" #. GTK no longer has a way to detect automatically when the GtkCurve has been changed, #. user will now have to explicitly change #: ../src/ui_render_dialog.c:783 msgid "Apply Curve Changes" msgstr "" #: ../src/ui_render_movie.c:399 #, fuzzy msgid "couldn't allocate memory space for ui_render_movie_t" msgstr "无法为时间数据分配空间" #: ../src/ui_render_movie.c:641 #, c-format msgid "%s: Rendering Movie Generation Dialog" msgstr "" #. widgets to specify how many frames #: ../src/ui_render_movie.c:669 msgid "Movie Duration (sec)" msgstr "" #: ../src/ui_render_movie.c:694 #, c-format msgid "Rotations on %s" msgstr "" #: ../src/ui_render_movie.c:845 msgid "Rendered Movie Progress" msgstr "" #: ../src/ui_series.c:57 msgid "over Space" msgstr "" #: ../src/ui_series.c:58 msgid "over Time" msgstr "" #: ../src/ui_series.c:59 msgid "over Gates" msgstr "" #: ../src/ui_series.c:63 #, fuzzy msgid "Look at a series of images over a spatial dimension" msgstr "从一个轴向顺序查看剖面图" #: ../src/ui_series.c:64 msgid "Look at a series of images over time" msgstr "从时间顺序查看剖面图" #: ../src/ui_series.c:65 #, fuzzy msgid "Look at a series of images over gates" msgstr "从时间顺序查看剖面图" #: ../src/ui_series.c:200 msgid "ui_series canvas failed to return a valid image\n" msgstr "" #: ../src/ui_series.c:341 msgid "No data sets to threshold\n" msgstr "" #: ../src/ui_series.c:405 #, fuzzy msgid "_Export Series" msgstr "导出视图(_E)" #: ../src/ui_series.c:406 #, fuzzy msgid "Export the series view to a JPEG image file" msgstr "将数据集的一幅视图导出" #: ../src/ui_series.c:444 msgid "Set the thresholds and colormaps for the data sets in the series view" msgstr "" #: ../src/ui_series.c:577 #, fuzzy msgid "couldn't allocate memory space for ui_series_t" msgstr "无法为时间数据分配空间" #: ../src/ui_series.c:693 msgid "Slicing for series" msgstr "" #: ../src/ui_series.c:700 #, fuzzy msgid "couldn't allocate memory space for pointers to image GnomeCanvasItem's" msgstr "无法为时间数据分配空间" #: ../src/ui_series.c:705 #, fuzzy msgid "" "couldn't allocate memory space for pointers to caption GnomeCanvasItem's" msgstr "无法为时间数据分配空间" #: ../src/ui_series.c:710 #, fuzzy msgid "couldn't allocate memory space for pointers to GnomeCanavasItem lists" msgstr "无法为时间数据分配空间" #: ../src/ui_series.c:990 #, c-format msgid "Series: %s (%s - %s)" msgstr "" #: ../src/ui_series.c:1007 msgid "Need selected objects to create a series" msgstr "" #: ../src/ui_series.c:1078 msgid "Need selected data sets to generate a series of slices over time" msgstr "" #: ../src/ui_series.c:1086 #, fuzzy msgid "unable to allocate memory space for frames" msgstr "无法为时间数据分配空间" #: ../src/ui_series.c:1095 msgid "unable to allocate memory for frame durations" msgstr "" #: ../src/ui_series.c:1369 #, c-format msgid "%s: Series Initialization Dialog" msgstr "" #. what series type do we want #: ../src/ui_series.c:1389 #, fuzzy msgid "Series Type:" msgstr "序列图(_S)" #. what view type do we want #: ../src/ui_series.c:1422 msgid "View Type:" msgstr "" #. internal variables #: ../src/ui_study.c:46 msgid "new" msgstr "" #: ../src/ui_study.c:49 msgid "m1" msgstr "" #: ../src/ui_study.c:49 #, fuzzy msgid "shift-m1" msgstr "平移" #: ../src/ui_study.c:50 msgid "m2" msgstr "" #: ../src/ui_study.c:50 #, fuzzy msgid "shift-m2" msgstr "平移" #: ../src/ui_study.c:51 msgid "m3" msgstr "" #: ../src/ui_study.c:51 #, fuzzy msgid "shift-m3" msgstr "平移" #: ../src/ui_study.c:51 #, fuzzy msgid "ctrl-m3" msgstr "Shift-Ctrl-3" #: ../src/ui_study.c:62 msgid "ctrl-x" msgstr "" #: ../src/ui_study.c:63 #, fuzzy msgid "shift-ctrl-m3" msgstr "Shift-Ctrl-3" #. BLANK #. CANVAS_FIDUCIAL_MARK #: ../src/ui_study.c:71 ../src/ui_study.c:83 msgid "move view" msgstr "移动视图" #: ../src/ui_study.c:71 msgid "shift data set" msgstr "移动数据集" #: ../src/ui_study.c:72 ../src/ui_study.c:84 msgid "move view, min. depth" msgstr "至小深度移动视图" #: ../src/ui_study.c:73 ../src/ui_study.c:85 msgid "change depth" msgstr "改变深度" #: ../src/ui_study.c:73 msgid "rotate data set" msgstr "旋转数据集" #: ../src/ui_study.c:73 ../src/ui_study.c:129 msgid "add fiducial mark" msgstr "增加基准标志" #. DATA SET #. CANVAS_ROI #. STUDY #. CANVAS_ISOCONTOUR_ROI #: ../src/ui_study.c:75 ../src/ui_study.c:79 ../src/ui_study.c:87 #: ../src/ui_study.c:91 ../src/ui_study.c:121 msgid "shift" msgstr "平移" #: ../src/ui_study.c:76 msgid "scale" msgstr "缩放" #: ../src/ui_study.c:77 ../src/ui_study.c:125 msgid "rotate" msgstr "旋转" #: ../src/ui_study.c:77 ../src/ui_study.c:89 ../src/ui_study.c:93 msgid "set data set inside roi to zero" msgstr "" #: ../src/ui_study.c:78 ../src/ui_study.c:90 ../src/ui_study.c:94 msgid "set data set outside roi to zero" msgstr "" #: ../src/ui_study.c:85 msgid "rotate study" msgstr "旋转项目" #: ../src/ui_study.c:88 ../src/ui_study.c:92 msgid "enter draw mode" msgstr "" #: ../src/ui_study.c:89 msgid "start isocontour change" msgstr "" #. CANVAS_FREEHAND_ROI #: ../src/ui_study.c:95 msgid "draw point" msgstr "" #: ../src/ui_study.c:95 msgid "draw large point" msgstr "" #: ../src/ui_study.c:96 msgid "leave draw mode" msgstr "" #: ../src/ui_study.c:97 #, fuzzy msgid "erase point" msgstr "选择点" #: ../src/ui_study.c:97 msgid "erase large point" msgstr "" #. CANVAS_DRAWING_MODE #: ../src/ui_study.c:99 #, fuzzy msgid "move line" msgstr "移动视图" #: ../src/ui_study.c:101 #, fuzzy msgid "rotate line" msgstr "旋转" #. CANVAS_LINE_PROFILE #: ../src/ui_study.c:103 msgid "draw - edge-to-edge" msgstr "" #: ../src/ui_study.c:104 msgid "draw - center out" msgstr "" #. CANVAS_NEW_ROI #: ../src/ui_study.c:107 msgid "pick isocontour start point" msgstr "" #. CANVAS_NEW_ISOCONTOUR_ROI #: ../src/ui_study.c:111 msgid "pick freehand drawing start point" msgstr "" #. CANVAS_NEW_FREEHAND_ROI #. CANVAS CHANGE ISOCONTOUR #. CANVAS SHIFT OBJECT #: ../src/ui_study.c:115 ../src/ui_study.c:119 ../src/ui_study.c:123 msgid "cancel" msgstr "取消" #: ../src/ui_study.c:117 msgid "pick new isocontour" msgstr "" #. CANVAS ROTATE OBJECT #: ../src/ui_study.c:127 msgid "select data set" msgstr "选择数据集" #: ../src/ui_study.c:128 ../src/ui_study.c:140 msgid "make active" msgstr "激活" #: ../src/ui_study.c:129 msgid "pop up data set dialog" msgstr "弹出数据集对话框" #: ../src/ui_study.c:129 ../src/ui_study.c:141 ../src/ui_study.c:145 msgid "add roi" msgstr "增加 ROI" #: ../src/ui_study.c:130 msgid "delete data set" msgstr "删除数据集" #. TREE_DATA_SET #: ../src/ui_study.c:131 msgid "select roi" msgstr "选择 ROI" #: ../src/ui_study.c:132 msgid "center view on roi" msgstr "以 ROI 为中心的视图" #: ../src/ui_study.c:133 msgid "pop up roi dialog" msgstr "弹出 ROI 对话框" #: ../src/ui_study.c:134 msgid "delete roi" msgstr "删除 ROI" #. TREE_ROI #: ../src/ui_study.c:135 msgid "select point" msgstr "选择点" #: ../src/ui_study.c:136 msgid "center view on point" msgstr "以点为中心的视图" #: ../src/ui_study.c:137 msgid "pop up point dialog" msgstr "弹出点对话框" #: ../src/ui_study.c:138 msgid "delete mark" msgstr "" #: ../src/ui_study.c:141 msgid "pop up study dialog" msgstr "" #: ../src/ui_study.c:507 #, c-format msgid "" "Adding fiducial mark for data set: %s\n" "Enter the mark's name:" msgstr "" #: ../src/ui_study.c:553 #, c-format msgid "" "Adding ROI to: %s\n" "Enter ROI Name:" msgstr "" #: ../src/ui_study.c:610 #, c-format msgid "%d-%d" msgstr "" #: ../src/ui_study.c:614 msgid "N/A" msgstr "" #: ../src/ui_study.c:629 #, c-format msgid "%g-%g s" msgstr "" #: ../src/ui_study.c:709 #, c-format msgid "[x,y,z] = [% 5.2f,% 5.2f,% 5.2f] mm" msgstr "" #: ../src/ui_study.c:712 #, c-format msgid "value = % 5.3g" msgstr "" #: ../src/ui_study.c:714 msgid "value = none" msgstr "" #: ../src/ui_study.c:716 msgid "shift (x,y,z) =" msgstr "" #: ../src/ui_study.c:717 ../src/ui_study.c:726 #, c-format msgid "[% 5.2f,% 5.2f,% 5.2f] mm" msgstr "" #: ../src/ui_study.c:721 #, c-format msgid "theta = % 5.3f degrees" msgstr "" #: ../src/ui_study.c:725 msgid "view center (x,y,z) =" msgstr "" #: ../src/ui_study.c:924 #, c-format msgid "Study: %s %s" msgstr "" #: ../src/ui_study.c:928 #, c-format msgid "Study: %s (%s) %s" msgstr "" #: ../src/ui_study_cb.c:57 msgid "" "This wizard requires compiled in support from the GNU Scientific Library " "(libgsl), which this copy of AMIDE does not have." msgstr "" #: ../src/ui_study_cb.c:76 #, c-format msgid "%s: Pick Object(s) to Import" msgstr "" #: ../src/ui_study_cb.c:151 #, c-format msgid "error loading study: %s" msgstr "读入 %1$s 图像分析项目出错" #: ../src/ui_study_cb.c:179 msgid "Open AMIDE XIF File" msgstr "" #: ../src/ui_study_cb.c:271 msgid "Save File" msgstr "保存文件" #: ../src/ui_study_cb.c:353 #, c-format msgid "Could not import data sets from file %s\n" msgstr "" #: ../src/ui_study_cb.c:373 msgid "Import File" msgstr "导入文件" #: ../src/ui_study_cb.c:476 #, fuzzy msgid "There's currently no active data set to export" msgstr "无当前数据集可删除" #: ../src/ui_study_cb.c:583 #, fuzzy, c-format msgid "error recovering study: %s" msgstr "读入 %1$s 图像分析项目出错" #: ../src/ui_study_cb.c:608 msgid "Recover AMIDE XIF File" msgstr "" #: ../src/ui_study_cb.c:714 msgid "no active data set to erase from" msgstr "无当前数据集可删除" #: ../src/ui_study_cb.c:723 #, c-format msgid "" "Do you really wish to erase the data set %s\n" " to the ROI: %s\n" " on the data set: %s\n" "This step is irreversible\n" "The minimum threshold value: %5.3f\n" " will be used to fill in the volume" msgstr "" #: ../src/ui_study_cb.c:724 msgid "exterior" msgstr "外部" #: ../src/ui_study_cb.c:724 msgid "interior" msgstr "内部" #: ../src/ui_study_cb.c:836 #, c-format msgid "Do you really want to delete: %s%s" msgstr "您是否确定删除:%1$s%2$s" #: ../src/ui_study_cb.c:839 #, fuzzy msgid "" "\n" "and its children" msgstr "" "\n" "它还是个孩子" #: ../src/ui_study_cb.c:1351 msgid "" "There are unsaved changes to the study.\n" "Are you sure you wish to quit?" msgstr "" "当前项目的变化还未保存。\n" "您是否确定推出?" #: ../src/ui_study_menus.c:172 ../src/ui_study_menus.c:251 msgid "_Transverse" msgstr "横断面(_T)" #: ../src/ui_study_menus.c:173 msgid "" "Export the current transaxial view to an image file (JPEG/TIFF/PNG/etc.)" msgstr "导出当前横断面视图到一个图像文件(JPEG/TIFF/PNG 等)" #: ../src/ui_study_menus.c:175 ../src/ui_study_menus.c:254 msgid "_Coronal" msgstr "头断面(_C)" #: ../src/ui_study_menus.c:176 msgid "Export the current coronal view to an image file (JPEG/TIFF/PNG/etc.)" msgstr "导出当前头断面视图到一个图像文件(JPEG/TIFF/PNG 等)" #: ../src/ui_study_menus.c:178 ../src/ui_study_menus.c:257 msgid "_Sagittal" msgstr "竖断面(_S)" #: ../src/ui_study_menus.c:179 msgid "Export the current sagittal view to an image file (JPEG/TIFF/PNG/etc.)" msgstr "导出当前竖断面视图到一个图像文件(JPEG/TIFF/PNG 等)" #: ../src/ui_study_menus.c:186 msgid "_New Study" msgstr "新项目(_N)" #: ../src/ui_study_menus.c:187 msgid "Create a new study viewer window" msgstr "创建一个新项目的查看窗" #: ../src/ui_study_menus.c:192 msgid "_Import File (guess)" msgstr "导入文件(猜测格式)(_I)" #: ../src/ui_study_menus.c:193 msgid "Import an image data file into this study, guessing at the file type" msgstr "向当前项目导入一个图像数据文件,猜测数据格式" #: ../src/ui_study_menus.c:196 msgid "Import File (_specify)" msgstr "导入文件(指定格式)(_s)" #: ../src/ui_study_menus.c:197 #, fuzzy msgid "Import an image data file into this study, specifying the import type" msgstr "向当前项目导入一个图像数据文件,指定导入方式" #: ../src/ui_study_menus.c:199 msgid "Import _Object from Study" msgstr "" #: ../src/ui_study_menus.c:200 msgid "Import an object, such as an ROI, from a preexisting .xif file" msgstr "" #: ../src/ui_study_menus.c:204 msgid "_Export View" msgstr "导出视图(_E)" #: ../src/ui_study_menus.c:205 #, fuzzy msgid "Export one of the views to a picture file" msgstr "将数据集的一幅视图导出" #: ../src/ui_study_menus.c:207 msgid "Export _Data Set" msgstr "" #: ../src/ui_study_menus.c:208 msgid "Export data set(s) to medical image formats" msgstr "" #: ../src/ui_study_menus.c:212 #, fuzzy msgid "_Recover Study" msgstr "新项目(_N)" #: ../src/ui_study_menus.c:213 msgid "Try to recover a corrupted XIF flat file" msgstr "" #: ../src/ui_study_menus.c:225 msgid "Add _ROI" msgstr "增加ROI文件(_R)" #: ../src/ui_study_menus.c:226 msgid "Add a new ROI" msgstr "新增ROI文件" #: ../src/ui_study_menus.c:228 msgid "Add _Fiducial Mark" msgstr "增加基准标志(_F)" #: ../src/ui_study_menus.c:229 msgid "Add a new fiducial mark to the active data set" msgstr "给当前数据集增加新的基准标志" #: ../src/ui_study_menus.c:238 msgid "_Series" msgstr "序列图(_S)" #: ../src/ui_study_menus.c:239 msgid "Look at a series of images" msgstr "按序列查看剖面图" #: ../src/ui_study_menus.c:242 msgid "_Volume Rendering" msgstr "体视图生成(_V)" #: ../src/ui_study_menus.c:243 msgid "perform a volume rendering on the currently selected objects" msgstr "生成当前选定对象的三维立体透视图" #: ../src/ui_study_menus.c:252 msgid "Generate a fly through using transaxial slices" msgstr "依横向产生逐帧察看动画" #: ../src/ui_study_menus.c:255 msgid "Generate a fly through using coronal slices" msgstr "依头向产生逐帧察看动画" #: ../src/ui_study_menus.c:258 msgid "Generate a fly through using sagittal slices" msgstr "依竖向产生逐帧察看动画" #: ../src/ui_study_menus.c:266 msgid "_Alignment Wizard" msgstr "排列向导(_A)" #: ../src/ui_study_menus.c:267 msgid "guides you throw the processing of alignment" msgstr "逐步指导你做排列处理" #: ../src/ui_study_menus.c:270 msgid "_Crop Active Data Set" msgstr "裁减当前数据集(_C)" #: ../src/ui_study_menus.c:271 msgid "allows you to crop the active data set" msgstr "裁减当前数据集" #: ../src/ui_study_menus.c:274 msgid "_Factor Analysis" msgstr "要素分析(_F)" #: ../src/ui_study_menus.c:275 msgid "allows you to do factor analysis of dynamic data on the active data set" msgstr "对当前数据集的动态数据做要素分析" #: ../src/ui_study_menus.c:278 msgid "_Filter Active Data Set" msgstr "过滤处理当前数据集(_F)" #: ../src/ui_study_menus.c:279 msgid "allows you to filter the active data set" msgstr "过滤处理当前数据集" #: ../src/ui_study_menus.c:283 msgid "Generate _Fly Through" msgstr "产生逐帧察看动画(_F)" #: ../src/ui_study_menus.c:284 msgid "generate an mpeg fly through of the data sets" msgstr "从数据集中产生逐帧察看动画" #: ../src/ui_study_menus.c:287 msgid "Generate Line _Profile" msgstr "" #: ../src/ui_study_menus.c:288 msgid "allows generating a line profile between two fiducial marks" msgstr "" #: ../src/ui_study_menus.c:291 msgid "Perform _Math on Data Sets" msgstr "" #: ../src/ui_study_menus.c:292 #, fuzzy msgid "allows doing simple math operations between data sets" msgstr "过滤处理当前数据集" #: ../src/ui_study_menus.c:295 msgid "Calculate _ROI Statistics" msgstr "计算ROI的统计信息(_R)" #: ../src/ui_study_menus.c:296 msgid "caculate ROI statistics" msgstr "计算ROI的统计信息" #: ../src/ui_study_menus.c:306 msgid "_Tools" msgstr "工具(_T)" #: ../src/ui_study_menus.c:411 msgid "Leave crosshairs on canvases" msgstr "将十字线留在背景上" #: ../src/ui_study_menus.c:429 msgid "Set the thresholds and colormaps for the active data set" msgstr "设定数据集的伪彩色表和极限" #: ../src/ui_study_menus.c:541 msgid "specify how much to magnify the images" msgstr "指定图像的放大率" #. add the field of view widget to our toolbar #: ../src/ui_study_menus.c:548 msgid "fov (%):" msgstr "" #: ../src/ui_study_menus.c:567 #, fuzzy msgid "specify how much of the image field of view to display" msgstr "指定图像的放大率" #. add the slice thickness selector #: ../src/ui_study_menus.c:574 msgid "thickness (mm):" msgstr "厚度(毫米):" #: ../src/ui_study_menus.c:593 msgid "specify how thick to make the slices (mm)" msgstr "指定切片的厚度(毫米)" #. gate #: ../src/ui_study_menus.c:599 #, fuzzy msgid "gate:" msgstr "时间:" #: ../src/ui_study_menus.c:609 #, fuzzy msgid "the gate range over which to view the data" msgstr "时间范围超出数据的视图(秒)" #. frame selector #: ../src/ui_study_menus.c:615 msgid "time:" msgstr "时间:" #: ../src/ui_study_menus.c:625 msgid "the time range over which to view the data (s)" msgstr "时间范围超出数据的视图(秒)" #: ../src/ui_time_dialog.c:59 ../src/ui_time_dialog.c:485 msgid "Start (s)" msgstr "开始(秒)" #: ../src/ui_time_dialog.c:60 ../src/ui_time_dialog.c:504 msgid "End (s)" msgstr "结束(秒)" #: ../src/ui_time_dialog.c:61 msgid "Frame #" msgstr "帧 #" #: ../src/ui_time_dialog.c:242 msgid "can't count frames or allocate memory!" msgstr "无法计算帧数或者分配内存" #: ../src/ui_time_dialog.c:459 #, c-format msgid "%s: Time Dialog" msgstr "%1$s:时间对话框" #: ../src/xml.c:172 #, c-format msgid "Couldn't read time value for %s, substituting %5.3f" msgstr "无法读取 %1$s 的时间值,代定为%2$5.3f" #: ../src/xml.c:201 ../src/xml.c:242 #, fuzzy msgid "Couldn't allocate memory space for time data" msgstr "无法为时间数据分配空间" #: ../src/xml.c:233 msgid "XIF File appears corrupted, setting frame durations to 1" msgstr "" #: ../src/xml.c:240 #, fuzzy, c-format msgid "Couldn't read value for %s, substituting 1" msgstr "无法读取 %1$s 的值,代定为%2$d" #: ../src/xml.c:287 #, c-format msgid "Couldn't read value for %s, substituting %5.3f" msgstr "无法读取 %1$s 的值,代定为%2$5.3f" #: ../src/xml.c:349 #, c-format msgid "Couldn't read value for %s, substituting FALSE" msgstr "无法读取 %1$s 的值,代定为“假”" #: ../src/xml.c:385 #, c-format msgid "Couldn't read value for %s, substituting %d" msgstr "无法读取 %1$s 的值,代定为%2$d" #: ../src/xml.c:426 #, fuzzy, c-format msgid "Couldn't read value for %s, substituting 0x%llx 0x%llx" msgstr "无法读取 %1$s 的值,代定为%2$d" #: ../src/xml.c:663 #, c-format msgid "Couldn't Parse AMIDE xml file %s" msgstr "" #: ../src/xml.c:687 #, c-format msgid "Could not seek to location %lx in file." msgstr "" #: ../src/xml.c:693 #, c-format msgid "Only read %x bytes from file, expected %x" msgstr "" #~ msgid "No data sets selected\n" #~ msgstr "未选定数据集\n" #~ msgid "Look at a series of transaxial views in a single frame" #~ msgstr "察看一帧的横断面图系列" #~ msgid "Look at a series of coronal views in a single frame" #~ msgstr "察看一帧的头断面图系列" #~ msgid "Look at a series of sagittal views in a single frame" #~ msgstr "察看一帧的竖断面图系列" #~ msgid "Look at a times series of a single transaxial view" #~ msgstr "察看一个横断面视图的时间序列" #~ msgid "Look at a time series of a single coronal view" #~ msgstr "察看一个头断面视图的时间系列" #~ msgid "Look at a time series of a a signal sagittal view" #~ msgstr "察看一个竖断面视图的时间系列" #~ msgid "_Space" #~ msgstr "空间(_S)" #~ msgid "_Time" #~ msgstr "时间(_T)" #~ msgid "Couldn't read value for %s, substituting zero" #~ msgstr "无法读取 %1$s 的值,代定为“零”" amide-1.0.6/amide-current/po/zh_TW.po000066400000000000000000004130101423227705100173470ustar00rootroot00000000000000# Traditional Chinese translation for Amide. # Copyright (C) Andreas Loening (msgids) # This file is distributed under the same license as the amide package. # Wales Wang , 2003. # Wei-Lun Chao , 2011. # #: ../src/amitk_study.c:967 ../src/amitk_study.c:1036 msgid "" msgstr "" "Project-Id-Version: amide 1.0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-11-12 15:17+0800\n" "PO-Revision-Date: 2011-11-12 15:20+0800\n" "Last-Translator: Wei-Lun Chao \n" "Language-Team: Chinese (traditional) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: ../etc/amide.desktop.in.h:1 msgid "A Medical Image Data Examiner" msgstr "醫學影像資料審視器" #: ../etc/amide.desktop.in.h:2 msgid "Amide" msgstr "Amide" #: ../etc/amide.desktop.in.h:3 msgid "Medical Image Examiner" msgstr "醫學影像審視器" #: ../src/alignment_mutual_information.c:308 #, c-format msgid "Maximizing the mutual information" msgstr "將交互資訊放到最大" #: ../src/alignment_procrustes.c:165 #, c-format msgid "Cannot perform an alignment with %d points, need at least 3" msgstr "無法以 %d 點像素施行對齊,需要至少 3 點" #: ../src/alignment_procrustes.c:210 #, c-format msgid "points lists not completely used in %s at %d" msgstr "%s 像素清單中 %d 未完全用完" #: ../src/alignment_procrustes.c:226 ../src/fads.c:148 ../src/fads.c:292 #, c-format msgid "SV decomp returned error: %s" msgstr "SV 解碼發生錯誤: %s" #: ../src/alignment_procrustes.c:232 #, c-format msgid "transpose returned error: %s" msgstr "轉換發生錯誤: %s" #: ../src/alignment_procrustes.c:238 #, c-format msgid "LU decomp returned error: %s" msgstr "LU 解碼發生錯誤: %s" #: ../src/amide.c:47 msgid "_Study" msgstr "檢驗(_S)" #: ../src/amide.c:48 msgid "Selected _Data Sets" msgstr "所選資料集(_D)" #: ../src/amide.c:49 msgid "Selected _ROIs" msgstr "所選 _ROIs" #: ../src/amide.c:50 msgid "Selected _Alignment Points" msgstr "所選對齊點(_A)" #: ../src/amide.c:115 msgid "This version of AMIDE has been compiled without the following functionality:" msgstr "這個版本的 AMIDE 已被編譯而排除下列功能:" #: ../src/amide.c:118 msgid "Line profiles, factor analysis, some filtering, and some alignment (missing libgsl)." msgstr "曲線輪廓、因素分析、某些篩選器,以及某些對齊性 (缺少 libgsl)。" #: ../src/amide.c:121 msgid "Reading of most medical imaging formats except raw and DICOM (missing libmdc)." msgstr "讀取大多數醫學成像格式,除了 raw 和 DICOM (缺少 libmdc)。" #: ../src/amide.c:124 msgid "Reading of most DICOM files (missing libdcmdata/dcmtk)." msgstr "讀取大多數 DICOM 檔案 (缺少 libdcmdata/dcmtk)。" #: ../src/amide.c:127 msgid "Volume rendering (missing libvolpack)." msgstr "體積潤算 (缺少 libvolpack)。" #: ../src/amide.c:130 msgid "Saving MPEG output (missing ffmpeg and missing libfame)." msgstr "儲存 MPEG 輸出 (缺少 ffmpeg 和缺少 libfame)。" #: ../src/amide.c:182 msgid "[FILE1] [FILE2] ..." msgstr "[檔案一] [檔案二]…" #: ../src/amide.c:242 #, c-format msgid "%s does not exist" msgstr "%s 不存在" #: ../src/amide.c:246 #, c-format msgid "Failed to load in as XIF file: %s" msgstr "載入為 XIF 檔案時失敗:%s" #: ../src/amide.c:270 #, c-format msgid "%s is not an AMIDE study or importable file type" msgstr "%s 不是一個 AMIDE 檢驗或是可匯入的檔案類型" #: ../src/amide.c:272 #, c-format msgid "%s is not an AMIDE XIF Directory" msgstr "%s 不是一個 AMIDE XIF 目錄" #: ../src/amide_gnome.c:85 #, c-format msgid "Unknown internal error while displaying this location." msgstr "顯示這個位置時發生不明內部錯誤。" #: ../src/amide_gnome.c:92 #, c-format msgid "The specified location is invalid." msgstr "指定的位置無效。" #: ../src/amide_gnome.c:99 #, c-format msgid "There was an error parsing the default action command associated with this location." msgstr "剖析與這個位置相關聯的預設動作命令時出現了錯誤。" #: ../src/amide_gnome.c:107 #, c-format msgid "There was an error launching the default action command associated with this location." msgstr "啟動與這個位置相關聯的預設動作命令時出現了錯誤。" #: ../src/amide_gnome.c:115 #, c-format msgid "There is no default action associated with this location." msgstr "沒有任何與這個位置相關聯的預設動作命令。" #: ../src/amide_gnome.c:122 #, c-format msgid "The default action does not support this protocol." msgstr "預設的動作不支援這個協定。" #: ../src/amide_gnome.c:129 #, c-format msgid "The request was cancelled." msgstr "要求被取消了。" #: ../src/amide_gnome.c:139 #, c-format msgid "The host \"%s\" could not be found." msgstr "找不到主機「%s」。" #: ../src/amide_gnome.c:145 #, c-format msgid "The host could not be found." msgstr "找不到主機。" #: ../src/amide_gnome.c:156 #, c-format msgid "The location or file could not be found." msgstr "找不到位置或檔案。" #: ../src/amide_gnome.c:163 #, c-format msgid "The login has failed." msgstr "登入已失敗。" #: ../src/amide_gnome.c:354 #, c-format msgid "Unable to find the app or global HELP domain" msgstr "無法找到應用軟體或全域說明功能" #: ../src/amide_gnome.c:391 #, c-format msgid "Unable to find the help files in any of the following directories, or these are not valid directories: %s : Please check your installation" msgstr "在下列任何目錄中無法找到說明檔案,或者是這些無效目錄:%s: 請檢查您的安裝" #: ../src/amitk_canvas.c:72 msgid "A" msgstr "A" #: ../src/amitk_canvas.c:72 msgid "P" msgstr "P" #: ../src/amitk_canvas.c:72 msgid "L" msgstr "L" #: ../src/amitk_canvas.c:72 msgid "R" msgstr "R" #: ../src/amitk_canvas.c:72 msgid "S" msgstr "S" #: ../src/amitk_canvas.c:72 msgid "I" msgstr "I" #: ../src/amitk_canvas.c:727 msgid "ROI Depth Selection" msgstr "ROI 深度選擇" #: ../src/amitk_canvas.c:741 msgid "Please pick depth of ROI (mm):" msgstr "請揀取 ROI 的深度 (公釐):" #: ../src/amitk_canvas.c:843 msgid "Parent of isocontour not currently displayed, can't draw isocontour" msgstr "目前並未顯示輪廓面的上層,無法繪製輪廓面" #: ../src/amitk_canvas.c:860 msgid "No data set found to draw isocontour on" msgstr "找不到任何資料集用以繪製輪廓面" #: ../src/amitk_canvas.c:877 #, c-format msgid "designated voxel not in data set %s" msgstr "指定的體素不存在於資料集 %s" #. pop up dialog to let user pick isocontour values, etc. and for any warning messages #: ../src/amitk_canvas.c:891 msgid "Isocontour Value Selection" msgstr "輪廓面數值選擇" #: ../src/amitk_canvas.c:913 #, c-format msgid "" "Multiple data frames are currently being shown from: %s\n" "The isocontour will only be drawn over frame %d" msgstr "" "多重資料影格目前顯示自:%s\n" "輪廓面將只被繪製於影格 %d" #: ../src/amitk_canvas.c:925 #, c-format msgid "" "Multiple gates are currently being shown from: %s\n" "The isocontour will only be drawn over gate %d" msgstr "" "多重閘口目前顯示自:%s\n" "輪廓面將只被繪製於閘口 %d" #. the spin buttons #: ../src/amitk_canvas.c:945 msgid "Min:" msgstr "最小:" #: ../src/amitk_canvas.c:961 msgid "Max:" msgstr "最大:" #. radio buttons to choose the isocontour type #: ../src/amitk_canvas.c:980 msgid "Above Min" msgstr "最小以上" #: ../src/amitk_canvas.c:981 msgid "Below Max" msgstr "最大以下" #: ../src/amitk_canvas.c:982 msgid "Between Min/Max" msgstr "在最小/最大之間" #: ../src/amitk_canvas.c:1048 msgid "Parent of roi not currently displayed, can't draw freehand roi" msgstr "目前並未顯示 roi 的上層,無法手繪 roi" #: ../src/amitk_canvas.c:1065 msgid "No data set found to draw freehand roi on" msgstr "找不到任何資料集用以手繪 roi" #. pop up dialog to let user pick isocontour values, etc. and for any warning messages #: ../src/amitk_canvas.c:1077 msgid "Freehand ROI Parameters" msgstr "手繪 ROI 參數" #: ../src/amitk_canvas.c:1096 #, c-format msgid "Voxel Size %s" msgstr "體素大小 %s" #: ../src/amitk_canvas.c:1658 ../src/amitk_canvas.c:2219 #: ../src/amitk_canvas.c:2269 ../src/amitk_canvas.c:2277 msgid "The active data set is not visible" msgstr "作用中資料集是不可見的" #: ../src/amitk_canvas.c:3225 msgid "Canvas has no style?\n" msgstr "畫布沒有任何樣式?\n" #: ../src/amitk_color_table.c:37 msgid "black/white linear" msgstr "黑/白線性" #: ../src/amitk_color_table.c:38 msgid "white/black linear" msgstr "白/黑線性" #: ../src/amitk_color_table.c:39 msgid "black/white/black" msgstr "黑/白/黑" #: ../src/amitk_color_table.c:40 msgid "white/black/white" msgstr "白/黑/白" #: ../src/amitk_color_table.c:41 msgid "red temperature" msgstr "紅色溫度" #: ../src/amitk_color_table.c:42 msgid "inverse red temp." msgstr "紅色逆溫度" #: ../src/amitk_color_table.c:43 msgid "blue temperature" msgstr "藍色溫度" #: ../src/amitk_color_table.c:44 msgid "inv. blue temp." msgstr "藍色逆溫度" #: ../src/amitk_color_table.c:45 msgid "green temperature" msgstr "綠色溫度" #: ../src/amitk_color_table.c:46 msgid "inv. green temp." msgstr "綠色逆溫度" #: ../src/amitk_color_table.c:47 msgid "hot metal" msgstr "熱金屬色" #: ../src/amitk_color_table.c:48 msgid "inv. hot metal" msgstr "熱逆金屬色" #: ../src/amitk_color_table.c:49 msgid "hot metal contour" msgstr "熱金屬輪廓" #: ../src/amitk_color_table.c:50 msgid "inv. hot metal c." msgstr "熱逆金屬輪廓" #: ../src/amitk_color_table.c:51 msgid "hot blue" msgstr "熱藍色" #: ../src/amitk_color_table.c:52 msgid "inverse hot blue" msgstr "熱逆藍色" #: ../src/amitk_color_table.c:53 msgid "hot green" msgstr "熱綠色" #: ../src/amitk_color_table.c:54 msgid "inverse hot green" msgstr "熱逆綠色" #: ../src/amitk_color_table.c:55 msgid "spectrum" msgstr "光譜" #: ../src/amitk_color_table.c:56 msgid "inverse spectrum" msgstr "逆光譜" #: ../src/amitk_color_table.c:57 msgid "NIH + white" msgstr "NIH + 白色" #: ../src/amitk_color_table.c:58 msgid "inv. NIH + white" msgstr "NIH + 逆白色" #: ../src/amitk_color_table.c:59 msgid "NIH" msgstr "NIH" #: ../src/amitk_color_table.c:60 msgid "inverse NIH" msgstr "逆 NIH" #: ../src/amitk_common.c:41 ../src/tb_roi_analysis.c:94 msgid "Min" msgstr "最小" #: ../src/amitk_common.c:42 ../src/tb_roi_analysis.c:95 msgid "Max" msgstr "最大" #: ../src/amitk_common.c:45 ../src/amitk_object_dialog.c:705 #: ../src/amitk_threshold.c:1288 msgid "Center" msgstr "中心" #: ../src/amitk_common.c:46 ../src/amitk_threshold.c:1289 msgid "Width" msgstr "寬度" #. N_("Bone"), #. N_("Soft Tissue") #: ../src/amitk_common.c:53 msgid "Abdomen" msgstr "腹部" #: ../src/amitk_common.c:54 msgid "Brain" msgstr "腦部" #: ../src/amitk_common.c:55 msgid "Extremities" msgstr "四肢" #: ../src/amitk_common.c:56 msgid "Liver" msgstr "肝臟" #: ../src/amitk_common.c:57 msgid "Lung" msgstr "肺臟" #: ../src/amitk_common.c:58 msgid "Pelvis, soft tissue" msgstr "骨盆,軟組織" #: ../src/amitk_common.c:59 msgid "Skull Base" msgstr "顱底" #: ../src/amitk_common.c:60 msgid "Spine A" msgstr "脊柱 A" #: ../src/amitk_common.c:61 msgid "Spine B" msgstr "脊柱 B" #: ../src/amitk_common.c:62 msgid "Thorax, soft tissue" msgstr "胸腔,軟組織" #: ../src/amitk_data_set.c:87 ../src/ui_study.c:402 msgid "interpolate using nearest neighbor (fast)" msgstr "使用最近的鄰點添寫 (快速)" #: ../src/amitk_data_set.c:88 ../src/ui_study.c:403 msgid "interpolate using trilinear interpolation (slow)" msgstr "使用三線內插法添寫 (緩慢)" #. place holder for AMITK_IMPORT_METHOD_GUESS #: ../src/amitk_data_set.c:94 msgid "_Raw Data" msgstr "原始資料(_R)" #: ../src/amitk_data_set.c:96 msgid "_DICOM via dcmtk" msgstr "_DICOM 透過 dcmtk" #: ../src/amitk_data_set.c:99 msgid "_ECAT 6/7 via libecat" msgstr "_ECAT 6/7 透過 libecat" #: ../src/amitk_data_set.c:109 msgid "Import file as raw data" msgstr "匯入原始資料檔案" #: ../src/amitk_data_set.c:111 msgid "Import a DICOM file or directory file using the DCMTK library" msgstr "使用 DCMTK 函式庫匯入 DICOM 資料檔案" #: ../src/amitk_data_set.c:114 msgid "Import a CTI 6.4 or 7.0 file using the libecat library" msgstr "使用 libecat 函式庫匯入 CTI 6.4 或 7.0 資料檔案" #: ../src/amitk_data_set.c:117 msgid "Import via the (X)medcon library (libmdc)" msgstr "使用 (X)medcon 函式庫 (libmdc) 匯入" #: ../src/amitk_data_set.c:122 msgid "Raw Data" msgstr "原始資料" #: ../src/amitk_data_set.c:124 msgid "DICOM via dcmtk" msgstr "DICOM 透過 dcmtk" #: ../src/amitk_data_set.c:133 msgid "Export file as raw data" msgstr "匯出原始資料檔案" #: ../src/amitk_data_set.c:135 msgid "Export a DICOM file or directory file using the DCMTK library" msgstr "使用 DCMTK 函式庫匯出 DICOM 檔案或目錄檔案" #: ../src/amitk_data_set.c:138 msgid "Export via the (X)medcon library (libmdc)" msgstr "使用 (X)medcon 函式庫 (libmdc) 匯出" #: ../src/amitk_data_set.c:143 msgid "Direct" msgstr "直接" #: ../src/amitk_data_set.c:144 msgid "%ID/cc" msgstr "%ID/cc" #: ../src/amitk_data_set.c:145 msgid "SUV" msgstr "SUV" #: ../src/amitk_data_set.c:149 msgid "MBq" msgstr "MBq" #: ../src/amitk_data_set.c:150 msgid "mCi" msgstr "mCi" #: ../src/amitk_data_set.c:151 msgid "uCi" msgstr "uCi" #: ../src/amitk_data_set.c:152 msgid "nCi" msgstr "nCi" #: ../src/amitk_data_set.c:156 msgid "Kg" msgstr "公斤" #: ../src/amitk_data_set.c:157 msgid "g" msgstr "公克" #: ../src/amitk_data_set.c:158 msgid "lbs" msgstr "英磅" #: ../src/amitk_data_set.c:159 msgid "ounces" msgstr "盎司" #: ../src/amitk_data_set.c:163 msgid "MBq/cc/Image Units" msgstr "MBq/cc/影像單位" #: ../src/amitk_data_set.c:164 msgid "mCi/cc/Image Units" msgstr "mCi/cc/影像單位" #: ../src/amitk_data_set.c:165 msgid "uCi/cc/Image Units" msgstr "uCi/cc/影像單位" #: ../src/amitk_data_set.c:166 msgid "nCi/cc/Image Units" msgstr "nCi/cc/影像單位" #: ../src/amitk_data_set.c:167 msgid "Image Units/(MBq/cc)" msgstr "影像單位/(MBq/cc)" #: ../src/amitk_data_set.c:168 msgid "Image Units/(mCi/cc)" msgstr "影像單位/(mCi/cc)" #: ../src/amitk_data_set.c:169 msgid "Image Units/(uCi/cc)" msgstr "影像單位/(uCi/cc)" #: ../src/amitk_data_set.c:170 msgid "Image Units/(nCi/cc)" msgstr "影像單位/(nCi/cc)" #: ../src/amitk_data_set.c:174 msgid "Single Scale Factor" msgstr "單一伸縮因子" #: ../src/amitk_data_set.c:175 msgid "Per Frame Scale Factor" msgstr "各影格伸縮因子" #: ../src/amitk_data_set.c:176 msgid "Per Plane Scale Factor" msgstr "各平面伸縮因子" #: ../src/amitk_data_set.c:177 msgid "Single Scale Factor with Intercept" msgstr "單一伸縮因子並截取" #: ../src/amitk_data_set.c:178 msgid "Per Frame Scale Factor with Intercept" msgstr "各影格伸縮因子並截取" #: ../src/amitk_data_set.c:179 msgid "Per Plane Scale Factor with Intercept" msgstr "各平面伸縮因子並截取" #: ../src/amitk_data_set.c:943 ../src/libmdc_interface.c:415 msgid "Voxel size X was read as 0, setting to 1 mm. This may be an internationalization error." msgstr "體素大小 X 讀出值為 0, 設定為 1 公釐。 這也許是軟體國際化的錯誤。" #: ../src/amitk_data_set.c:947 ../src/libmdc_interface.c:419 msgid "Voxel size Y was read as 0, setting to 1 mm. This may be an internationalization error." msgstr "體素大小 Y 讀出值為 0, 設定為 1 公釐。 這也許是軟體國際化的錯誤。" #: ../src/amitk_data_set.c:951 ../src/libmdc_interface.c:423 msgid "Voxel size Z was read as 0, setting to 1 mm. This may be an internationalization error." msgstr "體素大小 Z 讀出值為 0, 設定為 1 公釐。 這也許是軟體國際化的錯誤。" #: ../src/amitk_data_set.c:990 msgid "internal scaling factor returned NULL... either file is corrupt, or AMIDE has a bug" msgstr "內部縮放因子回傳空值… 若非檔案損壞,就是 AMIDE 有程式錯誤" #: ../src/amitk_data_set.c:1057 msgid "wrong type found on internal scaling, converting to double" msgstr "於內部縮放伸縮找到錯誤類型,轉換到雙精確度" #: ../src/amitk_data_set.c:1062 msgid "Couldn't allocate memory space for the new scaling factors" msgstr "無法配置記憶體空間給新的縮放因子" #: ../src/amitk_data_set.c:1367 msgid "couldn't allocate memory space for the data set structure to hold data" msgstr "無法配置記憶體空間給資料集結構以存放資料" #: ../src/amitk_data_set.c:1375 msgid "raw_data_read_file failed returning NULL data set" msgstr "raw_data_read_file 失敗並回傳空值資料集" #: ../src/amitk_data_set.c:1382 msgid "couldn't allocate memory space for the frame duration info" msgstr "無法配置記憶體空間給影格的時間資訊" #: ../src/amitk_data_set.c:1478 #, c-format msgid "" "File has incorrect permissions for reading\n" "Can I try changing access permissions on:\n" " %s?" msgstr "" "檔案的讀取許可不正確\n" "我可以嘗試變更存取許可於:\n" " %s?" #: ../src/amitk_data_set.c:1490 ../src/amitk_data_set.c:1497 msgid "failed to change read permissions, you're probably not the owner" msgstr "變更讀取許可時失敗,您或許並非擁有者" #: ../src/amitk_data_set.c:1504 msgid "failed to change read permissions on raw data file, you're probably not the owner" msgstr "變更原始資料檔案的讀取許可時失敗,您或許並非擁有者" #. unrecognized file type #: ../src/amitk_data_set.c:1558 #, c-format msgid "" "Extension %s not recognized on file: %s\n" "Guessing File Type" msgstr "" "延伸檔名 %s 無法辨識於檔案:%s\n" "正在猜測檔案類型" #: ../src/amitk_data_set.c:1630 #, c-format msgid "Data Set %s has erroneous voxel size of %gx%gx%g, setting to 1.0x1.0x1.0" msgstr "資料集 %s 有錯誤的體素大小 %gx%gx%g,設定為 1.0x1.0x1.0" #: ../src/amitk_data_set.c:1709 msgid "Couldn't allocate memory space for row_data" msgstr "無法配置記憶體空間給原始資料(_D)" #: ../src/amitk_data_set.c:1715 #, c-format msgid "couldn't open file for writing: %s" msgstr "無法開啟檔案以供寫入:%s" #: ../src/amitk_data_set.c:1721 #, c-format msgid "" "Exporting Raw Data for:\n" " %s" msgstr "" "匯出原始資料給:\n" " %s" #: ../src/amitk_data_set.c:1749 ../src/dcmtk_interface.cc:2384 #: ../src/libmdc_interface.c:1120 #, c-format msgid "Error in generating resliced data, %dx%d != %dx%d" msgstr "產生重新切片的資料時發生錯誤,%dx%d != %dx%d" #: ../src/amitk_data_set.c:1792 #, c-format msgid "incomplete save of raw data, wrote %lx (bytes), file: %s" msgstr "原始資料儲存不完整,已寫入 %lx (位元組),檔案:%s" #: ../src/amitk_data_set.c:1900 #, c-format msgid "Generating new data set" msgstr "產生新資料集" #: ../src/amitk_data_set.c:1914 msgid "Could not allocate memory space for volume" msgstr "無法配置記憶體空間給體積" #: ../src/amitk_data_set.c:1947 msgid "Failed to allocate export data set" msgstr "配置匯出資料集時失敗" #: ../src/amitk_data_set.c:2464 ../src/amitk_data_set.c:2485 #: ../src/amitk_data_set.c:2507 ../src/amitk_data_set.c:2529 msgid "unknown" msgstr "不明" #: ../src/amitk_data_set.c:2973 #, c-format msgid "" "Calculating Max/Min Values for:\n" " %s" msgstr "" "計算最大/最小值用於:\n" " %s" #: ../src/amitk_data_set.c:4145 #, c-format msgid "" "Generating projections of:\n" " %s" msgstr "" "產生資料投影自:\n" " %s" #: ../src/amitk_data_set.c:4176 #, c-format msgid "couldn't allocate memory space for the projection, wanted %dx%dx%dx%dx%d elements" msgstr "無法配置記憶體空間給資料投影,需要 %dx%dx%dx%dx%d 元素" #. set a new name for this guy #: ../src/amitk_data_set.c:4400 #, c-format msgid "%s, cropped" msgstr "%s,已裁剪" #: ../src/amitk_data_set.c:4411 ../src/amitk_data_set.c:4418 msgid "couldn't allocate memory space for the cropped internal scaling structure" msgstr "無法配置記憶體空間給裁剪過的內部縮放伸縮結構" #: ../src/amitk_data_set.c:4424 #, c-format msgid "" "Generating cropped version of:\n" " %s" msgstr "" "產生裁剪版本自:\n" " %s" #: ../src/amitk_data_set.c:4604 msgid "couldn't allocate memory space for the cropped raw data set structure" msgstr "無法配置記憶體空間給裁剪過的原始資料集結構" #: ../src/amitk_data_set.c:4732 msgid "Filtering: Failed to allocate wavetable and workspace" msgstr "篩選:無法配置音效表和工作區" #: ../src/amitk_data_set.c:4739 msgid "couldn't allocate memory space for the subset structure" msgstr "無法配置記憶體空間給子集結構" #: ../src/amitk_data_set.c:4759 msgid "Couldn't allocate memory space for the subset data" msgstr "無法配置記憶體空間給子集資料" #: ../src/amitk_data_set.c:4768 ../src/amitk_data_set.c:4950 #, c-format msgid "Filtering Data Set: %s" msgstr "篩選資料集: %s" #: ../src/amitk_data_set.c:4921 msgid "data set z dimension to small for kernel, setting kernel dimension to 1" msgstr "資料集 z 維度對內核而言太小,設定內核維度到 1" #: ../src/amitk_data_set.c:4925 msgid "data set y dimension to small for kernel, setting kernel dimension to 1" msgstr "資料集 y 維度對內核而言太小,設定內核維度到 1" #: ../src/amitk_data_set.c:4929 msgid "data set x dimension to small for kernel, setting kernel dimension to 1" msgstr "資料集 x 維度對內核而言太小,設定內核維度到 1" #: ../src/amitk_data_set.c:4942 msgid "couldn't allocate memory space for the internal raw data" msgstr "無法配置記憶體空間給內部原始資料" #. set a new name for this guy #: ../src/amitk_data_set.c:5129 #, c-format msgid "%s, %s filtered" msgstr "%s,%s 已篩選" #: ../src/amitk_data_set.c:5137 msgid "couldn't allocate memory space for the filtered raw data set structure" msgstr "無法配置記憶體空間給篩選過的原始資料集結構" #: ../src/amitk_data_set.c:5164 msgid "failed to calculate 3D gaussian kernel" msgstr "計算立體 gaussian 內核時失敗" #: ../src/amitk_data_set.c:5585 #, c-format msgid "Can't handle 'by frame' operations with data sets with unequal frame numbers, will use all frames of %s and the first gate of %s" msgstr "具備不對等影格數量的資料集,無法「依影格」計算處理,將使用 %s 的所有影格以及 %s 的第一個影格" #: ../src/amitk_data_set.c:5589 #, c-format msgid "Output data set will have the same number of frames as %s" msgstr "輸出資料集將具有與 %s 相同的影格數量" #: ../src/amitk_data_set.c:5598 #, c-format msgid "Can't handle studies with different numbers of gates, will use all gates of %s and the first gate of %s " msgstr "無法處理具備不同閘口數量的檢驗,將使用 %s 的所有閘口以及 %s 的第一個閘口" #: ../src/amitk_data_set.c:5606 #, c-format msgid "couldn't allocate %d MB for the output_ds data set structure" msgstr "無法配置 %d MB 給 output_ds 資料集結構" #. set a new name for this guy #: ../src/amitk_data_set.c:5623 #, c-format msgid "Result: %s %s %s" msgstr "結果:%s %s %s" #: ../src/amitk_data_set.c:5630 #, c-format msgid "Performing math operation" msgstr "施行數學運算" #: ../src/amitk_data_set.c:5684 msgid "couldn't generate slices from the data set..." msgstr "無法產生切片自資料集…" #: ../src/amitk_data_set_variable_type.c:110 msgid "couldn't allocate memory space for the data set structure to hold distribution data" msgstr "無法配置記憶體空間給資料集結構以存放發布資料" #: ../src/amitk_data_set_variable_type.c:118 #, c-format msgid "" "Generating distribution data for:\n" " %s" msgstr "" "產生發布資料自:\n" " %s" #: ../src/amitk_data_set_variable_type.c:233 #, c-format msgid "couldn't allocate memory space for the slice, wanted %dx%dx%d elements" msgstr "無法配置記憶體空間給切片,需要 %dx%dx%d 元素" #: ../src/amitk_filter.c:61 msgid "couldn't allocate memory space for the kernel structure" msgstr "無法配置記憶體空間給內核結構" #: ../src/amitk_filter.c:73 msgid "Couldn't allocate memory space for the kernel data" msgstr "無法配置記憶體空間給內核資料" #: ../src/amitk_object.c:633 msgid "AMIDE xml file doesn't appear to have a root." msgstr "AMIDE xml 檔案不具備根項目。" #: ../src/amitk_object_dialog.c:157 #, c-format msgid "Copy of %s" msgstr "%s 的複本" #: ../src/amitk_object_dialog.c:238 msgid "Basic Info" msgstr "基本資訊" #: ../src/amitk_object_dialog.c:246 msgid "Data Set Name:" msgstr "資料集名稱:" #: ../src/amitk_object_dialog.c:248 msgid "Name:" msgstr "名稱:" #. widgets to change the object's type #: ../src/amitk_object_dialog.c:268 msgid "Type:" msgstr "類型:" #. widgets to change the date of the scan name #: ../src/amitk_object_dialog.c:319 msgid "Scan Date:" msgstr "掃描日期:" #. widgets to change the object's modality #: ../src/amitk_object_dialog.c:332 msgid "Modality:" msgstr "造影:" #. widget to change the interpolation #: ../src/amitk_object_dialog.c:348 msgid "Interpolation Type" msgstr "內插法類型" #. widgets to change the subject name associated with the data #: ../src/amitk_object_dialog.c:416 msgid "Subject Name:" msgstr "主題名稱:" #. widgets to change the id associated with the data #: ../src/amitk_object_dialog.c:430 msgid "Subject ID:" msgstr "主題識別號:" #. widgets to change the subject's date of birth #: ../src/amitk_object_dialog.c:443 msgid "Subject DOB:" msgstr "主題 DOB:" #. widgets to change the subject's orientation #: ../src/amitk_object_dialog.c:458 msgid "Subject Orientation:" msgstr "主題方向:" #. widgets to change the subject's sex (much easier in the virtual world than in real life) #: ../src/amitk_object_dialog.c:473 msgid "Subject Sex:" msgstr "主題性別:" #. widget to change the scaling factor #: ../src/amitk_object_dialog.c:501 msgid "Conversion Type:" msgstr "轉換類型:" #: ../src/amitk_object_dialog.c:535 msgid "Scaling Factor:" msgstr "縮放因子:" #. injected dose #: ../src/amitk_object_dialog.c:562 msgid "Injected Dose:" msgstr "注射劑量:" #. subject weight #: ../src/amitk_object_dialog.c:594 msgid "Subject Weight:" msgstr "主題重量:" #. cylinder factor #: ../src/amitk_object_dialog.c:626 msgid "Cylinder Factor:" msgstr "柱面因子:" #. widgets to change the study's creation date #: ../src/amitk_object_dialog.c:663 msgid "Creation Date:" msgstr "建立日期:" #: ../src/amitk_object_dialog.c:703 msgid "View Center" msgstr "檢視中心" #: ../src/amitk_object_dialog.c:712 msgid "View Center (mm from origin)" msgstr "檢視中心 (從原點起算公釐數)" #: ../src/amitk_object_dialog.c:714 msgid "Center Location (mm from origin)" msgstr "中心位置 (從原點起算公釐數)" #: ../src/amitk_object_dialog.c:779 msgid "Voxel Size" msgstr "體素大小" #: ../src/amitk_object_dialog.c:783 msgid "Voxel Size (mm)" msgstr "體素大小 (公釐)" #: ../src/amitk_object_dialog.c:837 msgid "Dimensions" msgstr "維度" #. widgets to change the dimensions of the objects (in object's space) #: ../src/amitk_object_dialog.c:842 msgid "Dimensions (mm) wrt to ROI" msgstr "維度 (公釐) wrt 到 ROI" #: ../src/amitk_object_dialog.c:887 msgid "Rotate" msgstr "旋轉" #: ../src/amitk_object_dialog.c:902 msgid "Colormap/Threshold" msgstr "顏色對照表/臨界值" #. start making the page to adjust time values #: ../src/amitk_object_dialog.c:919 msgid "Time" msgstr "時間" #. scan start time..... #: ../src/amitk_object_dialog.c:927 msgid "Scan Start Time (s)" msgstr "掃描起始時間 (秒)" #. frame duration(s).... #: ../src/amitk_object_dialog.c:953 ../src/tb_roi_analysis.c:85 msgid "Frame" msgstr "影格" #: ../src/amitk_object_dialog.c:958 ../src/tb_roi_analysis.c:86 msgid "Duration (s)" msgstr "持續時間 (s)" #: ../src/amitk_object_dialog.c:1017 ../src/ui_preferences_dialog.c:328 msgid "ROI/View Preferences" msgstr "ROI/檢視偏好設定" #. AMITK_IS_DATA_SET #: ../src/amitk_object_dialog.c:1019 msgid "Windowing Preferences" msgstr "視窗偏好設定" #: ../src/amitk_object_dialog.c:1104 msgid "Immutables" msgstr "不可變的" #: ../src/amitk_object_dialog.c:1110 msgid "Max-Min Voxel Dim" msgstr "最大-最小的體素維度" #: ../src/amitk_object_dialog.c:1126 msgid "Isocontour Min Specified Value" msgstr "輪廓面最小指定值" #: ../src/amitk_object_dialog.c:1139 msgid "Isocontour Max Specified Value" msgstr "輪廓面最大指定值" #: ../src/amitk_object_dialog.c:1180 msgid "Memory Used (GB):" msgstr "已用記憶體 (GB):" #: ../src/amitk_object_dialog.c:1183 msgid "Memory Used (MB):" msgstr "已用記憶體 (MB):" #: ../src/amitk_object_dialog.c:1186 msgid "Memory Used (KB):" msgstr "已用記憶體 (KB):" #: ../src/amitk_object_dialog.c:1190 msgid "Memory Used (bytes):" msgstr "已用記憶體 (位元組):" #. widget to tell you the internal data format #: ../src/amitk_object_dialog.c:1209 msgid "Data Format:" msgstr "資料格式:" #. widget to tell you the scaling format #: ../src/amitk_object_dialog.c:1232 msgid "Scale Format:" msgstr "伸縮格式:" #. widgets to display the data set dimensions #: ../src/amitk_object_dialog.c:1255 msgid "Data Set Dimensions (voxels)" msgstr "資料集維度 (體素)" #. MRI parameters #: ../src/amitk_object_dialog.c:1290 msgid "MRI Parameters" msgstr "MRI 參數" #. inversion time #: ../src/amitk_object_dialog.c:1299 msgid "Inversion Time (ms):" msgstr "反逆時間 (ms):" #. echo time #: ../src/amitk_object_dialog.c:1317 msgid "Echo Time (ms):" msgstr "回應時間 (ms):" #: ../src/amitk_object_dialog.c:2381 #, c-format msgid "Modification Dialog: %s\n" msgstr "修改對話框:%s\n" #: ../src/amitk_point.c:90 #, c-format msgid "Couldn't read value for %s, substituting [%5.3f %5.3f %5.3f]" msgstr "無法讀取 %s 的數值,正在替代 [%5.3f %5.3f %5.3f]" #: ../src/amitk_point.c:180 #, c-format msgid "Couldn't read value for %s, substituting [%d %d %d %d %d]" msgstr "無法讀取 %s 的數值,正在替代 [%d %d %d %d %d]" #: ../src/amitk_point.c:188 #, c-format msgid "Couldn't read gate value for %s, substituting %d" msgstr "無法讀取 %s 的數值,正在替代 %d" #: ../src/amitk_point.c:192 #, c-format msgid "Couldn't read frame value for %s, substituting %d" msgstr "無法讀取 %s 的影格值,正在替代 %d" #: ../src/amitk_preferences.c:57 msgid "None" msgstr "無" #: ../src/amitk_preferences.c:58 msgid "Specified Directory" msgstr "指定目錄" #: ../src/amitk_preferences.c:59 msgid "Working Directory" msgstr "工作目錄" #: ../src/amitk_progress_dialog.c:165 msgid "Progress Dialog" msgstr "進度對話框" #: ../src/amitk_raw_data.c:62 ../src/amitk_raw_data.c:141 msgid "Unsigned Byte (8 bit)" msgstr "無正負號位元組 (8 位元)" #: ../src/amitk_raw_data.c:63 ../src/amitk_raw_data.c:142 msgid "Signed Byte (8 bit)" msgstr "帶正負號位元組 (8 位元)" #: ../src/amitk_raw_data.c:64 msgid "Unsigned Short (16 bit)" msgstr "無正負號短整數 (16 位元)" #: ../src/amitk_raw_data.c:65 msgid "Signed Short (16 bit)" msgstr "帶正負號短整數 (16 位元)" #: ../src/amitk_raw_data.c:66 msgid "Unsigned Integer (32 bit)" msgstr "無正負號整數 (32 位元)" #: ../src/amitk_raw_data.c:67 msgid "Signed Integer (32 bit)" msgstr "帶正負號整數 (32 位元)" #: ../src/amitk_raw_data.c:68 msgid "Float (32 bit)" msgstr "浮點數 (32 位元)" #: ../src/amitk_raw_data.c:69 msgid "Double (64 bit)" msgstr "倍精度浮點數 (64 位元)" #: ../src/amitk_raw_data.c:143 msgid "Unsigned Short, Little Endian (16 bit)" msgstr "無正負號短整數,低位在前 (16 位元)" #: ../src/amitk_raw_data.c:144 msgid "Signed Short, Little Endian (16 bit)" msgstr "帶正負號短整數,低位在前 (16 位元)" #: ../src/amitk_raw_data.c:145 msgid "Unsigned Integer, Little Endian (32 bit)" msgstr "無正負號整數,低位在前 (32 位元)" #: ../src/amitk_raw_data.c:146 msgid "Signed Integer, Little Endian (32 bit)" msgstr "帶正負號整數,低位在前 (32 位元)" #: ../src/amitk_raw_data.c:147 msgid "Float, Little Endian (32 bit)" msgstr "浮點數,低位在前 (32 位元)" #: ../src/amitk_raw_data.c:148 msgid "Double, Little Endian (64 bit)" msgstr "倍精度浮點數,低位在前 (64 位元)" #: ../src/amitk_raw_data.c:149 msgid "Unsigned Short, Big Endian (16 bit)" msgstr "無正負號短整數,高位在前 (16 位元)" #: ../src/amitk_raw_data.c:150 msgid "Signed Short, Big Endian (16 bit)" msgstr "帶正負號短整數,高位在前 (16 位元)" #: ../src/amitk_raw_data.c:151 msgid "Unsigned Integer, Big Endian (32 bit)" msgstr "無正負號整數,高位在前 (32 位元)" #: ../src/amitk_raw_data.c:152 msgid "Signed Integer, Big Endian (32 bit)" msgstr "帶正負號整數,高位在前 (32 位元)" #: ../src/amitk_raw_data.c:153 msgid "Float, Big Endian (32 bit)" msgstr "浮點數,高位在前 (32 位元)" #: ../src/amitk_raw_data.c:154 msgid "Double, Big Endian (64 bit)" msgstr "倍精度浮點數,高位在前 (64 位元)" #: ../src/amitk_raw_data.c:155 msgid "Unsigned Integer, PDP (32 bit)" msgstr "無正負號整數,PDP (32 位元)" #: ../src/amitk_raw_data.c:156 msgid "Signed Integer, PDP (32 bit)" msgstr "帶正負號整數,PDP (32 位元)" #: ../src/amitk_raw_data.c:157 msgid "Float, PDP/VAX (32 bit)" msgstr "浮點數,PDP/VAX (32 位元)" #: ../src/amitk_raw_data.c:158 msgid "ASCII (8 bit)" msgstr "ASCII (8 位元)" #: ../src/amitk_raw_data.c:361 #, c-format msgid "Reading: %s" msgstr "讀取:%s" #: ../src/amitk_raw_data.c:370 msgid "couldn't allocate memory space for the raw data set structure" msgstr "無法配置記憶體空間給原始資料集結構" #: ../src/amitk_raw_data.c:378 ../src/amitk_raw_data.c:383 #, c-format msgid "couldn't open raw data file %s" msgstr "無法開啟原始資料檔案 %s" #. EOF is usually -1 #: ../src/amitk_raw_data.c:396 #, c-format msgid "could not step forward %d elements in raw data file:\n\treturned error: %d" msgstr "無法在原始資料檔案中逐一讀取 %d 項元素:\n\t回傳的錯誤:%d" #: ../src/amitk_raw_data.c:402 #, c-format msgid "could not seek forward %ld bytes in raw data file" msgstr "無法在原始資料檔案中逐一尋指 %ld 位元組" #: ../src/amitk_raw_data.c:411 #, c-format msgid "couldn't malloc %zd bytes for file buffer\n" msgstr "無法配置 %zd 位元組給檔案緩衝區\n" #: ../src/amitk_raw_data.c:434 #, c-format msgid "read wrong # of elements from raw data, expected %zd, got %zd" msgstr "從原始資料讀取了錯誤的元素數量,預期 %zd 卻得到 %zd" #. EOF = -1 (usually) #: ../src/amitk_raw_data.c:458 #, c-format msgid "could not read ascii file after %d elements, file or parameters are erroneous" msgstr "於 %d 元素之後無法讀取 ASCII 檔案,檔案或參數有誤" #: ../src/amitk_raw_data.c:829 #, c-format msgid "couldn't save raw data file: %s" msgstr "無法儲存原始資料檔案:%s" #: ../src/amitk_raw_data.c:857 #, c-format msgid "incomplete save of raw data, wrote %zd (bytes), needed %zd (bytes), file: %s" msgstr "原始資料的儲存不完整,已寫入 %zd (位元組),所需要 %zd (位元組),檔案:%s" #: ../src/amitk_raw_data.c:931 #, c-format msgid "Raw data xml file doesn't appear to have a root: %s" msgstr "原始資料 xml 檔案似乎沒有根項目:%s" #: ../src/amitk_raw_data.c:972 ../src/xml.c:672 ../src/xml.c:678 msgid "File to large to read on 32bit platform." msgstr "檔案對於在 32 位元平臺上讀取而言過大。" #: ../src/amitk_roi.c:44 msgid "_Ellipsoid" msgstr "橢圓體(_E)" #: ../src/amitk_roi.c:45 msgid "Elliptic _Cylinder" msgstr "橢圓柱面(_C)" #: ../src/amitk_roi.c:46 msgid "_Box" msgstr "方框(_B)" #: ../src/amitk_roi.c:47 msgid "_2D Isocontour" msgstr "平面輪廓(_2)" #: ../src/amitk_roi.c:48 msgid "_3D Isocontour" msgstr "立體輪廓(_3)" #: ../src/amitk_roi.c:49 msgid "_2D Freehand" msgstr "平面手繪(_2)" #: ../src/amitk_roi.c:50 msgid "_3D Freehand" msgstr "立體手繪(_3)" #: ../src/amitk_roi.c:54 msgid "Add a new elliptical ROI" msgstr "加入新的橢圓 ROI" #: ../src/amitk_roi.c:55 msgid "Add a new elliptic cylinder ROI" msgstr "加入新的橢圓柱面 ROI" #: ../src/amitk_roi.c:56 msgid "Add a new box shaped ROI" msgstr "加入新的方框 ROI" #: ../src/amitk_roi.c:57 msgid "Add a new 2D Isocontour ROI" msgstr "加入新的平面輪廓 ROI" #: ../src/amitk_roi.c:58 msgid "Add a new 3D Isocontour ROI" msgstr "加入新的立體輪廓 ROI" #: ../src/amitk_roi.c:59 msgid "Add a new 2D Freehand ROI" msgstr "加入新的平面手繪 ROI" #: ../src/amitk_roi.c:60 msgid "Add a new 3D Freehand ROI" msgstr "加入新的立體手繪 ROI" #: ../src/amitk_roi_variable_type.c:59 ../src/amitk_roi_variable_type.c:71 msgid "Out of Memory" msgstr "記憶體不足" #. and a display of the current axis #: ../src/amitk_space_edit.c:145 msgid "i" msgstr "i" #: ../src/amitk_space_edit.c:148 msgid "j" msgstr "j" #: ../src/amitk_space_edit.c:151 msgid "k" msgstr "k" #: ../src/amitk_space_edit.c:186 msgid "data set axis:" msgstr "資料集軸線:" #. button to apply entries #: ../src/amitk_space_edit.c:192 msgid "apply manual entries" msgstr "套用手動項目" #. button to reset the axis #: ../src/amitk_space_edit.c:200 msgid "reset to identity" msgstr "重置為相同" #. our AIR buttons #: ../src/amitk_space_edit.c:216 msgid "AIR Files:" msgstr "AIR 檔案:" #: ../src/amitk_space_edit.c:221 msgid "Apply .AIR" msgstr "套用 .AIR" #: ../src/amitk_space_edit.c:228 msgid "Export .AIR" msgstr "匯出 .AIR" #. first double check that we really want to do this #: ../src/amitk_space_edit.c:362 msgid "" "Do you really wish to manual set the axis?\n" "This may flip left/right relationships" msgstr "" "您真的希望手動設定軸線嗎?\n" "這也許會翻轉左/右關係" #. first double check that we really want to do this #: ../src/amitk_space_edit.c:392 msgid "" "Do you really wish to reset the axis to identity?\n" "This may flip left/right relationships" msgstr "" "您真的希望重置軸線為相同嗎?\n" "這也許會翻轉左/右關係" #. first double check that we really want to do this #: ../src/amitk_space_edit.c:416 msgid "" "Do you really wish to invert?\n" "This will flip left/right relationships" msgstr "" "您真的希望反轉嗎?\n" "這將會翻轉左/右關係" #: ../src/amitk_study.c:469 #, c-format msgid "inappropriate zoom (%5.3f) for study, reseting to 1.0" msgstr "不適當的縮放 (%5.3f) 用於檢驗,重置為 1.0" #: ../src/amitk_study.c:907 ../src/amitk_study.c:1008 #: ../src/amitk_study.c:1135 #, c-format msgid "Couldn't open file %s\n" msgstr "無法開啟檔案 %s\n" #: ../src/amitk_study.c:968 msgid "The above warnings may arise because portions of the XIF" msgstr "以上的警告也許會因為部分 XIF 而發生" #: ../src/amitk_study.c:969 msgid "file were corrupted." msgstr "檔案已損壞。" #: ../src/amitk_study.c:1002 msgid "Couldn't change directories in loading study" msgstr "無法在載入檢驗時變更目錄" #: ../src/amitk_study.c:1020 msgid "File is corrupt. The file may have been incompletely saved. You can attempt recovering the file by using the recover function under the file menu." msgstr "檔案損壞。檔案儲存也許不完整。您可以藉由使用檔案選單之下的回復功能來嘗試回復檔案。" #: ../src/amitk_study.c:1037 msgid "The above warnings most likely indicate changes to the" msgstr "以上的警告很有可能指出變更發生於" #: ../src/amitk_study.c:1038 msgid "XIF file format, please resave the data as soon as possible." msgstr "XIF 檔案格式,請儘快重新儲存資料。" #: ../src/amitk_study.c:1050 ../src/amitk_study.c:1149 msgid "Couldn't return to previous directory in load study" msgstr "無法在載入檢驗時回到上一個目錄" #: ../src/amitk_study.c:1089 ../src/amitk_study.c:1101 #, c-format msgid "Couldn't unlink file: %s" msgstr "無法取消鏈結檔案:%s" #: ../src/amitk_study.c:1095 #, c-format msgid "Couldn't remove directory: %s" msgstr "無法移除目錄:%s" #: ../src/amitk_study.c:1106 #, c-format msgid "Unrecognized file type for file: %s, couldn't delete" msgstr "無法辨識的檔案類型之於檔案:%s,無法刪除" #: ../src/amitk_study.c:1116 #, c-format msgid "Couldn't create amide directory: %s" msgstr "無法建立 amide 目錄:%s" #: ../src/amitk_study.c:1130 msgid "Couldn't change directories in writing study, study not saved" msgstr "無法在寫入檢驗時變更目錄,檢驗並未儲存" #: ../src/amitk_threshold.c:49 msgid "per slice" msgstr "各切片" #: ../src/amitk_threshold.c:50 msgid "per frame" msgstr "各影格" #: ../src/amitk_threshold.c:51 msgid "interpolated between frames" msgstr "已在影格之間添寫" #: ../src/amitk_threshold.c:52 msgid "global" msgstr "全域" #: ../src/amitk_threshold.c:56 msgid "Min/Max" msgstr "最小/最大" #: ../src/amitk_threshold.c:57 msgid "Center/Width" msgstr "中心/寬度" #: ../src/amitk_threshold.c:64 msgid "threshold the images based on the max and min values in the current slice" msgstr "臨界處理影像,基於目前切片中的最大和最小值" #: ../src/amitk_threshold.c:65 msgid "threshold the images based on the max and min values in the current frame" msgstr "臨界處理影像,基於目前影格中的最大和最小值" #: ../src/amitk_threshold.c:66 msgid "threshold the images based on max and min values interpolated from the reference frame thresholds" msgstr "臨界處理影像,基於從參考影格臨界值所添寫的最大和最小值" #: ../src/amitk_threshold.c:67 msgid "threshold the images based on the max and min values of the entire data set" msgstr "臨界處理影像,基於目前影格中的最大和最小值" #: ../src/amitk_threshold.c:71 msgid "threshold by setting min and max values - Nuclear Medicine Style" msgstr "依照最小和最大設定臨界值 - 核子醫學樣式" #: ../src/amitk_threshold.c:72 msgid "theshold by setting a window center and width - Radiology Style" msgstr "由視窗中心和寬度設定臨界值 - 放射線科樣式" #: ../src/amitk_threshold.c:328 msgid "Percent" msgstr "百分比" #: ../src/amitk_threshold.c:392 msgid "Color Table:" msgstr "顏色表格:" #: ../src/amitk_threshold.c:394 #, c-format msgid "Color Table %d:" msgstr "顏色表格 %d:" #: ../src/amitk_threshold.c:415 ../src/amitk_threshold.c:419 msgid "if not enabled, the primary color table will be used for this set of views" msgstr "如果未啟用,主要的顏色表格將用於這個檢視集合" #: ../src/amitk_threshold.c:418 msgid "enable color table" msgstr "啟用顏色表格" #. threshold type selection #: ../src/amitk_threshold.c:435 msgid "Threshold Type" msgstr "臨界值類型" #. threshold type selection #: ../src/amitk_threshold.c:496 ../src/ui_preferences_dialog.c:433 msgid "Threshold Style" msgstr "臨界值樣式" #. color table selector #: ../src/amitk_threshold.c:558 msgid "ref. frame 0:" msgstr "參考影格 0:" #. show/hide taken care of by threshold_update_layout #: ../src/amitk_threshold.c:563 msgid "ref. frame 1:" msgstr "參考影格 1:" #: ../src/amitk_threshold.c:587 msgid "distribution" msgstr "發布" #: ../src/amitk_threshold.c:595 msgid "full" msgstr "全螢幕" #. show/hide taken care of by threshold_update_layout #: ../src/amitk_threshold.c:601 msgid "scaled" msgstr "伸縮" #: ../src/amitk_threshold.c:743 msgid "Threshold has no style?\n" msgstr "臨界值沒有任何樣式?\n" #: ../src/amitk_threshold.c:1293 msgid "Max Threshold" msgstr "最大臨界值" #: ../src/amitk_threshold.c:1294 msgid "Min Threshold" msgstr "最小臨界值" #: ../src/amitk_threshold.c:1351 msgid "Absolute" msgstr "絕對" #. reset the title #: ../src/amitk_threshold.c:2133 ../src/amitk_threshold.c:2173 #, c-format msgid "Data Set: %s\n" msgstr "資料集:%s\n" #: ../src/amitk_threshold.c:2152 ../src/amitk_threshold.c:2293 msgid "Threshold Dialog" msgstr "臨界值對話框" #: ../src/analysis.c:217 #, c-format msgid "couldn't allocate memory space for data array for frame %d/gate %d" msgstr "無法配置記憶體空間給影格 %d/閘口 %d 的資料陣列" #: ../src/analysis.c:287 #, c-format msgid "couldn't allocate memory space for roi analysis of frame %d/gate %d" msgstr "無法配置記憶體空間給影格 %d/閘口 %d 的 roi 分析" #: ../src/analysis.c:424 msgid "couldn't allocate memory space for roi analysis of frames" msgstr "無法配置記憶體空間給影格的 roi 分析" #: ../src/analysis.c:455 #, c-format msgid "ROI: %s appears not to have been drawn" msgstr "ROI:%s 似乎未被繪出" #: ../src/analysis.c:511 msgid "couldn't allocate memory space for roi analysis of volumes" msgstr "無法配置記憶體空間給體積的 roi 分析" #: ../src/analysis.c:583 msgid "couldn't allocate memory space for roi analyses" msgstr "無法配置記憶體空間給 roi 分析" #: ../src/dcmtk_interface.cc:140 ../src/dcmtk_interface.cc:1474 #, c-format msgid "could not find dataset in DICOM file %s\n" msgstr "在 DICOM 檔案 %s 中找不到資料集\n" #: ../src/dcmtk_interface.cc:150 #, c-format msgid "Modality %s is not understood. Ignoring File %s" msgstr "成像方式 %s 無法理解。 忽略檔案 %s" #: ../src/dcmtk_interface.cc:182 #, c-format msgid "could not find # of columns - Failed to load file %s\n" msgstr "找不到欄數 - 無法載入檔案 %s\n" #: ../src/dcmtk_interface.cc:188 #, c-format msgid "could not find # of rows - Failed to load file %s\n" msgstr "找不到列數 - 無法載入檔案 %s\n" #: ../src/dcmtk_interface.cc:235 #, c-format msgid "could not find # of bits allocated - Failed to load file %s\n" msgstr "找不到配置的位元數 - 無法載入檔案 %s\n" #: ../src/dcmtk_interface.cc:241 #, c-format msgid "could not find pixel representation - Failed to load file %s\n" msgstr "找不到像素表示方式 - 無法載入檔案 %s\n" #: ../src/dcmtk_interface.cc:261 #, c-format msgid "unsupported # of bits allocated (%d) - Failed to load file %s\n" msgstr "不受支援的配置位元數 (%d) - 無法載入檔案 %s\n" #: ../src/dcmtk_interface.cc:268 #, c-format msgid "Couldn't allocate space for the data set structure to hold DCMTK data - Failed to load file %s" msgstr "無法配置記憶體空間給資料集結構以存放 DCMTK 資料 - 無法載入檔案 %s" #: ../src/dcmtk_interface.cc:286 #, c-format msgid "Could not find the pixel size, setting to 1 mm for File %s" msgstr "找不到像素大小,設定為 1 公釐用於檔案 %s" #: ../src/dcmtk_interface.cc:298 #, c-format msgid "Could not find the slice thickness, setting to 1 mm for File %s" msgstr "找不到切片粗細,設定為 1 公釐用於檔案 %s" #: ../src/dcmtk_interface.cc:612 #, c-format msgid "error reading in pixel data - DCMTK error: %s - Failed to read file %s" msgstr "讀入像素資料 - DCMTK 錯誤時發生錯誤:%s - 無法讀取檔案 %s" #: ../src/dcmtk_interface.cc:890 #, c-format msgid "Cannot evenly divide the number of slices by the number of frames for data set %s - ignoring dynamic data" msgstr "無法由影格數量平衡劃分資料集 %s 中的切片數量 - 忽略動態資料" #: ../src/dcmtk_interface.cc:899 #, c-format msgid "Cannot evenly divide the number of slices by the number of gates for data set %s - ignoring gated data" msgstr "無法由閘口數量平衡劃分資料集 %s 中的切片數量 - 忽略閘口資料" #: ../src/dcmtk_interface.cc:945 msgid "couldn't allocate space for the frame duration info" msgstr "無法配置記憶體空間給影格持續時間資訊" #: ../src/dcmtk_interface.cc:1028 #, c-format msgid "Detected discontinous frames in data set %s - frame start times will be incorrect" msgstr "在資料集 %s 中偵測到不連續的影格 - 影格起始時間將不正確" #: ../src/dcmtk_interface.cc:1031 #, c-format msgid "Slice thickness (%5.3f mm) not equal to slice spacing (%5.3f mm) in data set %s - will use slice spacing for thickness" msgstr "在資料集 %3$s 中切片粗細 (%1$5.3f 公釐) 不等於切片間隔 (%2$5.3f 公釐) - 將切片間隔做為切片粗細使用" #: ../src/dcmtk_interface.cc:1217 msgid "Importing File(s) Through DCMTK" msgstr "透過 DCMTK 匯入檔案" #. can handle multiple dicom files each with a single slice, or one dicom file with multiple slices, #. can't handle multiple files each with multiple slices #: ../src/dcmtk_interface.cc:1236 msgid "no support for multislice files within DICOM directory format" msgstr "在 DICOM 目錄格式之內不支援多重切片檔案" #: ../src/dcmtk_interface.cc:1482 msgid "Scanning Files to find additional DICOM Slices" msgstr "掃描檔案以尋找額外的 DICOM 切片" #: ../src/dcmtk_interface.cc:1553 msgid "Multiple data sets were found in the same directory as the specified file. In addition to the dataset corresponding to the specified file, would you like to load in these additional datasets?" msgstr "在相同目錄中找到了多重資料集做為指定的檔案。在相應於指定檔案的資料集以外,您也想要載入這些額外資料集?" #: ../src/dcmtk_interface.cc:1746 msgid "Could not find a DICOM Data Dictionary. Reading may fail. Consider defining the environmental variable DCMDICTPATH to the dicom.dic file." msgstr "找不到 DICOM 資料辭典。 讀取也許會失敗。 請考慮定義環境變數 DCMDICTPATH 為 dicom.dic 檔案。" #: ../src/dcmtk_interface.cc:1751 #, c-format msgid "could not read DICOM file %s, dcmtk returned %s" msgstr "無法讀取 DICOM 檔案 %s,dcmtk 回傳了 %s" #: ../src/dcmtk_interface.cc:1991 #, c-format msgid "File already exists with name: %s" msgstr "檔案已存在且名為:%s" #: ../src/dcmtk_interface.cc:1997 ../src/dcmtk_interface.cc:2040 #, c-format msgid "Couldn't create directory: %s" msgstr "無法建立目錄:%s" #: ../src/dcmtk_interface.cc:2006 #, c-format msgid "Existing DICOMDIR file %s is not a regular file" msgstr "現有 DICOMDIR 檔案 %s 並非標準檔案" #: ../src/dcmtk_interface.cc:2011 #, c-format msgid "Existing DICOMDIR file %s exists but is not appendable, error %s" msgstr "現有 DICOMDIR 檔案 %s 存在但是無法附加,錯誤 %s" #: ../src/dcmtk_interface.cc:2017 #, c-format msgid "Could not create DICOMDIR file %s, error %s" msgstr "無法建立 DICOMDIR 檔案 %s,錯誤 %s" #: ../src/dcmtk_interface.cc:2073 ../src/libmdc_interface.c:981 #, c-format msgid "dimensions of output data set will be %dx%dx%d, voxel size of %fx%fx%f" msgstr "輸出資料集的維度將是 %dx%dx%d,體素大小為 %fx%fx%f" #: ../src/dcmtk_interface.cc:2329 #, c-format msgid "" "Exporting File Through DCMTK:\n" " %s" msgstr "" "透過 DCMTK 匯出檔案:\n" " %s" #: ../src/dcmtk_interface.cc:2372 msgid "Could not malloc transfer buffer" msgstr "無法配置記憶體給轉送緩衝區" #: ../src/dcmtk_interface.cc:2471 #, c-format msgid "couldn't write out file %s, error %s" msgstr "無法寫出檔案 %s,錯誤 %s" #: ../src/dcmtk_interface.cc:2478 #, c-format msgid "couldn't append file %s to DICOMDIR %s, error %s" msgstr "無法附加檔案 %s 到 DICOMDIR %s,錯誤 %s" #: ../src/dcmtk_interface.cc:2514 #, c-format msgid "Failed to write DICOMDIR file, error %s\n" msgstr "寫入 DICOMDIR 檔案時失敗,錯誤 %s\n" #. N_("Steepest Descent"), #: ../src/fads.c:40 msgid "Fletcher-Reeves conjugate gradient" msgstr "Fletcher-Reeves 共軛梯度" #: ../src/fads.c:41 msgid "Polak-Ribiere conjugate gradient" msgstr "Polak-Ribiere 共軛梯度" #: ../src/fads.c:47 msgid "Principle Component Analysis" msgstr "主成分分析" #: ../src/fads.c:48 msgid "Penalized Least Squares Factor Analysis" msgstr "受罰最小平方因素分析" #: ../src/fads.c:49 msgid "2 compartment model" msgstr "二室模型" #: ../src/fads.c:53 msgid "Priniciple Component Analysis based on singular value decomposition." msgstr "基於單值分解的主成分分析。" #: ../src/fads.c:56 msgid "Principle component analysis with positivity constraints and a penalized least squares objective, an adaptation of Sitek, et al., IEEE Trans. Med. Imag., 2002. If beta is set to zero, this is normal factor analysis, similar to Di Paola, et al., IEEE Trans. Nuc. Sci., 1982" msgstr "主成分分析具備正向限制和受罰最小平方目的,是參考修改自 Sitek, et al., IEEE Trans. Med. Imag., 2002. If beta is set to zero, this is normal factor analysis, similar to Di Paola, et al., IEEE Trans. Nuc. Sci., 1982" #: ../src/fads.c:62 msgid "Standard 2 compartment model" msgstr "標準二室模型" #: ../src/fads.c:109 msgid "need dynamic data set in order to perform factor analysis" msgstr "需要動態資料集以便施行因素分析" #: ../src/fads.c:115 ../src/fads.c:120 ../src/fads.c:271 #, c-format msgid "Failed to allocate %dx%d array" msgstr "配置 %dx%d 陣列時失敗" #: ../src/fads.c:125 ../src/fads.c:276 #, c-format msgid "Failed to allocate %d vector" msgstr "配置 %d 向量時失敗" #: ../src/fads.c:157 #, c-format msgid "Failed to allocate %d factor array" msgstr "配置 %d 因子陣列時失敗" #: ../src/fads.c:266 #, c-format msgid "failed to alloc matrix, size %dx%d" msgstr "配置矩陣時失敗,大小為 %dx%d" #: ../src/fads.c:311 ../src/fads.c:338 #, c-format msgid "failed to alloc matrix size %dx%d" msgstr "配置矩陣大小 %dx%d 時失敗" #: ../src/fads.c:325 #, c-format msgid "failed to alloc vector size %d" msgstr "配置向量大小 %d 時失敗" #: ../src/fads.c:398 ../src/fads.c:1207 ../src/fads.c:2178 msgid "failed to allocate new_ds" msgstr "配置 new_ds 時失敗" #: ../src/fads.c:429 #, c-format msgid "couldn't open: %s for writing PCA analyses" msgstr "無法開啟:%s 以寫入主成分分析" #: ../src/fads.c:941 msgid "failed forward error malloc" msgstr "轉寄錯誤配置失敗" #: ../src/fads.c:948 msgid "failed weight malloc" msgstr "權重配置失敗" #: ../src/fads.c:955 msgid "failed equality constraint alpha malloc" msgstr "對等限制 alpha 配置失敗" #: ../src/fads.c:961 msgid "failed equality constraint blood curve malloc" msgstr "對等限制血液曲線配置失敗" #: ../src/fads.c:967 ../src/fads.c:1938 msgid "failed malloc for equality lagrange multiplier - alpha" msgstr "對等 lagrange 倍增器配置失敗 - alpha" #: ../src/fads.c:975 ../src/fads.c:1946 msgid "failed malloc for equality lagrange multiplier - blood curve" msgstr "對等 lagrange 倍增器配置失敗 - 血液曲線" #: ../src/fads.c:983 ../src/fads.c:1954 msgid "failed malloc for inequality lagrange multiplier - alpha" msgstr "不對等 lagrange 倍增器配置失敗 - alpha" #: ../src/fads.c:992 msgid "failed malloc for inequailty lagrange multiplier - factors" msgstr "不對等 lagrange 倍增器配置失敗 - 因子" #: ../src/fads.c:1009 ../src/fads.c:2001 msgid "failed to allocate multidimensional minimizer" msgstr "配置多維度倍減器時失敗" #: ../src/fads.c:1080 #, c-format msgid "" "Calculating Penalized Least Squares Factor Analysis:\n" " %s" msgstr "" "計算受罰最小平方因素分析:\n" " %s" #: ../src/fads.c:1223 #, c-format msgid "factor %d" msgstr "因子 %d" #: ../src/fads.c:1241 ../src/fads.c:2216 #, c-format msgid "couldn't open: %s for writing fads analyses" msgstr "無法開啟:%s 用於寫入 fads 分析" #: ../src/fads.c:1890 msgid "failed to allocate intermediate data storage for tissue components" msgstr "配置中介資料儲存體給組織組成時失敗" #: ../src/fads.c:1896 msgid "failed to allocate intermediate data storage for forward error" msgstr "配置中介資料儲存體給轉寄錯誤時失敗" #: ../src/fads.c:1902 msgid "failed to allocate frame start array" msgstr "配置影格啟始陣列時失敗" #: ../src/fads.c:1908 msgid "failed to allocate frame end array" msgstr "配置影格結束陣列時失敗" #: ../src/fads.c:1914 msgid "failed to allocate frame midpt array" msgstr "配置影格中段陣列時失敗" #: ../src/fads.c:1926 msgid "failed malloc for equality constraint on alpha" msgstr "配置記憶體給 alpha 對等限制時失敗" #: ../src/fads.c:1932 msgid "failed malloc for equality constraint on blood curve" msgstr "配置記憶體給血液曲線對等限制時失敗" #: ../src/fads.c:1962 msgid "failed malloc for inequailty lagrange multiplier - blood curve" msgstr "配置記憶體給不對等 lagrange 倍增器時失敗 - 血液曲線" #: ../src/fads.c:1970 msgid "failed malloc for inequailty lagrange multiplier - k12" msgstr "配置記憶體給不對等 lagrange 倍增器時失敗 - k12" #: ../src/fads.c:1978 msgid "failed malloc for inequailty lagrange multiplier - k21" msgstr "配置記憶體給不對等 lagrange 倍增器時失敗 - k21" #: ../src/fads.c:2009 msgid "failed to allocate initial vector" msgstr "配置初始向量時失敗" #: ../src/fads.c:2039 #, c-format msgid "" "Calculating Two Compartment Factor Analysis:\n" " %s" msgstr "" "計算二室因素分析:\n" " %s" #: ../src/fads.c:2159 #, c-format msgid "Minimum found after %d iterations\n" msgstr "%d 次反覆運算之後找到最小值\n" #: ../src/fads.c:2161 #, c-format msgid "terminated minization \n" msgstr "最小化已終止\n" #: ../src/fads.c:2163 #, c-format msgid "No minimum found after %d iterations, exited with: %s\n" msgstr "%d 次反覆運算之後找不到最小值,離開狀態:%s\n" #: ../src/fads.c:2197 #, c-format msgid "tissue type %d: k12 %g k21 %g" msgstr "組織類型 %d:k12 %g k21 %g" #: ../src/fads.c:2199 #, c-format msgid "blood fraction" msgstr "血液成分" #: ../src/image.c:180 msgid "couldn't allocate memory for rgba_data for roi image" msgstr "無法配置記憶體給 rgba_data 用於 roi 影像" #: ../src/image.c:222 msgid "couldn't allocate memory for rgb_data for blank image" msgstr "無法配置記憶體給 rgb_data 用於空白影像" #: ../src/image.c:254 msgid "couldn't allocate memory for image from 8 bit data" msgstr "無法配置記憶體給八位元資料的影像" #: ../src/image.c:303 msgid "couldn't allocate memory for rgba16_data for transferring rendering to image" msgstr "無法配置記憶體給 rgba16_data 用於轉換潤算為影像" #: ../src/image.c:380 msgid "couldn't allocate memory for char_data for rendering image" msgstr "無法配置記憶體給 char_data 用於潤算影像" #: ../src/image.c:427 msgid "couldn't allocate memory for rgba_data for bar_graph" msgstr "無法配置記憶體給 rgba_data 用於 bar_graph" #: ../src/image.c:502 msgid "couldn't allocate memory for rgb_data for color_strip" msgstr "無法配置記憶體給 rgb_data 用於 color_strip" #: ../src/image.c:557 msgid "couldn't allocate memory for rgba_data for projection image" msgstr "無法配置記憶體給 rgba_data 用於投影影像" #: ../src/image.c:608 msgid "couldn't allocate memory for rgba_data for slice image" msgstr "無法配置記憶體給 rgba_data 用於切片影像" #: ../src/libecat_interface.c:35 msgid "Unknown Data Type" msgstr "不明資料類型" #. UnknownMatDataType #: ../src/libecat_interface.c:36 msgid "Byte" msgstr "位元組" #. ByteData #: ../src/libecat_interface.c:37 msgid "Short (16 bit), Little Endian" msgstr "短整數 (16 位元),低位在前" #. VAX_Ix2 #: ../src/libecat_interface.c:38 msgid "Integer (32 bit), Little Endian" msgstr "整數 (32 位元),低位在前" #. VAX_Ix4 #: ../src/libecat_interface.c:39 msgid "VAX Float (32 bit)" msgstr "VAX 浮點數 (32 位元)" #. VAX_Rx4 #: ../src/libecat_interface.c:40 msgid "IEEE Float (32 bit)" msgstr "IEEE 浮點數 (32 位元)" #. IeeeFloat #: ../src/libecat_interface.c:41 msgid "Short (16 bit), Big Endian" msgstr "短整數 (16 位元),高位在前" #. SunShort #: ../src/libecat_interface.c:42 msgid "Integer (32 bit), Big Endian" msgstr "整數 (32 位元),高位在前" #: ../src/libecat_interface.c:87 #, c-format msgid "Can't open file %s using libecat" msgstr "無法利用 libecat 開啟檔案 %s" #: ../src/libecat_interface.c:111 #, c-format msgid "Don't know how to handle this CTI file type: %d" msgstr "不知道如何處理這個 CTI 檔案類型:%d" #: ../src/libecat_interface.c:121 #, c-format msgid "Libecat can't get header info at matrix %x in file %s" msgstr "Libecat 無法取得矩陣 %x 的標頭資訊於檔案 %s" #: ../src/libecat_interface.c:143 #, c-format msgid "No support for importing CTI files with data type of: %d (%s)" msgstr "不支援匯入具有資料類型:%d (%s) 的 CTI 檔案" #: ../src/libecat_interface.c:175 msgid "Couldn't allocate memory space for the data set structure to hold CTI data" msgstr "無法配置記憶體空間給資料集結構以存放 CTI 資料" #. handle corrupted cti files #: ../src/libecat_interface.c:281 msgid "Detected corrupted CTI file, will try to continue by guessing voxel_size" msgstr "偵測到損壞的 CTI 檔案,將會嘗試藉由猜測體素大小以繼續" #: ../src/libecat_interface.c:284 msgid "Detected zero voxel size in CTI file, will try to continue by guessing voxel_size" msgstr "在 CTI 檔案中偵測到零值體素大小,將會嘗試藉由猜測體素大小以繼續" #. handle corrupted cti files #: ../src/libecat_interface.c:294 msgid "Detected corrupted CTI file, will try to continue by guessing offset" msgstr "偵測到損壞的 CTI 檔案,將會嘗試藉由猜測偏移值以繼續" #: ../src/libecat_interface.c:323 #, c-format msgid "" "Importing CTI File:\n" " %s" msgstr "" "匯入 CTI 檔案:\n" " %s" #: ../src/libecat_interface.c:428 #, c-format msgid "Libecat returned %d blank planes... corrupted data file? Use data with caution." msgstr "Libecat 回傳 %d 個空白平面… 資料檔案已損壞? 使用資料請小心。" #: ../src/libmdc_interface.c:53 msgid "(_X)MedCon Guess" msgstr "(_X)MedCon 猜測" #: ../src/libmdc_interface.c:54 msgid "_GIF 87a/89a" msgstr "_GIF 87a/89a" #: ../src/libmdc_interface.c:55 msgid "Acr/_Nema 2.0" msgstr "Acr/_Nema 2.0" #: ../src/libmdc_interface.c:56 msgid "_Concorde/microPET" msgstr "_Concorde/microPET" #: ../src/libmdc_interface.c:57 msgid "ECAT _6 via (X)MedCon" msgstr "ECAT _6 透過 (X)MedCon" #: ../src/libmdc_interface.c:58 msgid "ECAT _7 via (X)MedCon" msgstr "ECAT _7 透過 (X)MedCon" #: ../src/libmdc_interface.c:59 msgid "_InterFile 3.3" msgstr "_InterFile 3.3" #: ../src/libmdc_interface.c:60 msgid "_Analyze (SPM)" msgstr "_Analyze (SPM)" #: ../src/libmdc_interface.c:61 msgid "_DICOM 3.0 via (X)MedCon" msgstr "_DICOM 3.0 透過 (X)MedCon" #: ../src/libmdc_interface.c:62 msgid "_NIFTI via (X)MedCon" msgstr "_NIFTI 透過 (X)MedCon" #: ../src/libmdc_interface.c:66 msgid "let (X)MedCon/libmdc guess file type" msgstr "讓 (X)MedCon/libmdc 猜測檔案類型" #: ../src/libmdc_interface.c:67 msgid "Import a file stored as GIF" msgstr "匯入儲存為 GIF 的檔案" #: ../src/libmdc_interface.c:68 msgid "Import a Acr/Nema 2.0 file" msgstr "匯入 Acr/Nema 2.0 檔案" #: ../src/libmdc_interface.c:69 msgid "Import a file from the Concorde microPET" msgstr "從 Concorde microPET 匯入檔案" #: ../src/libmdc_interface.c:70 msgid "Import a CTI/ECAT 6 file through (X)MedCon" msgstr "透過 (X)MedCon 匯入 CTI/ECAT 6 檔案" #: ../src/libmdc_interface.c:71 msgid "Import a CTI/ECAT 7 file through (X)MedCon" msgstr "透過 (X)MedCon 匯入 CTI/ECAT 7 檔案" #: ../src/libmdc_interface.c:72 msgid "Import a InterFile 3.3 file" msgstr "匯入 InterFile 3.3 檔案" #: ../src/libmdc_interface.c:73 msgid "Import an Analyze file" msgstr "匯入 Analyze 檔案" #: ../src/libmdc_interface.c:74 msgid "Import a DICOM 3.0 file through (X)MedCon" msgstr "透過 (X)MedCon 匯入 DICOM 3.0 檔案" #: ../src/libmdc_interface.c:75 msgid "Import a NIFTI file through (X)MedCon" msgstr "透過 (X)MedCon 匯入 NIFTI 檔案" #: ../src/libmdc_interface.c:89 msgid "Acr/Nema 2.0" msgstr "Acr/Nema 2.0" #: ../src/libmdc_interface.c:90 msgid "Concorde/microPET" msgstr "Concorde/microPET" #: ../src/libmdc_interface.c:91 msgid "ECAT 6 via (X)MedCon" msgstr "透過 (X)MedCon 匯入 ECAT 6 檔案" #: ../src/libmdc_interface.c:92 msgid "InterFile 3.3" msgstr "InterFile 3.3" #: ../src/libmdc_interface.c:93 msgid "Analyze (SPM)" msgstr "Analyze (SPM)" #: ../src/libmdc_interface.c:94 msgid "DICOM 3.0 via (X)MedCon" msgstr "DICOM 3.0 透過 (X)MedCon" #: ../src/libmdc_interface.c:95 msgid "NIFTI" msgstr "NIFTI" #: ../src/libmdc_interface.c:99 msgid "Export a Acr/Nema 2.0 file" msgstr "匯出 Acr/Nema 2.0 檔案" #: ../src/libmdc_interface.c:100 msgid "Export a Concorde format file" msgstr "匯出 Concorde 格式檔案" #: ../src/libmdc_interface.c:101 msgid "Export a CTI/ECAT 6 file" msgstr "匯出 CTI/ECAT 6 檔案" #: ../src/libmdc_interface.c:102 msgid "Export a InterFile 3.3 file" msgstr "匯出 InterFile 3.3 檔案" #: ../src/libmdc_interface.c:103 msgid "Export an Analyze file" msgstr "匯出 Analyze 檔案" #: ../src/libmdc_interface.c:104 msgid "Export a DICOM 3.0 file" msgstr "匯出 DICOM 3.0 檔案" #: ../src/libmdc_interface.c:105 msgid "Export a NIFTI file" msgstr "匯出 NIFTI 檔案" #: ../src/libmdc_interface.c:255 #, c-format msgid "Can't open file %s with libmdc/(X)MedCon" msgstr "無法以 libmdc/(X)MedCon 開啟檔案 %s" #: ../src/libmdc_interface.c:262 #, c-format msgid "Can't read file %s with libmdc/(X)MedCon" msgstr "無法以 libmdc/(X)MedCon 讀取檔案 %s" #. 9 #. 8 #. 11 #. 12 #. 13 #. 1 #: ../src/libmdc_interface.c:347 #, c-format msgid "Importing data type %d file through (X)MedCon unsupported in AMIDE, trying anyway" msgstr "透過 (X)MedCon 匯入資料類型 %d 的檔案並不受 AMIDE 支援,無論如何還是試試看" #: ../src/libmdc_interface.c:361 ../src/libmdc_interface.c:607 #, c-format msgid "Couldn't read plane %d in %s with libmdc/(X)MedCon" msgstr "無法以 libmdc/(X)MedCon 讀取 %2$s 中的 %1$d 平面" #: ../src/libmdc_interface.c:367 #, c-format msgid "libmdc returned error: %s" msgstr "libmdc 回傳了錯誤:%s" #: ../src/libmdc_interface.c:406 msgid "Couldn't allocate memory space for the data set structure to hold (X)MedCon data" msgstr "無法配置記憶體空間給資料集結構以存放 (X)MedCon 資料" #: ../src/libmdc_interface.c:543 msgid "(X)MedCon returned no duration information. Frame durations will be incorrect" msgstr "(X)MedCon 沒有回傳任何持續時間資訊。 影格持續時間將會不正確" #: ../src/libmdc_interface.c:563 #, c-format msgid "" "Importing File Through (X)MedCon:\n" " %s" msgstr "" "透過 (X)MedCon 匯入檔案:\n" " %s" #: ../src/libmdc_interface.c:737 msgid "(X)MedCon couldn't convert to a float... out of memory?" msgstr "(X)MedCon 無法轉換為浮點數… 記憶體不足?" #: ../src/libmdc_interface.c:773 #, c-format msgid "(X)MedCon returned %d blank planes... corrupted data file? Use data with caution." msgstr "(X)MedCon 回傳了 %d 空白平面… 資料檔案已損壞? 使用資料請小心。" #: ../src/libmdc_interface.c:893 #, c-format msgid "Unsupported export file format: %d\n" msgstr "不支援的匯出檔案格式:%d\n" #: ../src/libmdc_interface.c:1040 msgid "couldn't malloc DYNAMIC_DATA structs" msgstr "無法配置記憶體給 DYNAMIC_DATA 結構" #: ../src/libmdc_interface.c:1046 msgid "couldn't malloc img_data structs" msgstr "無法配置記憶體給 img_data 結構" #: ../src/libmdc_interface.c:1052 #, c-format msgid "" "Exporting File Through (X)MedCon:\n" " %s" msgstr "" "透過 (X)MedCon 匯出檔案:\n" " %s" #: ../src/libmdc_interface.c:1111 #, c-format msgid "couldn't alloc %d bytes for plane" msgstr "無法配置 %d 位元組給平面" #: ../src/libmdc_interface.c:1158 #, c-format msgid "couldn't pixel fiddle, error: %s" msgstr "無法像素化無意義資料,錯誤:%s" #: ../src/libmdc_interface.c:1165 #, c-format msgid "couldn't write out file %s, error %d" msgstr "無法寫出檔案 %s,錯誤 %d" #: ../src/mpeg_encode.c:325 ../src/mpeg_encode.c:516 msgid "Unable to allocate yuv struct" msgstr "無法配置 yuv 結構" #: ../src/mpeg_encode.c:335 ../src/mpeg_encode.c:524 msgid "Unable to allocate yuv buffer" msgstr "無法配置 yuv 緩衝區" #: ../src/mpeg_encode.c:491 msgid "couldn't allocate memory space for context_t" msgstr "無法配置記憶體空間給 context_t" #: ../src/mpeg_encode.c:503 msgid "couldn't allocate memory space for fame parameters" msgstr "無法配置記憶體空間給 fame 參數" #: ../src/mpeg_encode.c:510 msgid "Unable to allocate memory space for mpeg encoding buffer" msgstr "無法配置記憶體空間給 mpeg 編碼緩衝區" #: ../src/mpeg_encode.c:543 msgid "unable to open output file for mpeg encoding" msgstr "無法開啟輸出檔案給 mpeg 編碼" #: ../src/raw_data_import.c:242 msgid "read offset (entries):" msgstr "讀取偏移 (項目):" #: ../src/raw_data_import.c:245 msgid "read offset (bytes):" msgstr "讀取偏移 (位元組):" #: ../src/raw_data_import.c:259 msgid "total entries to read through:" msgstr "透過讀取的項目總計:" #: ../src/raw_data_import.c:274 msgid "total bytes to read through:" msgstr "透過讀取的位元組總計:" #: ../src/raw_data_import.c:349 #, c-format msgid "%s: Raw Data Import Dialog\n" msgstr "%s:原始資料匯入對話框\n" #. widgets to change the roi's name #: ../src/raw_data_import.c:363 msgid "name:" msgstr "名稱:" #. widgets to change the object's modality #: ../src/raw_data_import.c:401 msgid "modality:" msgstr "造影:" #. widgets to change the raw data file's data format #: ../src/raw_data_import.c:425 msgid "data format:" msgstr "資料格式:" #. how many bytes we can read from the file #: ../src/raw_data_import.c:446 msgid "file size (bytes):" msgstr "檔案大小 (位元組):" #. labels for the x, y, and z components #: ../src/raw_data_import.c:493 ../src/ui_render.c:972 msgid "x" msgstr "x" #: ../src/raw_data_import.c:496 ../src/ui_render.c:946 msgid "y" msgstr "y" #: ../src/raw_data_import.c:499 ../src/ui_render.c:954 msgid "z" msgstr "z" #: ../src/raw_data_import.c:502 msgid "gates" msgstr "閘口" #: ../src/raw_data_import.c:505 msgid "frames" msgstr "影格" #. widgets to change the dimensions of the data set #: ../src/raw_data_import.c:512 msgid "dimensions (# voxels)" msgstr "維度 (# 體素)" #. widgets to change the voxel size of the data set #: ../src/raw_data_import.c:533 msgid "voxel size (mm)" msgstr "體素大小 (公釐)" #. scale factor to apply to the data #: ../src/raw_data_import.c:556 msgid "scale factor" msgstr "伸縮因子" #: ../src/raw_data_import.c:593 msgid "Couldn't allocate memory space for raw_data_info structure for raw data import" msgstr "無法配置記憶體空間給 raw_data_info 結構用於原始資料匯入" #: ../src/raw_data_import.c:605 #, c-format msgid "Couldn't get stat's on file %s for raw data import" msgstr "無法取得檔案 %s 的狀態用於原始資料匯入" #: ../src/render.c:46 msgid "Highest Quality and Slowest" msgstr "最高品質且最慢" #: ../src/render.c:47 msgid "High Quality and Medium Speed" msgstr "高品質且中等速度" #: ../src/render.c:48 msgid "Medium Quality and Fast" msgstr "中等品質且快速" #: ../src/render.c:49 msgid "Low Quality and Fastest" msgstr "低品質且最快" #: ../src/render.c:52 msgid "Opacity" msgstr "濁度" #: ../src/render.c:53 msgid "Grayscale" msgstr "灰階" #: ../src/render.c:150 msgid "couldn't allocate memory space for rendering context" msgstr "無法配置記憶體空間給潤算狀態組合" #: ../src/render.c:201 msgid "\"Per Slice\" thresholding illogical for conversion to volume rendering, using \"Global\" thresholding " msgstr "「各切片」用於轉換到體積潤算的臨界值不合邏輯,正在使用「全域」臨界值 " #: ../src/render.c:214 msgid "couldn't allocate memory space for density ramp x" msgstr "無法配置記憶體空間給密度斜面 x" #: ../src/render.c:219 msgid "couldn't allocate memory space for density ramp y" msgstr "無法配置記憶體空間給密度斜面 y" #: ../src/render.c:230 msgid "couldn't allocate memory space for gradient ramp x" msgstr "無法配置記憶體空間給梯度斜面 x" #: ../src/render.c:235 msgid "couldn't allocate memory space for gradient ramp y" msgstr "無法配置記憶體空間給梯度斜面 y" #: ../src/render.c:254 msgid "Error Setting the Rendering Density Ramp" msgstr "設定潤算密度斜面時發生錯誤" #: ../src/render.c:264 msgid "Error Setting the Rendering Gradient Ramp" msgstr "設定潤算梯度斜面時發生錯誤" #: ../src/render.c:272 #, c-format msgid "Error Setting the Rendering Voxel Size (%s): %s" msgstr "設定潤算體素大小 (%s) 時發生錯誤:%s" #: ../src/render.c:282 #, c-format msgid "Error Specifying the Rendering Voxel Fields (%s, NORMAL): %s" msgstr "指定潤算體素欄位 (%s,一般) 時發生錯誤:%s" #: ../src/render.c:289 #, c-format msgid "Error Specifying the Rendering Voxel Fields (%s, DENSITY): %s" msgstr "指定潤算體素欄位 (%s,密度) 時發生錯誤:%s" #: ../src/render.c:297 #, c-format msgid "Error Specifying the Rendering Voxel Fields (%s, GRADIENT): %s" msgstr "指定潤算體素欄位 (%s,梯度) 時發生錯誤:%s" #: ../src/render.c:307 #, c-format msgid "Error Setting the Rendering Classifier Table (%s, DENSITY): %s" msgstr "設定潤算分類表格 (%s,密度) 時發生錯誤:%s" #: ../src/render.c:317 #, c-format msgid "Error Setting the Classifier Table (%s, GRADIENT): %s" msgstr "設定分類表格 (%s,梯度) 時發生錯誤:%s" #: ../src/render.c:415 #, c-format msgid "Error Setting the Context Size (%s): %s" msgstr "設定狀態組合大小 (%s) 時發生錯誤:%s" #: ../src/render.c:428 #, c-format msgid "Could not allocate memory space for density data for %s" msgstr "無法配置記憶體空間給密度資料用於 %s" #: ../src/render.c:440 #, c-format msgid "Could not allocate memory space for rendering context volume for %s" msgstr "無法配置記憶體空間給潤算狀態組合體積用於 %s" #: ../src/render.c:452 #, c-format msgid "Converting for rendering: %s" msgstr "正在轉換潤算:%s" #: ../src/render.c:654 #, c-format msgid "Error Computing the Rendering Normals (%s): %s" msgstr "計算潤算法線 (%s) 時發生錯誤:%s" #: ../src/render.c:682 #, c-format msgid "Error Setting Rendering Octree Threshold (%s, DENSITY): %s" msgstr "設定潤算八元樹臨界值 (%s,密度) 時發生錯誤:%s" #: ../src/render.c:688 #, c-format msgid "Error Setting Rendering Octree Threshold (%s, GRADIENT): %s" msgstr "設定潤算八元樹臨界值 (%s,梯度) 時發生錯誤:%s" #: ../src/render.c:695 #, c-format msgid "Error Generating Octree (%s): %s" msgstr "產生八元樹 (%s) 時發生錯誤:%s" #: ../src/render.c:722 #, c-format msgid "Error Setting the Rendering Material (%s, SHINYNESS): %s" msgstr "設定潤算材料 (%s,光度) 時發生錯誤:%s" #: ../src/render.c:732 #, c-format msgid "Error Setting the Rendering Shader (%s): %s" msgstr "設定潤算陰影 (%s) 時發生錯誤:%s" #: ../src/render.c:740 #, c-format msgid "Error Shading Table for Rendering (%s): %s" msgstr "加潤算陰影表格 (%s) 時發生錯誤:%s" #: ../src/render.c:775 #, c-format msgid "Error Setting The Item To Rotate (%s): %s" msgstr "設定項目為旋轉 (%s) 時發生錯誤:%s" #: ../src/render.c:780 #, c-format msgid "Error Rotating Rendering (%s): %s" msgstr "旋轉潤算 (%s) 時發生錯誤:%s" #: ../src/render.c:858 #, c-format msgid "Error Setting Rendering Max Ray Opacity (%s): %s" msgstr "設定潤算最大光線濁度 (%s) 時發生錯誤:%s" #: ../src/render.c:864 #, c-format msgid "Error Setting the Min Voxel Opacity (%s): %s" msgstr "設定最小體素濁度 (%s) 時發生錯誤:%s" #: ../src/render.c:893 #, c-format msgid "Could not allocate memory space for Rendering Image for %s" msgstr "無法配置記憶體空間給潤算影像用於 %s" #: ../src/render.c:901 #, c-format msgid "Error Switching the Rendering Image Pixel Return Type (%s): %s" msgstr "交換潤算影像像素傳回類型 (%s) 時發生錯誤:%s" #: ../src/render.c:913 #, c-format msgid "Error Setting the Rendering Depth Cue (%s): %s" msgstr "設定潤算深度暗示 (%s) 時發生錯誤:%s" #: ../src/render.c:930 #, c-format msgid "Error Enabling Rendering Depth Cueing (%s): %s" msgstr "啟用潤算景深暗示 (%s) 時發生錯誤:%s" #: ../src/render.c:960 #, c-format msgid "Error Classifying the Volume (%s): %s" msgstr "分類體積 (%s) 時發生錯誤:%s" #: ../src/render.c:966 #, c-format msgid "Error Rendering the Classified Volume (%s): %s" msgstr "潤算分類的體積 (%s) 時發生錯誤:%s" #: ../src/render.c:972 #, c-format msgid "Error Rendering the Volume (%s): %s" msgstr "潤算體積 (%s) 時發生錯誤:%s" #: ../src/tb_alignment.c:39 msgid "There is only one data set in this study. There needs to be at least two data sets to perform an alignment" msgstr "在這個檢驗中只有一個資料集。 至少需要兩個資料集才能施行對齊操作" #: ../src/tb_alignment.c:43 msgid "" "In order to perform an alignment, each data set must have at least three objects with the same name as the corresponding three objects in the other data set.\n\n" "Please see the help documentation for a longer explanation as to how alignments can be done." msgstr "" "為了施行對齊,每個資料集至少要有三個與其他資料集中相應物件同名的物件。\n\n" "請參看說明文件中,關於如何完成對齊操作的詳細解釋。" #: ../src/tb_alignment.c:51 msgid "" "Welcome to the data set alignment wizard, used for aligning one medical image data set with another. \n\n" "Currently, only rigid body registration using either fiducial marks, or maximization of mutual information has been implemented inside of AMIDE. This program was built without libgsl support, as such registration utilizing fiducial marks is not supported.\n\n" "The mutual information algorithm is run on the currently displayed slices, not the whole data sets." msgstr "" "歡迎使用資料集對齊精靈,用於將一個醫學影像資料集與另外一個對齊。\n\n" "目前只有使用基準標記或交互資訊最大化的 rigid 內文註冊,已被 AMIDE 實作於內部。這個程式是 built 而無需 libgsl 支援,因為此類註冊利用基準標記未被支援。\n\n" "交互資訊演算法是運行在之上目前顯示的切片,不是整個資料集。" #: ../src/tb_alignment.c:101 msgid "Fiducial Markers" msgstr "基準標記" #: ../src/tb_alignment.c:103 msgid "Mutual Information" msgstr "交互資訊" #: ../src/tb_alignment.c:212 msgid "couldn't allocate memory space for tb_alignment_t" msgstr "無法配置記憶體空間給 tb_alignment_t" #: ../src/tb_alignment.c:498 msgid "Align Data Set: (moving)" msgstr "對齊資料集:(移動)" #: ../src/tb_alignment.c:521 msgid "Align Data Set: (fixed)" msgstr "對齊資料集:(固定)" #: ../src/tb_alignment.c:560 msgid "Points for Alignment" msgstr "用於對齊的點數" #: ../src/tb_alignment.c:634 #, c-format msgid "" "The alignment has been calculated, press Finish to apply, or Cancel to quit.\n\n" "The calculated fiducial reference error is:\n\t %5.2f mm/point" msgstr "" "對齊已經計算,按下完成以套用,或按下取消以離開。\n\n" "計算出的基準參考錯誤是:\n\t%5.5f 公釐/點" #: ../src/tb_alignment.c:648 #, c-format msgid "" "The alignment has been calculated, press Finish to apply, or Cancel to quit.\n\n" "The calculated mutual information metric is:\n\t %5.2f" msgstr "" "對齊已計算,按下完成以套用,或取消以離開。\n\n" "已計算的交互資訊度量資訊是:\n\t%5.2f" #: ../src/tb_alignment.c:708 msgid "Data Set Alignment Wizard" msgstr "資料集對齊精靈" #: ../src/tb_alignment.c:717 msgid "Alignment Type Selection" msgstr "對齊型態選擇" #: ../src/tb_alignment.c:725 ../src/tb_math.c:543 msgid "Data Set Selection" msgstr "資料集選擇" #: ../src/tb_alignment.c:731 msgid "Fiducial Marks Selection" msgstr "基準標記選擇" #: ../src/tb_alignment.c:739 msgid "Alignment Error" msgstr "對齊錯誤" #: ../src/tb_alignment.c:747 ../src/tb_math.c:560 msgid "Conclusion" msgstr "結論" #: ../src/tb_crop.c:41 msgid "" "When the apply button is hit, a new data set will be created\n" "and placed into the study's tree, consisting of the appropriately\n" "cropped data\n" msgstr "" "當套用按鈕被點擊時,新的資料集將被建立\n" "並且放入檢驗樹,而由適當裁剪的資料\n" "所構成\n" #. the zoom selection #: ../src/tb_crop.c:195 msgid "zoom" msgstr "縮放" #: ../src/tb_crop.c:215 msgid "gate" msgstr "閘口" #: ../src/tb_crop.c:236 msgid "frame" msgstr "影格" #: ../src/tb_crop.c:291 #, c-format msgid "%s range:" msgstr "%s 範圍:" #: ../src/tb_crop.c:319 msgid "(mm)" msgstr "(公釐)" #. widget to tell you the internal data format #: ../src/tb_crop.c:390 msgid "Current Data Format:" msgstr "目前的資料格式:" #. widget to tell you the scaling format #: ../src/tb_crop.c:403 msgid "Current Scale Format:" msgstr "目前的伸縮格式:" #. widget to tell you the internal data format #: ../src/tb_crop.c:422 msgid "Output Data Format:" msgstr "輸出資料格式:" #. widget to tell you the scaling format #: ../src/tb_crop.c:435 msgid "Output Scale Format:" msgstr "輸出伸縮格式:" #: ../src/tb_crop.c:992 msgid "couldn't allocate memory space for tb_crop_t" msgstr "無法配置記憶體空間給 tb_crop_t" #: ../src/tb_crop.c:1033 ../src/tb_filter.c:429 ../src/ui_study_cb.c:56 msgid "No data set is currently marked as active" msgstr "目前沒有資料集被標記為作用中" #: ../src/tb_crop.c:1076 msgid "Data Set Cropping Wizard" msgstr "資料集裁剪精靈" #: ../src/tb_export_data_set.c:111 msgid "couldn't allocate memory space for tb_export_t" msgstr "無法配置記憶體空間給 tb_export_t" #: ../src/tb_export_data_set.c:216 ../src/tb_export_data_set.c:373 msgid "No Data Sets are current visible" msgstr "目前沒有任何可見的資料集" #. the rest of this function runs the file selection dialog box #: ../src/tb_export_data_set.c:249 ../src/ui_study_cb.c:535 msgid "Export to File" msgstr "匯出至檔案" #: ../src/tb_export_data_set.c:535 #, c-format msgid "%s: Export Data Set Dialog" msgstr "%s:匯出資料集對話框" #: ../src/tb_export_data_set.c:557 msgid "Exporting Data Sets" msgstr "匯出資料集" #: ../src/tb_export_data_set.c:564 msgid "Export:" msgstr "匯出:" #. tooltip N_("Export the data set in its original orientation (unresliced)") #: ../src/tb_export_data_set.c:569 #, c-format msgid "Original Orientation - %s" msgstr "原來的方向 - %s" #. tooltip N_("Export the data set in its current orientation (resliced)") #: ../src/tb_export_data_set.c:580 #, c-format msgid "Resliced Orientation - %s" msgstr "重新切片方向 - %s" #: ../src/tb_export_data_set.c:592 msgid "All Visible Data Sets (resliced)" msgstr "所有可見的資料集 (重新切片)" #: ../src/tb_export_data_set.c:617 msgid "export format:" msgstr "匯出格式:" #. widgets to change the voxel size of the data set #: ../src/tb_export_data_set.c:661 msgid "voxel size (mm) [x,y,z]:" msgstr "體素大小 (公釐) [x,y,z]:" #. gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_buttons[0]),FALSE); #. gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_buttons[0]), FALSE); #. gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_buttons[0]), GTK_UPDATE_ALWAYS); #: ../src/tb_export_data_set.c:686 msgid "bounding box:" msgstr "邊界方框:" #: ../src/tb_fads.c:41 msgid "Factor Analysis Wizard" msgstr "因素分析精靈" #: ../src/tb_fads.c:46 msgid "" "This page allows the computation of the singular value decomposition for the data set in question. These values can give you an idea of how many important factors the data set has.\n\n" "This process can be extremely slow, so skip this page if you already know the answer." msgstr "" "這個頁面允許用於所提資枓集的單值分解計算。 這些值可以給您有多少重要因子資料集的概念。\n\n" "這個程序可能會極度緩慢,因此如果您已經知道答案就跳過這個頁面。" #: ../src/tb_fads.c:54 msgid "When the apply button is hit, the appropriate factor analysis data structures will be created, and placed underneath the given data set in the study tree\n" msgstr "當套用按鈕被點擊時,適當的因素分析資料結構將被建立,而且被置放於在檢驗樹中給定的資料集之下\n" #: ../src/tb_fads.c:59 msgid "" "Welcome to the factor analysis of dynamic structures wizard. \n\n" "None of this code has been validated, and it's probably wrong, so use at your own risk" msgstr "" "歡迎使用動態結構精靈的因素分析。\n\n" "沒有任何編碼曾被驗證過,因此或許是錯誤的,使用時請自負風險" #: ../src/tb_fads.c:66 msgid "" "Welcome to the factor analysis of dynamic structures wizard. \n\n" "This wizard only works with dynamic studies" msgstr "" "歡迎使用動態結構精靈的因素分析。\n\n" "這個精靈只適用於動態檢驗" #: ../src/tb_fads.c:154 #, c-format msgid "" "%s\n" "Method Picked: %s" msgstr "" "%s\n" "揀取的方法:%s" #: ../src/tb_fads.c:187 msgid "Filename for Factor Data" msgstr "因子資料檔名" #: ../src/tb_fads.c:389 msgid "failed malloc for frames array" msgstr "配置記憶體給影格陣列時失敗" #: ../src/tb_fads.c:394 msgid "failed malloc for vals array" msgstr "配置記憶體給 vals 陣列時失敗" #: ../src/tb_fads.c:523 msgid "couldn't allocate memory space for tb_fads_t" msgstr "無法配置記憶體空間給 tb_fads_t" #. do I need to compute factors? #: ../src/tb_fads.c:650 msgid "Compute Singular Values?" msgstr "計算單值?" #. ask for the fads method to use #: ../src/tb_fads.c:686 msgid "FADS Method:" msgstr "FADS 方法:" #. ask for the minimizer algorithm to use #: ../src/tb_fads.c:720 msgid "Minimization Algorithm:" msgstr "最小化演算法:" #. max # of iterations #: ../src/tb_fads.c:735 msgid "Max. # of iterations:" msgstr "反覆運算最大次數:" #. stopping criteria #: ../src/tb_fads.c:750 msgid "Stopping Criteria:" msgstr "停止準則:" #. stopping criteria #: ../src/tb_fads.c:767 msgid "Beta:" msgstr "測試:" #. how many factors to solve for? #: ../src/tb_fads.c:782 msgid "# of Factors to use" msgstr "要使用的因子數量" #. k12 criteria #: ../src/tb_fads.c:797 msgid "initial k12 (1/s):" msgstr "初始 k12 (1/s):" #. k21 criteria #: ../src/tb_fads.c:814 msgid "initial K21 (1/s):" msgstr "初始 K21 (1/s):" #. A table to add blood sample measurements #: ../src/tb_fads.c:837 msgid "Add Blood Sample" msgstr "加入血液樣本" #: ../src/tb_fads.c:877 msgid "Remove Blood Sample" msgstr "移除血液樣本" #. mm #. mm #: ../src/tb_filter.c:46 msgid "Data Set Filtering Wizard" msgstr "資料集篩選精靈" #: ../src/tb_filter.c:49 msgid "When the apply button is hit, a new data set will be created and placed into the study's tree, consisting of the appropriately filtered data\n" msgstr "當套用按鈕被點擊時,新的資料集將被建立並被放入檢驗樹,而由適當篩選過的資料所構成\n" #: ../src/tb_filter.c:55 msgid "The Gaussian filter is an effective smoothing filter" msgstr "Gaussian 篩選器是一種有效的平滑篩選器" #: ../src/tb_filter.c:60 msgid "" "Median filter work relatively well at preserving edges while\n" "removing speckle noise.\n\n" "This filter is the 3D median filter, so the neighborhood used for\n" "determining the median will be KSxKSxKS, KS=kernel size" msgstr "" "我的篩選器作用相對的地得不錯於保留邊緣當\n" "移除斑點雜訊。\n\n" "這個篩選器是 3D 我的篩選器,因而 neighborhood 用於\n" "決定我的將是 KSxKSxKS,KS=內核大小" #: ../src/tb_filter.c:67 msgid "" "Median filters work relatively well at preserving edges while\n" "removing speckle noise.\n\n" "This filter is the 1D median filter, so the neighboorhood used for\n" "determining the median will be of the given kernel size, and the\n" "data set will be filtered 3x (once for each direction)." msgstr "" "中值篩選器就保留邊緣值同時移除斑點雜訊\n" "來說相對表現不錯。\n\n" "這個篩選器是 1D 中值篩選器,因此用於\n" "決定中值的鄰值將是給定的內核大小,而\n" "資料集將被篩選三次 (每個方向一次)。" #: ../src/tb_filter.c:76 msgid "" "This filter requires support from the GNU Scientific Library (GSL).\n" "This version of AMIDE has not been compiled with GSL support enabled." msgstr "" "這個篩選器需要來自 GNU 科學函式庫 (GSL) 的支援。\n" "這個版本的 AMIDE 編譯時並未啟用 GSL 支援。" #: ../src/tb_filter.c:282 msgid "couldn't allocate memory space for tb_filter_t" msgstr "無法配置記憶體空間給 tb_filter_t" #: ../src/tb_filter.c:315 msgid "Which Filter" msgstr "何種篩選器" #. the kernel selection #: ../src/tb_filter.c:343 ../src/tb_filter.c:394 msgid "Kernel Size" msgstr "內核大小" #: ../src/tb_filter.c:360 msgid "FWHM (mm)" msgstr "FWHM (公釐)" #. the rest of this function runs the file selection dialog box #: ../src/tb_fly_through.c:308 ../src/ui_render_movie.c:236 msgid "Output MPEG As" msgstr "輸出 MPEG 為" #: ../src/tb_fly_through.c:479 #, c-format msgid "encoding of frame %d failed" msgstr "影格 %d 編碼時失敗" #: ../src/tb_fly_through.c:630 msgid "couldn't allocate memory space for tb_fly_through_t" msgstr "無法配置記憶體空間給 tb_fly_through_t" #: ../src/tb_fly_through.c:694 msgid "Fly Through Generation" msgstr "產生掃視" #: ../src/tb_fly_through.c:697 msgid "_Generate Fly Through" msgstr "產生掃視(_G)" #: ../src/tb_fly_through.c:716 msgid "Current Position (mm):" msgstr "現行位置 (公釐):" #: ../src/tb_fly_through.c:726 msgid "Start Position (mm):" msgstr "開始位置 (公釐):" #: ../src/tb_fly_through.c:741 msgid "End Position (mm):" msgstr "結束位置 (公釐):" #: ../src/tb_fly_through.c:756 msgid "Movie Duration (sec):" msgstr "影片持續時間 (sec):" #: ../src/tb_fly_through.c:774 msgid "Fly through movie generation" msgstr "產生掃視影片" #: ../src/tb_fly_through.c:785 msgid "Set Start Position" msgstr "設定開始位置" #: ../src/tb_fly_through.c:790 msgid "Set End Position" msgstr "設定結束位置" #. do we want to make a movie over time or over frames #: ../src/tb_fly_through.c:848 ../src/ui_render_movie.c:702 msgid "Dynamic Movie:" msgstr "動態影片:" #. the radio buttons #: ../src/tb_fly_through.c:859 ../src/ui_render_movie.c:713 msgid "No" msgstr "否" #: ../src/tb_fly_through.c:866 ../src/ui_render_movie.c:718 msgid "over time" msgstr "經由時間" #: ../src/tb_fly_through.c:870 ../src/ui_render_movie.c:722 msgid "over frames" msgstr "經由影格" #: ../src/tb_fly_through.c:882 ../src/ui_render_movie.c:732 msgid "over frames smoothed" msgstr "經由影格平滑化" #: ../src/tb_fly_through.c:888 ../src/ui_render_movie.c:736 msgid "over gates" msgstr "經由閘口" #. widgets to specify the start and end times #: ../src/tb_fly_through.c:908 ../src/ui_render_movie.c:748 msgid "Start Time (s)" msgstr "開始時間 (秒)" #: ../src/tb_fly_through.c:911 ../src/ui_render_movie.c:751 msgid "Start Frame" msgstr "開始影格" #: ../src/tb_fly_through.c:938 ../src/ui_render_movie.c:778 msgid "End Time (s)" msgstr "結束時間 (秒)" #: ../src/tb_fly_through.c:941 ../src/ui_render_movie.c:781 msgid "End Frame" msgstr "結束影格" #: ../src/tb_fly_through.c:969 ../src/ui_render_movie.c:810 msgid "Display time on image" msgstr "在影像上顯示時間" #: ../src/tb_math.c:37 msgid "There is only one data set in this study. There needs to be at least two data sets to perform mathematical operations" msgstr "在這個檢驗中只有一個資料集。 需要至少兩個資料集以施行數學計算" #: ../src/tb_math.c:41 msgid "" "Welcome to the data set math wizard, used for performing mathematical operations between medical image data sets.\n\n" "Note - you will get more pleasing results if the data sets in question are set to trilinear interpolation mode." msgstr "" "歡迎使用資料集數學精靈,用於在醫學影像資料集之間施行數學計算。\n\n" "註記 - 如果用到的資料集被設定為三線性內插模式,您將會得到更佳的結果。" #: ../src/tb_math.c:277 #, c-format msgid "A new data set will be created with the math operation, press Finish to calculate this data set, or Cancel to quit." msgstr "新的資料集將以數學運算建立,按下完成將會計算這個資料集,或是按下取消以離開。" #: ../src/tb_math.c:309 msgid "Math operation failed - results not added to study" msgstr "數學運算失敗 - 結果未加入檢驗" #: ../src/tb_math.c:386 msgid "couldn't allocate memory space for tb_math_t" msgstr "無法配置記憶體空間給 tb_math_t" #: ../src/tb_math.c:419 msgid "Data Set 1:" msgstr "資料集 1:" #: ../src/tb_math.c:442 msgid "Data Set 2:" msgstr "資料集 2:" #: ../src/tb_math.c:474 msgid "Math Operation" msgstr "數學運算" #: ../src/tb_math.c:533 msgid "Data Set Math Wizard" msgstr "資料集數學精靈" #: ../src/tb_math.c:550 msgid "Operation Selection" msgstr "運算選擇" #: ../src/tb_profile.c:223 msgid "couldn't allocate memory space for tb_profile_t" msgstr "無法配置記憶體空間給 tb_profile_t" #: ../src/tb_profile.c:257 #, c-format msgid "# Profiles on Study: %s\tGenerated on: %s" msgstr "# 檢驗輪廓檔:%s\t產生於:%s" #: ../src/tb_profile.c:262 #, c-format msgid "" "#\n" "# Profile on: %s\n" msgstr "" "#\n" "# 輪廓檔於:%s\n" #: ../src/tb_profile.c:266 msgid "# Gaussian Fit: b + p * e^(-0.5*(x-c)^2/s^2)\n" msgstr "# Gaussian 擬合:b + p * e^(-0.5*(x-c)^2/s^2)\n" #: ../src/tb_profile.c:267 #, c-format msgid "#\titerations used %d, status %s\n" msgstr "#\t反覆運算已用 %d,狀態 %s\n" #: ../src/tb_profile.c:270 ../src/tb_profile.c:275 ../src/tb_profile.c:823 #: ../src/tb_profile.c:826 msgid "(fixed)" msgstr "(固定)" #: ../src/tb_profile.c:286 msgid "# x\tvalue\n" msgstr "# x\t數值\n" #. the rest of this function runs the file selection dialog box #: ../src/tb_profile.c:315 msgid "Export Profile" msgstr "匯出輪廓檔" #: ../src/tb_profile.c:366 #, c-format msgid "couldn't open: %s for writing profiles" msgstr "無法開啟:%s 以寫入輪廓檔" #. write out the gaussian equation #: ../src/tb_profile.c:778 msgid "fit = b + p * e^(-0.5*(x-c)^2/s^2)" msgstr "擬合 = b + p * e^(-0.5*(x-c)^2/s^2)" #: ../src/tb_profile.c:812 #, c-format msgid "" "\n\n" "gaussian fit on: %s\n" "iterations used %d, status %s\n" "b = %.5g +/- %.5g %s\n" "p = %.5g +/- %.5g\n" "c = %.5g +/- %.5g mm %s\n" "s = %.5g +/- %.5g\n" "fwhm = %.5g +/- %.5g mm\n" "fwtm = %.5g +/- %.5g mm" msgstr "" "\n\n" "gaussian 擬合於:%s\n" "反覆運算已用 %d,狀態 %s\n" "b = %.5g +/- %.5g %s\n" "p = %.5g +/- %.5g\n" "c = %.5g +/- %.5g 公釐 %s\n" "s = %.5g +/- %.5g\n" "fwhm = %.5g +/- %.5g 公釐\n" "fwtm = %.5g +/- %.5g 公釐" #. start setting up the widget we'll display the info from #: ../src/tb_profile.c:1181 #, c-format msgid "%s Profile Tool: Study %s" msgstr "%s 輪廓檔工具:檢驗 %s" #. which view do we want the profile on #: ../src/tb_profile.c:1215 msgid "Line Profile on:" msgstr "曲線輪廓於:" #. changing the angle #: ../src/tb_profile.c:1246 msgid "Angle (degrees):" msgstr "角度 (度):" #: ../src/tb_roi_analysis.c:83 msgid "ROI" msgstr "ROI" #: ../src/tb_roi_analysis.c:84 ../src/ui_time_dialog.c:62 msgid "Data Set" msgstr "資料集" #: ../src/tb_roi_analysis.c:87 msgid "Midpt (s)" msgstr "Midpt (秒)" #: ../src/tb_roi_analysis.c:88 msgid "Gate" msgstr "閘口" #. N_("Total"), #: ../src/tb_roi_analysis.c:90 msgid "Median" msgstr "中值" #: ../src/tb_roi_analysis.c:91 msgid "Mean" msgstr "平均" #: ../src/tb_roi_analysis.c:92 msgid "Var" msgstr "Var" #: ../src/tb_roi_analysis.c:93 msgid "Std Dev" msgstr "Std Dev" #: ../src/tb_roi_analysis.c:96 msgid "Size (mm^3)" msgstr "大小 (公釐^3)" #: ../src/tb_roi_analysis.c:97 msgid "Frac. Voxels" msgstr "體素成分" #: ../src/tb_roi_analysis.c:98 msgid "Voxels" msgstr "體素" #: ../src/tb_roi_analysis.c:139 msgid "Export Statistics" msgstr "匯出統計資訊" #: ../src/tb_roi_analysis.c:139 msgid "Export ROI Raw Data Values" msgstr "匯出 ROI 原始資料值" #: ../src/tb_roi_analysis.c:152 msgid "roi_raw_data" msgstr "roi_raw_data" #: ../src/tb_roi_analysis.c:152 msgid "analysis" msgstr "分析" #: ../src/tb_roi_analysis.c:197 #, c-format msgid "couldn't open: %s for writing roi data" msgstr "無法開啟:%s 用於寫入 roi 資料" #: ../src/tb_roi_analysis.c:203 #, c-format msgid "# %s: ROI Analysis File - generated on %s" msgstr "# %s:ROI 分析檔案 - 產生於 %s" #: ../src/tb_roi_analysis.c:205 #, c-format msgid "# Study:\t%s\n" msgstr "# 檢驗:\t%s\n" #: ../src/tb_roi_analysis.c:209 #, c-format msgid "# ROI:\t%s\tType:\t%s" msgstr "# ROI:\t%s\t類型:\t%s" #: ../src/tb_roi_analysis.c:214 #, c-format msgid "\tIsocontour Above Value:\t%g" msgstr "\t數值之上的輪廓面:\t%g" #: ../src/tb_roi_analysis.c:216 #, c-format msgid "\tIsocontour Below Value:\t%g" msgstr "\t數值之下的輪廓面:\t%g" #. AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX #: ../src/tb_roi_analysis.c:218 #, c-format msgid "\tIsocontour Between Values:\t%g %g" msgstr "\t數值之間的輪廓面:\t%g %g" #: ../src/tb_roi_analysis.c:227 #, c-format msgid "# Calculation done with all voxels in ROI\n" msgstr "# 在 ROI 中的所有體素已經計算完畢\n" #: ../src/tb_roi_analysis.c:230 #, c-format msgid "# Calculation done on %5.3f percentile of voxels in ROI\n" msgstr "# 在 ROI 中的 %5.3f 體素已經計算完畢\n" #: ../src/tb_roi_analysis.c:233 #, c-format msgid "# Calculation done on voxels >= %5.3f percent of maximum value in ROI\n" msgstr "# 在 ROI 中 >= %5.3f 最大值的體素已經計算完畢\n" #: ../src/tb_roi_analysis.c:236 #, c-format msgid "# Calculation done on voxels >= %g in ROI\n" msgstr "# 在 ROI 中 >= %g 的體素已經計算完畢\n" #: ../src/tb_roi_analysis.c:248 #, c-format msgid "# Data Set:\t%s\tScaling Factor:\t%g\n" msgstr "# 資料集:\t%s\t縮放因子:\t%g\n" #: ../src/tb_roi_analysis.c:255 #, c-format msgid "# Output Data Units: %s\n" msgstr "# 輸出資料單位:%s\n" #: ../src/tb_roi_analysis.c:257 #, c-format msgid "# Injected Dose: %g [%s]\n" msgstr "# 注射劑量:%g [%s]\n" #: ../src/tb_roi_analysis.c:261 #, c-format msgid "# Cylinder Factor: %g [%s]\n" msgstr "# 柱面因子:%g [%s]\n" #: ../src/tb_roi_analysis.c:272 #, c-format msgid "# Subject Weight: %g [%s]\n" msgstr "# 主題重量:%g [%s]\n" #: ../src/tb_roi_analysis.c:359 #, c-format msgid "# Stats for Study: %s\tGenerated on: %s" msgstr "# 檢驗統計資訊:%s\t產生於:%s" #: ../src/tb_roi_analysis.c:535 msgid "ROI Statistics" msgstr "ROI 統計資訊" #. tell us the type #: ../src/tb_roi_analysis.c:547 msgid "type:" msgstr "類型:" #: ../src/tb_roi_analysis.c:749 msgid "couldn't allocate memory space for tb_roi_analysis_t" msgstr "無法配置記憶體空間給 tb_roi_analysis_t" #: ../src/tb_roi_analysis.c:793 msgid "No Data Sets selected for calculating analyses" msgstr "未選取任何資料集用於計算分析" #: ../src/tb_roi_analysis.c:805 msgid "No ROI's selected for calculating analyses" msgstr "未選取任何 ROI 用於計算分析" #. start setting up the widget we'll display the info from #: ../src/tb_roi_analysis.c:819 #, c-format msgid "%s Roi Analysis: Study %s" msgstr "%s Roi 分析:檢驗 %s" #: ../src/tb_roi_analysis.c:959 #, c-format msgid "%s: ROI Analysis Initialization Dialog" msgstr "%s:ROI 分析初始化對話框" #: ../src/tb_roi_analysis.c:979 msgid "Calculate:" msgstr "計算:" #: ../src/tb_roi_analysis.c:982 msgid "All ROIS:" msgstr "所有 ROIS:" #: ../src/tb_roi_analysis.c:985 msgid "Selected ROIS:" msgstr "已選 ROIS:" #: ../src/tb_roi_analysis.c:990 msgid "On All Data Sets:" msgstr "於所有資料集:" #: ../src/tb_roi_analysis.c:1008 msgid "On Selected Data Sets:" msgstr "於已選資料集:" #. do we want to calculate over a subfraction #: ../src/tb_roi_analysis.c:1047 msgid "Calculate over all voxels (normal):" msgstr "對所有體素進行計算 (一般):" #. do we want to calculate over a subfraction #: ../src/tb_roi_analysis.c:1058 #, c-format msgid "Calculate over % highest voxels:" msgstr "對最高體素百分比進行計算:" #. do we want to calculate over a percentage of max #: ../src/tb_roi_analysis.c:1082 #, c-format msgid "Calculate for voxels >= % of Max:" msgstr "對體素 >= 最大值百分比進行計算:" #. do we want to calculate over a percentage of max #: ../src/tb_roi_analysis.c:1106 msgid "Calculate for voxels >= Value:" msgstr "對體素 >= 某值進行計算:" #. do we want more accurate quantitation #: ../src/tb_roi_analysis.c:1146 msgid "More Accurate Quantitation (Slow)" msgstr "更多正確量化 (慢)" #. Help menu #: ../src/ui_common.c:72 msgid "_Contents" msgstr "內容(_C)" #: ../src/ui_common.c:72 msgid "Open the AMIDE manual" msgstr "開啟 AMIDE 手冊" #: ../src/ui_common.c:73 msgid "About AMIDE" msgstr "關於 AMIDE" #: ../src/ui_common.c:87 msgid "Solid" msgstr "純色" #: ../src/ui_common.c:88 msgid "On/Off" msgstr "開/關" #: ../src/ui_common.c:89 msgid "Double Dash" msgstr "雙破折號" #: ../src/ui_common.c:116 msgid "AMIDE's a Medical Image Data Examiner\n" msgstr "AMIDE 醫學影像資料審視器\n" #: ../src/ui_common.c:118 msgid "Email bug reports to: " msgstr "將錯誤以電子郵件回報給:" #: ../src/ui_common.c:121 msgid "Compiled with support for the following libraries:\n" msgstr "編譯時已支援下列函式庫:\n" #: ../src/ui_common.c:124 msgid "libecat: CTI File library by Merence Sibomona\n" msgstr "libecat:CTI 檔案函式庫來自 Merence Sibomona\n" #: ../src/ui_common.c:127 msgid "libgsl: GNU Scientific Library by the GSL Team (version " msgstr "libgsl:GNU 科學函式庫來自 GSL 團隊 (版本 " #: ../src/ui_common.c:130 msgid "libmdc: Medical Imaging File library by Erik Nolf (version " msgstr "libmdc:醫學影像檔案函式庫來自 Erik Nolf (版本 " #: ../src/ui_common.c:133 msgid "libdcmdata: OFFIS DICOM Toolkit DCMTK (C) 1993-2004, OFFIS e.V. (version " msgstr "libdcmdata:OFFIS DICOM 工具組 DCMTK ©1993-2004, OFFIS e.V. (版本 " #: ../src/ui_common.c:136 msgid "libvolpack: Volume Rendering library by Philippe Lacroute (version " msgstr "libvolpack:體積潤算函式庫來自 Philippe Lacroute (版本 " #: ../src/ui_common.c:139 msgid "libavcodec: media encoding library by the FFMPEG Team (version " msgstr "libavcodec:媒體編碼函式庫來自 FFMPEG 團隊 (版本 " #: ../src/ui_common.c:142 msgid "libfame: Fast Assembly Mpeg Encoding library by the FAME Team (version " msgstr "libfame:快速組譯 Mpeg 編碼函式庫來自 FAME 團隊 (版本 " #. widgets to change the roi's size #: ../src/ui_common.c:397 msgid "ROI Width (pixels)" msgstr "ROI 寬度 (像素)" #. widgets to change the roi's line style #. Anti-aliased canvas doesn't yet support this #. also need to remove #ifndef for relevant lines in amitk_canvas_object.c #: ../src/ui_common.c:454 msgid "ROI Line Style:" msgstr "ROI 線條樣式:" #. do we want to fill in isocontour roi's #: ../src/ui_common.c:471 msgid "Draw Isocontours/Freehands Filled:" msgstr "繪製輪廓面/手繪填滿:" #: ../src/ui_common.c:491 msgid "Canvas Layout:" msgstr "畫布版面配置:" #: ../src/ui_common.c:520 msgid "Multiple Canvases Layout:" msgstr "多重畫布版面配置:" #. do we want the size of the canvas to not resize #: ../src/ui_common.c:562 msgid "Maintain view size constant:" msgstr "保持檢視大小常數:" #. widgets to change the amount of empty space in the center of the target #: ../src/ui_common.c:575 msgid "Target Empty Area (pixels)" msgstr "目標清空區域 (像素)" #: ../src/ui_common.c:764 msgid "Request Dialog" msgstr "要求對話框" #: ../src/ui_gate_dialog.c:43 msgid "Gate #" msgstr "閘口 #" #: ../src/ui_gate_dialog.c:340 #, c-format msgid "%s: Gate Dialog" msgstr "%s:閘口對話框" #: ../src/ui_gate_dialog.c:361 msgid "Start Gate" msgstr "開始閘口" #: ../src/ui_gate_dialog.c:378 msgid "End Gate" msgstr "結束閘口" #: ../src/ui_preferences_dialog.c:39 msgid "" "These preferences are used only for new studies. \n" "Use the study modification dialog to change these \n" "parameters for the current study." msgstr "" "這些偏好設定只用於新的檢驗。\n" "使用檢驗修改對話框以對目前檢驗\n" "變更這些參數。" #: ../src/ui_preferences_dialog.c:44 msgid "" "These preferences are used only for new data sets. \n" "Use the data set modification dialog to change these \n" "parameters for the current data set." msgstr "" "這些偏好設定只用於新的資料集。\n" "使用資料集修改對話框以對目前資料集\n" "變更這些參數。" #: ../src/ui_preferences_dialog.c:302 #, c-format msgid "%s: Preferences Dialog" msgstr "%s:偏好設定對話框" #: ../src/ui_preferences_dialog.c:412 msgid "Thresholding" msgstr "臨界處理" #: ../src/ui_preferences_dialog.c:476 msgid "Default Color Tables" msgstr "預設顏色表格" #. color table selector #: ../src/ui_preferences_dialog.c:483 #, c-format msgid "default %s color table:" msgstr "預設 %s 顏色表格:" #: ../src/ui_preferences_dialog.c:513 msgid "Miscellaneous" msgstr "雜項" #: ../src/ui_preferences_dialog.c:517 msgid "Send Warning Messages to Console:" msgstr "發送警告訊息到主控臺:" #: ../src/ui_preferences_dialog.c:532 msgid "Prompt for \"Save Changes\" on Exit:" msgstr "離開時提示「儲存變更」:" #: ../src/ui_preferences_dialog.c:547 msgid "Which Default Directory:" msgstr "何項預設目錄:" #: ../src/ui_preferences_dialog.c:565 msgid "Specified Directory:" msgstr "指定目錄:" #: ../src/ui_preferences_dialog.c:570 msgid "Default Directory:" msgstr "預設目錄:" #: ../src/ui_render.c:369 msgid "Export File" msgstr "匯出檔案" #: ../src/ui_render.c:408 ../src/ui_series.c:255 ../src/ui_study_cb.c:394 #: ../src/ui_study_cb.c:611 #, c-format msgid "Failure Saving File: %s" msgstr "儲存檔案失敗:%s" #: ../src/ui_render.c:411 ../src/ui_render_movie.c:526 #: ../src/ui_study_cb.c:602 msgid "Canvas failed to return a valid image\n" msgstr "畫布無法回傳有效影像\n" #. Toplevel #: ../src/ui_render.c:475 ../src/ui_series.c:369 ../src/ui_study.c:333 msgid "_File" msgstr "檔案(_F)" #: ../src/ui_render.c:476 ../src/ui_study.c:334 msgid "_Edit" msgstr "編輯(_E)" #: ../src/ui_render.c:477 ../src/ui_series.c:370 ../src/ui_study.c:337 msgid "_Help" msgstr "求助(_H)" #. File menu #: ../src/ui_render.c:480 msgid "_Export Rendering" msgstr "匯出潤算(_E)" #: ../src/ui_render.c:480 msgid "Export the rendered image" msgstr "匯出潤算的影像" #: ../src/ui_render.c:482 msgid "_Create Movie" msgstr "建立影片(_C)" #: ../src/ui_render.c:482 msgid "Create a movie out of a sequence of renderings" msgstr "建立超出潤算序列的影片" #: ../src/ui_render.c:484 msgid "Close the rendering dialog" msgstr "關閉潤算對話框" #. Edit menu #: ../src/ui_render.c:487 msgid "_Rendering Parameters" msgstr "潤算參數(_R)" #: ../src/ui_render.c:487 msgid "Adjust parameters pertinent to the rendered image" msgstr "調整與潤算影像有關的參數" #. Toolbar items #: ../src/ui_render.c:490 msgid "X-fer" msgstr "X-fer" #: ../src/ui_render.c:490 msgid "Opacity and density transfer functions" msgstr "濁度和密度轉換函式" #: ../src/ui_render.c:494 msgid "Mono" msgstr "平面" #: ../src/ui_render.c:494 msgid "Monoscopic rendering" msgstr "平面影像潤算" #: ../src/ui_render.c:495 msgid "Stereo" msgstr "立體" #: ../src/ui_render.c:495 msgid "Stereoscopic rendering" msgstr "立體影像潤算" #. add the zoom widget to our toolbar #: ../src/ui_render.c:570 ../src/ui_study.c:675 msgid "zoom:" msgstr "縮放:" #: ../src/ui_render.c:581 msgid "specify how much to magnify the rendering" msgstr "指定放大潤算多少" #: ../src/ui_render.c:673 msgid "couldn't allocate memory space for ui_render_t" msgstr "無法配置記憶體空間給 ui_render_t" #: ../src/ui_render.c:894 msgid "Rendering Window" msgstr "潤算視窗" #. button to reset the axis #: ../src/ui_render.c:983 msgid "Reset Axis" msgstr "重置軸線" #: ../src/ui_render.c:1039 #, c-format msgid "%s: Rendering Initialization Dialog" msgstr "%s:潤算初始化對話框" #. do we want to strip values #: ../src/ui_render.c:1075 msgid "Set values greater than max. threshold to zero?" msgstr "設定大於最大臨界值者為零?" #. do we want to converse memory #: ../src/ui_render.c:1083 msgid "Accelerate Rendering? Increases memory use ~3x" msgstr "加速潤算? 增加記憶體使用約三倍" #. do we want the initial opacities to be only density dependent #: ../src/ui_render.c:1091 msgid "Initial opacity functions only density dependent?" msgstr "初始濁度函式只相依於密度?" #: ../src/ui_render_dialog.c:323 msgid "couldn't allocate memory space for ramp x" msgstr "無法配置記憶體空間給斜面 x" #: ../src/ui_render_dialog.c:328 msgid "couldn't allocate memory space for ramp y" msgstr "無法配置記憶體空間給斜面 y" #: ../src/ui_render_dialog.c:419 msgid "Failed to Allocate Memory for Ramp" msgstr "配置記憶體給斜面時失敗" #: ../src/ui_render_dialog.c:465 #, c-format msgid "%s: Rendering Parameters Dialog" msgstr "%s:潤算參數對話框" #. widgets to change the quality versus speed of rendering #: ../src/ui_render_dialog.c:488 msgid "Speed versus Quality" msgstr "速度對品質" #. allow rendering to be click and drag #: ../src/ui_render_dialog.c:505 msgid "update without button release" msgstr "更新而不需放開按鈕" #. widget for the stereo eye angle #: ../src/ui_render_dialog.c:520 msgid "Stereo Angle" msgstr "立體角度" #. widget for the stereo eye width #: ../src/ui_render_dialog.c:534 msgid "Eye Width (mm)" msgstr "眼寬 (公釐)" #. the depth cueing enabling button #: ../src/ui_render_dialog.c:556 msgid "enable/disable depth cueing" msgstr "啟用/停用景深暗示 " #: ../src/ui_render_dialog.c:564 msgid "Front Factor" msgstr "正面因子" #: ../src/ui_render_dialog.c:577 msgid "Density" msgstr "密度" #: ../src/ui_render_dialog.c:618 #, c-format msgid "%s: Transfer Function Dialog" msgstr "%s:轉換函式對話框" #. widgets to change the returned pixel type of the rendering #: ../src/ui_render_dialog.c:644 msgid "Return Type" msgstr "回傳類型" #. color table selector #: ../src/ui_render_dialog.c:659 msgid "color table:" msgstr "顏色表格:" #: ../src/ui_render_dialog.c:686 msgid "" "Density\n" "Dependent\n" "Opacity" msgstr "" "密度\n" "相依\n" "濁度" #. gradient classification #: ../src/ui_render_dialog.c:688 msgid "" "Gradient\n" "Dependent\n" "Opacity" msgstr "" "梯度\n" "相依\n" "濁度" #. GTK no longer has a way to detect automatically when the GtkCurve has been changed, #. user will now have to explicitly change #: ../src/ui_render_dialog.c:712 msgid "Apply Curve Changes" msgstr "套用曲線變更" #: ../src/ui_render_movie.c:380 msgid "couldn't allocate memory space for ui_render_movie_t" msgstr "無法配置記憶體空間給 ui_render_movie_t" #: ../src/ui_render_movie.c:621 #, c-format msgid "%s: Rendering Movie Generation Dialog" msgstr "%s:潤算影片產生對話框" #: ../src/ui_render_movie.c:627 msgid "_Generate Movie" msgstr "產生影片(_G)" #. widgets to specify how many frames #: ../src/ui_render_movie.c:649 msgid "Movie Duration (sec)" msgstr "影片持續時間 (秒)" #: ../src/ui_render_movie.c:674 #, c-format msgid "Rotations on %s" msgstr "旋轉於 %s" #: ../src/ui_render_movie.c:825 msgid "Rendered Movie Progress" msgstr "潤算影片進度" #: ../src/ui_series.c:47 msgid "over Space" msgstr "經由空間" #: ../src/ui_series.c:48 msgid "over Time" msgstr "經由時間" #: ../src/ui_series.c:49 msgid "over Gates" msgstr "經由閘口" #: ../src/ui_series.c:53 msgid "Look at a series of images over a spatial dimension" msgstr "經由空間維度查看系列影像" #: ../src/ui_series.c:54 msgid "Look at a series of images over time" msgstr "經由時間維度查看系列影像" #: ../src/ui_series.c:55 msgid "Look at a series of images over gates" msgstr "經由閘口查看系列影像" #: ../src/ui_series.c:184 msgid "Export to Image" msgstr "匯出為影像" #: ../src/ui_series.c:250 msgid "ui_series canvas failed to return a valid image" msgstr "ui_series 畫布無法回傳有效影像" #: ../src/ui_series.c:309 msgid "No data sets to threshold\n" msgstr "沒有任何資料集可以臨界處理\n" #. File menu #: ../src/ui_series.c:373 msgid "_Export Series" msgstr "匯出系列(_E)" #: ../src/ui_series.c:373 msgid "Export the series to a JPEG image file" msgstr "匯出系列為 JPEG 圖像檔案" #: ../src/ui_series.c:374 msgid "Close the series dialog" msgstr "關閉系列對話框" #. Toolbar items #: ../src/ui_series.c:377 msgid "Threshold" msgstr "臨界值" #: ../src/ui_series.c:377 msgid "Set the thresholds and colormaps for the data sets in the series view" msgstr "設定用於系列檢視中資料集的臨界值和顏色對照表" #: ../src/ui_series.c:556 msgid "couldn't allocate memory space for ui_series_t" msgstr "無法配置記憶體空間給 ui_series_t" #: ../src/ui_series.c:674 #, c-format msgid "Slicing for series" msgstr "用於系列檢視的切片" #: ../src/ui_series.c:681 msgid "couldn't allocate memory space for pointers to image GnomeCanvasItem's" msgstr "無法配置記憶體空間給影像 GnomeCanvasItem 的指標" #: ../src/ui_series.c:686 msgid "couldn't allocate memory space for pointers to caption GnomeCanvasItem's" msgstr "無法配置記憶體空間給題要 GnomeCanvasItem 的指標" #: ../src/ui_series.c:691 msgid "couldn't allocate memory space for pointers to GnomeCanavasItem lists" msgstr "無法配置記憶體空間給 GnomeCanavasItem 清單的指標" #: ../src/ui_series.c:965 #, c-format msgid "Series: %s (%s - %s)" msgstr "系列:%s (%s - %s)" #: ../src/ui_series.c:987 msgid "Need selected objects to create a series" msgstr "需要已選物件以建立系列" #: ../src/ui_series.c:1057 msgid "Need selected data sets to generate a series of slices over time" msgstr "需要已選資料集以產生經由時的切片系列" #: ../src/ui_series.c:1065 msgid "unable to allocate memory space for frames" msgstr "無法配置記憶體空間給影格" #: ../src/ui_series.c:1074 msgid "unable to allocate memory for frame durations" msgstr "無法配置記憶體給影格持續時間" #: ../src/ui_series.c:1328 #, c-format msgid "%s: Series Initialization Dialog" msgstr "%s:系列初始化對話框" #. what series type do we want #: ../src/ui_series.c:1352 msgid "Series Type:" msgstr "系列類型:" #. what view type do we want #: ../src/ui_series.c:1390 msgid "View Type:" msgstr "檢視類型:" #. internal variables #: ../src/ui_study.c:46 msgid "new" msgstr "新" #: ../src/ui_study.c:49 msgid "m1" msgstr "m1" #: ../src/ui_study.c:49 msgid "shift-m1" msgstr "shift-m1" #: ../src/ui_study.c:50 msgid "m2" msgstr "m2" #: ../src/ui_study.c:50 msgid "shift-m2" msgstr "shift-m2" #: ../src/ui_study.c:51 msgid "m3" msgstr "m3" #: ../src/ui_study.c:51 ../src/ui_study.c:63 msgid "shift-m3" msgstr "shift-m3" #: ../src/ui_study.c:51 msgid "ctrl-m3" msgstr "ctrl-m3" #: ../src/ui_study.c:62 msgid "ctrl-x" msgstr "ctrl-x" #. BLANK #. CANVAS_FIDUCIAL_MARK #: ../src/ui_study.c:71 ../src/ui_study.c:83 msgid "move view" msgstr "移動檢視" #: ../src/ui_study.c:71 msgid "shift data set" msgstr "平移資料集" #: ../src/ui_study.c:72 ../src/ui_study.c:84 msgid "move view, min. depth" msgstr "移動檢視,最小深度" #: ../src/ui_study.c:73 ../src/ui_study.c:85 msgid "change depth" msgstr "變更深度" #: ../src/ui_study.c:73 msgid "rotate data set" msgstr "旋轉資料集" #: ../src/ui_study.c:73 ../src/ui_study.c:129 msgid "add fiducial mark" msgstr "加入基準標記" #. DATA SET #. CANVAS_ROI #. STUDY #. CANVAS_ISOCONTOUR_ROI #: ../src/ui_study.c:75 ../src/ui_study.c:79 ../src/ui_study.c:87 #: ../src/ui_study.c:91 ../src/ui_study.c:121 msgid "shift" msgstr "平移" #: ../src/ui_study.c:76 msgid "scale" msgstr "伸縮" #: ../src/ui_study.c:77 ../src/ui_study.c:125 msgid "rotate" msgstr "旋轉" #: ../src/ui_study.c:77 ../src/ui_study.c:89 ../src/ui_study.c:93 msgid "set data set inside roi to zero" msgstr "設定 roi 內部資料集為零" #: ../src/ui_study.c:78 ../src/ui_study.c:90 ../src/ui_study.c:94 msgid "set data set outside roi to zero" msgstr "設定 roi 外部資料集為零" #: ../src/ui_study.c:85 msgid "rotate study" msgstr "旋轉檢驗" #: ../src/ui_study.c:88 ../src/ui_study.c:92 msgid "enter draw mode" msgstr "輸入繪製模式" #: ../src/ui_study.c:89 msgid "start isocontour change" msgstr "開始輪廓面變更" #. CANVAS_FREEHAND_ROI #: ../src/ui_study.c:95 msgid "draw point" msgstr "繪製點" #: ../src/ui_study.c:95 msgid "draw large point" msgstr "繪製大點" #: ../src/ui_study.c:96 msgid "leave draw mode" msgstr "離開繪製模式" #: ../src/ui_study.c:97 msgid "erase point" msgstr "清除點" #: ../src/ui_study.c:97 msgid "erase large point" msgstr "清除大點" #. CANVAS_DRAWING_MODE #: ../src/ui_study.c:99 msgid "move line" msgstr "移動線條" #: ../src/ui_study.c:101 msgid "rotate line" msgstr "旋轉線條" #. CANVAS_LINE_PROFILE #: ../src/ui_study.c:103 msgid "draw - edge-to-edge" msgstr "繪製 - 邊緣到邊緣" #: ../src/ui_study.c:104 msgid "draw - center out" msgstr "繪製 - 從中心向外" #. CANVAS_NEW_ROI #: ../src/ui_study.c:107 msgid "pick isocontour start point" msgstr "揀取輪廓面開始點" #. CANVAS_NEW_ISOCONTOUR_ROI #: ../src/ui_study.c:111 msgid "pick freehand drawing start point" msgstr "揀取手繪開始點" #. CANVAS_NEW_FREEHAND_ROI #. CANVAS CHANGE ISOCONTOUR #. CANVAS SHIFT OBJECT #: ../src/ui_study.c:115 ../src/ui_study.c:119 ../src/ui_study.c:123 msgid "cancel" msgstr "取消" #: ../src/ui_study.c:117 msgid "pick new isocontour" msgstr "揀取新的輪廓面" #. CANVAS ROTATE OBJECT #: ../src/ui_study.c:127 msgid "select data set" msgstr "選取資料集" #: ../src/ui_study.c:128 ../src/ui_study.c:140 msgid "make active" msgstr "使其作用" #: ../src/ui_study.c:129 msgid "pop up data set dialog" msgstr "彈出資料集對話框" #: ../src/ui_study.c:129 ../src/ui_study.c:141 ../src/ui_study.c:145 msgid "add roi" msgstr "加入 roi" #: ../src/ui_study.c:130 msgid "delete data set" msgstr "刪除資料集" #. TREE_DATA_SET #: ../src/ui_study.c:131 msgid "select roi" msgstr "選取 roi" #: ../src/ui_study.c:132 msgid "center view on roi" msgstr "以 ROI 為中心的檢視" #: ../src/ui_study.c:133 msgid "pop up roi dialog" msgstr "彈出 roi 對話框" #: ../src/ui_study.c:134 msgid "delete roi" msgstr "刪除 roi" #. TREE_ROI #: ../src/ui_study.c:135 msgid "select point" msgstr "選取點" #: ../src/ui_study.c:136 msgid "center view on point" msgstr "以點為中心的檢視" #: ../src/ui_study.c:137 msgid "pop up point dialog" msgstr "彈出點對話框" #: ../src/ui_study.c:138 msgid "delete mark" msgstr "刪除標記" #: ../src/ui_study.c:141 msgid "pop up study dialog" msgstr "彈出檢驗對話框" #: ../src/ui_study.c:335 msgid "_View" msgstr "檢視(_V)" #: ../src/ui_study.c:336 msgid "_Tools" msgstr "工具(_T)" #. submenus #: ../src/ui_study.c:340 msgid "Import File (_specify)" msgstr "匯入檔案 (指定類型)(_S)" #. N_("Import an image data file into this study, specifying the import type"), #: ../src/ui_study.c:342 msgid "_Export View" msgstr "匯出檢視(_E)" #. N_("Export one of the views to a picture file") #: ../src/ui_study.c:344 msgid "Add _ROI" msgstr "加入 _ROI" #: ../src/ui_study.c:347 msgid "Generate _Fly Through" msgstr "產生掃視(_F)" #. FileMenu #: ../src/ui_study.c:352 msgid "_New Study" msgstr "新檢驗(_N)" #: ../src/ui_study.c:352 msgid "Create a new study viewer window" msgstr "建立新的檢驗檢視器視窗" #: ../src/ui_study.c:353 msgid "_Open Study" msgstr "開啟檢驗(_O)" #: ../src/ui_study.c:353 msgid "Open a previously saved study (XIF file)" msgstr "開啟之前儲存的檢驗 (XIF 檔案)" #: ../src/ui_study.c:354 msgid "Save Study As" msgstr "儲存檢驗為" #: ../src/ui_study.c:354 msgid "Save current study (as a XIF file)" msgstr "儲存目前的檢驗 (存成 XIF 檔案)" #: ../src/ui_study.c:355 msgid "Import File (guess)" msgstr "匯入檔案 (猜測類型)" #: ../src/ui_study.c:355 msgid "Import an image data file into this study, guessing at the file type" msgstr "匯入影像資料檔案到這個檢驗,並猜測檔案類型" #: ../src/ui_study.c:356 msgid "Import _Object from Study" msgstr "從檢驗匯入物件(_O)" #: ../src/ui_study.c:356 msgid "Import an object, such as an ROI, from a preexisting study (XIF file)" msgstr "匯入像是 ROI 的物件自既有的檢驗 (XIF 檔案)" #: ../src/ui_study.c:357 msgid "Export _Data Set" msgstr "匯出資料集(_D)" #: ../src/ui_study.c:357 msgid "Export data set(s) to a medical image format" msgstr "匯出資料集為醫學影像格式" #: ../src/ui_study.c:358 msgid "_Recover Study" msgstr "回復檢驗(_R)" #: ../src/ui_study.c:358 msgid "Try to recover a corrupted XIF file" msgstr "嘗試回復已損壞的 XIF 檔案" #: ../src/ui_study.c:359 msgid "Open XIF Directory" msgstr "開啟 XIF 目錄" #: ../src/ui_study.c:359 msgid "Open a study stored in XIF directory format" msgstr "開啟以 XIF 目錄格式儲存的檢驗" #: ../src/ui_study.c:360 msgid "Save As XIF Drectory" msgstr "另存為 XIF 目錄" #: ../src/ui_study.c:360 msgid "Save a study in XIF directory format" msgstr "以 XIF 目錄格式儲存檢驗" #: ../src/ui_study.c:361 msgid "Import from XIF Directory" msgstr "從 XIF 目錄匯入" #: ../src/ui_study.c:361 msgid "Import an object, such as an ROI, from a preexisting XIF directory" msgstr "匯入像是 ROI 的物件自既有的 XIF 目錄" #: ../src/ui_study.c:362 msgid "Close the current study" msgstr "關閉目前的檢驗" #: ../src/ui_study.c:363 msgid "Quit AMIDE" msgstr "離開 AMIDE" #. ExportView Submenu #: ../src/ui_study.c:366 ../src/ui_study.c:391 msgid "_Transverse" msgstr "橫切面(_T)" #: ../src/ui_study.c:366 msgid "Export the current transaxial view to an image file (JPEG/TIFF/PNG/etc.)" msgstr "匯出目前的橫切面檢視到影像檔案 (JPEG/TIFF/PNG/...)" #: ../src/ui_study.c:367 ../src/ui_study.c:392 msgid "_Coronal" msgstr "冠切面(_C)" #: ../src/ui_study.c:367 msgid "Export the current coronal view to an image file (JPEG/TIFF/PNG/etc.)" msgstr "匯出目前的冠切面檢視到影像檔案 (JPEG/TIFF/PNG/...)" #: ../src/ui_study.c:368 ../src/ui_study.c:393 msgid "_Sagittal" msgstr "縱切面(_S)" #: ../src/ui_study.c:368 msgid "Export the current sagittal view to an image file (JPEG/TIFF/PNG/etc.)" msgstr "匯出目前的縱切面檢視到影像檔案 (JPEG/TIFF/PNG/...)" #. EditMenu #: ../src/ui_study.c:371 msgid "Add _Fiducial Mark" msgstr "加入基準標記(_F)" #: ../src/ui_study.c:371 msgid "Add a new fiducial mark to the active data set" msgstr "加入新的基準標記到作用資料集" #. ViewMenu #: ../src/ui_study.c:375 msgid "_Series" msgstr "系列(_S)" #: ../src/ui_study.c:375 msgid "Look at a series of images" msgstr "查看影像系列" #: ../src/ui_study.c:377 msgid "_Volume Rendering" msgstr "體積潤算中(_V)" #: ../src/ui_study.c:377 msgid "perform a volume rendering on the currently selected objects" msgstr "對目前已選物件施行體積潤算" #. ToolsMenu #: ../src/ui_study.c:381 msgid "_Alignment Wizard" msgstr "對齊精靈(_A)" #: ../src/ui_study.c:381 msgid "guides you throw the processing of alignment" msgstr "逐步指引您對齊的程序" #: ../src/ui_study.c:382 msgid "_Crop Active Data Set" msgstr "裁剪作用資料集(_C)" #: ../src/ui_study.c:382 msgid "allows you to crop the active data set" msgstr "允許您裁剪作用資料集" #: ../src/ui_study.c:383 msgid "_Factor Analysis" msgstr "因素分析(_F)" #: ../src/ui_study.c:383 msgid "allows you to do factor analysis of dynamic data on the active data set" msgstr "允許您於作用資料集進行動態資料的因素分析" #: ../src/ui_study.c:384 msgid "_Filter Active Data Set" msgstr "篩選作用資料集(_F)" #: ../src/ui_study.c:384 msgid "allows you to filter the active data set" msgstr "允許您篩選作用資料集" #: ../src/ui_study.c:385 msgid "Generate Line _Profile" msgstr "產生曲線輪廓(_P)" #: ../src/ui_study.c:385 msgid "allows generating a line profile between two fiducial marks" msgstr "允許在兩個基準標記之間產生曲線輪廓" #: ../src/ui_study.c:386 msgid "Perform _Math on Data Sets" msgstr "於資料集施行數學運算(_M)" #: ../src/ui_study.c:386 msgid "allows doing simple math operations between data sets" msgstr "允許在資料集之間進行簡單的數學計算" #: ../src/ui_study.c:387 msgid "Calculate _ROI Statistics" msgstr "計算 _ROI 統計資訊" #: ../src/ui_study.c:387 msgid "caculate ROI statistics" msgstr "計算 ROI 統計資訊" #: ../src/ui_study.c:391 msgid "Generate a fly through using transaxial slices" msgstr "使用橫切面切片產生掃視" #: ../src/ui_study.c:392 msgid "Generate a fly through using coronal slices" msgstr "使用冠切面切片產生掃視" #: ../src/ui_study.c:393 msgid "Generate a fly through using sagittal slices" msgstr "使用縱切面切片產生掃視" #. Toolbar items #: ../src/ui_study.c:397 msgid "_Threshold" msgstr "臨界值(_T)" #: ../src/ui_study.c:397 msgid "Set the thresholds and colormaps for the active data set" msgstr "設定作用資料集的臨界值和顏色對照表" #: ../src/ui_study.c:402 msgid "Near." msgstr "鄰近" #: ../src/ui_study.c:403 msgid "Tri." msgstr "三線" #: ../src/ui_study.c:407 msgid "Blend" msgstr "漸變" #: ../src/ui_study.c:407 msgid "blend all data sets" msgstr "混合所有資料集" #: ../src/ui_study.c:408 msgid "Overlay" msgstr "外罩" #: ../src/ui_study.c:408 msgid "overlay active data set on blended data sets" msgstr "將作用資料集外罩於混和資料集" #: ../src/ui_study.c:412 msgid "Single" msgstr "單一" #: ../src/ui_study.c:412 msgid "All objects are shown in a single view" msgstr "所有物件顯示在單一檢視中" #: ../src/ui_study.c:413 msgid "2-way" msgstr "雙向" #: ../src/ui_study.c:413 msgid "Objects are shown between 2 linked views" msgstr "物件顯示在 2 鏈結檢視之間" #: ../src/ui_study.c:414 msgid "3-way" msgstr "三向" #: ../src/ui_study.c:414 msgid "Objects are shown between 3 linked views" msgstr "物件顯示在 3 鏈結檢視之間" #: ../src/ui_study.c:420 msgid "Target" msgstr "目標" #: ../src/ui_study.c:420 msgid "Leave crosshairs on views" msgstr "保留十字準線於檢視" #: ../src/ui_study.c:421 msgid "Transverse" msgstr "橫切面" #: ../src/ui_study.c:421 msgid "Enable transverse view" msgstr "啟用橫切面檢視" #: ../src/ui_study.c:422 msgid "Coronal" msgstr "冠切面" #: ../src/ui_study.c:422 msgid "Enable coronal view" msgstr "啟用冠切面檢視" #: ../src/ui_study.c:423 msgid "Sagittal" msgstr "縱切面" #: ../src/ui_study.c:423 msgid "Enable sagittal view" msgstr "啟用縱切面檢視" #: ../src/ui_study.c:691 msgid "specify how much to magnify the images" msgstr "指定影像要放大多少" #. add the field of view widget to our toolbar #: ../src/ui_study.c:697 msgid "fov (%):" msgstr "檢視範圍 (%):" #: ../src/ui_study.c:712 msgid "specify how much of the image field of view to display" msgstr "指定要顯示多少的影像檢視範圍" #. add the slice thickness selector #: ../src/ui_study.c:718 msgid "thickness (mm):" msgstr "厚度 (公釐):" #: ../src/ui_study.c:731 msgid "specify how thick to make the slices (mm)" msgstr "指定切片要多厚 (公釐)" #. gate #. note, can't use gtk_tool_button, as no way to set the relief in gtk 2.10, and the default #. is no relief so you can't tell that it's a button.... - #: ../src/ui_study.c:739 msgid "gate:" msgstr "閘口:" #: ../src/ui_study.c:745 msgid "the gate range over which to view the data" msgstr "檢視資料所經由的閘口範圍" #. frame selector #: ../src/ui_study.c:752 msgid "time:" msgstr "時間:" #: ../src/ui_study.c:758 msgid "the time range over which to view the data (s)" msgstr "檢視資料所經由的時間範圍 (秒)" #: ../src/ui_study.c:949 #, c-format msgid "" "Adding fiducial mark for data set: %s\n" "Enter the mark's name:" msgstr "" "加入基準標記於資料集:%s\n" "輸入標記名稱:" #: ../src/ui_study.c:995 #, c-format msgid "" "Adding ROI to: %s\n" "Enter ROI Name:" msgstr "" "加入 ROI 到:%s\n" "輸入 ROI 名稱:" #: ../src/ui_study.c:1052 #, c-format msgid "%d-%d" msgstr "%d-%d" #: ../src/ui_study.c:1056 #, c-format msgid "N/A" msgstr "無法提供" #: ../src/ui_study.c:1069 #, c-format msgid "%g-%g s" msgstr "%g-%g 秒" #: ../src/ui_study.c:1150 #, c-format msgid "[x,y,z] = [% 5.2f,% 5.2f,% 5.2f] mm" msgstr "[x,y,z] = [% 5.2f,% 5.2f,% 5.2f] 公釐" #: ../src/ui_study.c:1153 #, c-format msgid "value = % 5.3g" msgstr "數值 = % 5.3g" #: ../src/ui_study.c:1155 #, c-format msgid "value = none" msgstr "數值 = 無" #: ../src/ui_study.c:1157 #, c-format msgid "shift (x,y,z) =" msgstr "平移 (x,y,z) =" #: ../src/ui_study.c:1158 ../src/ui_study.c:1167 #, c-format msgid "[% 5.2f,% 5.2f,% 5.2f] mm" msgstr "[% 5.2f,% 5.2f,% 5.2f] 公釐" #: ../src/ui_study.c:1162 #, c-format msgid "theta = % 5.3f degrees" msgstr "theta = % 5.3f 度" #: ../src/ui_study.c:1166 #, c-format msgid "view center (x,y,z) =" msgstr "檢視中心 (x,y,z) =" #: ../src/ui_study.c:1364 #, c-format msgid "Study: %s %s" msgstr "檢驗:%s %s" #: ../src/ui_study.c:1368 #, c-format msgid "Study: %s (%s) %s" msgstr "檢驗:%s (%s) %s" #: ../src/ui_study_cb.c:58 msgid "This wizard requires compiled in support from the GNU Scientific Library (libgsl), which this copy of AMIDE does not have." msgstr "這個精靈需要編譯時就支援 GNU 科學函式庫 (libgsl),而此份 AMIDE 並沒有。" #: ../src/ui_study_cb.c:77 #, c-format msgid "%s: Pick Object(s) to Import" msgstr "%s:揀取物件以匯入" #: ../src/ui_study_cb.c:149 msgid "XIF Files" msgstr "XIF 檔案" #: ../src/ui_study_cb.c:156 msgid "All Files" msgstr "所有檔案" #. get the name of the file to import #: ../src/ui_study_cb.c:169 msgid "Recover AMIDE XIF FILE" msgstr "回復 AMIDE XIF 檔案" #: ../src/ui_study_cb.c:169 msgid "Open AMIDE XIF File" msgstr "開啟 AMIDE XIF 檔案" #: ../src/ui_study_cb.c:189 ../src/ui_study_cb.c:373 #, c-format msgid "Inappropriate filename: %s" msgstr "不適當檔名:%s" #: ../src/ui_study_cb.c:199 #, c-format msgid "error recovering study: %s" msgstr "回復檢驗時發生錯誤:%s" #: ../src/ui_study_cb.c:202 #, c-format msgid "error loading study: %s" msgstr "載入檢驗時發生錯誤:%s" #: ../src/ui_study_cb.c:299 #, c-format msgid "Overwrite file: %s" msgstr "覆寫檔案:%s" #. get the name of the file to import #: ../src/ui_study_cb.c:322 msgid "Save AMIDE XIF File" msgstr "儲存 AMIDE XIF 檔案" #. get the name of the file to import #: ../src/ui_study_cb.c:430 msgid "Import File" msgstr "匯入檔案" #: ../src/ui_study_cb.c:447 #, c-format msgid "Inappropriate Filename: %s" msgstr "不適當檔名:%s" #: ../src/ui_study_cb.c:479 #, c-format msgid "Could not import data sets from file %s\n" msgstr "無法匯入資料集自檔案 %s\n" #: ../src/ui_study_cb.c:498 msgid "There's currently no active data set to export" msgstr "目前沒有作用中資料集可供匯出" #: ../src/ui_study_cb.c:700 msgid "no active data set to erase from" msgstr "沒有作用中資料集可供清除" #: ../src/ui_study_cb.c:709 #, c-format msgid "" "Do you really wish to erase the data set %s\n" " to the ROI: %s\n" " on the data set: %s\n" "This step is irreversible\n" "The minimum threshold value: %5.3f\n" " will be used to fill in the volume" msgstr "" "您真的希望要清除資料集 %s\n" " 到 ROI:%s\n" " 於資料集:%s\n" "這個步驟是不可回復的\n" "最小臨界值:%5.3f\n" " 將被用來填入體積" #: ../src/ui_study_cb.c:710 msgid "exterior" msgstr "外部" #: ../src/ui_study_cb.c:710 msgid "interior" msgstr "內部" #: ../src/ui_study_cb.c:822 #, c-format msgid "Do you really want to delete: %s%s" msgstr "您真的要刪除:%s%s" #: ../src/ui_study_cb.c:825 msgid "" "\n" "and its children" msgstr "" "\n" "以及它的子項" #: ../src/ui_study_cb.c:1321 msgid "" "There are unsaved changes to the study.\n" "Are you sure you wish to quit?" msgstr "" "有些檢驗的變更尚未儲存。\n" "您確定想要離開嗎?" #: ../src/ui_time_dialog.c:59 ../src/ui_time_dialog.c:485 msgid "Start (s)" msgstr "開始 (秒)" #: ../src/ui_time_dialog.c:60 ../src/ui_time_dialog.c:504 msgid "End (s)" msgstr "結束 (秒)" #: ../src/ui_time_dialog.c:61 msgid "Frame #" msgstr "影格 #" #: ../src/ui_time_dialog.c:242 msgid "can't count frames or allocate memory!" msgstr "無法計數影格或配置記憶體!" #: ../src/ui_time_dialog.c:459 #, c-format msgid "%s: Time Dialog" msgstr "%s:時間對話框" #: ../src/xml.c:172 #, c-format msgid "Couldn't read time value for %s, substituting %5.3f" msgstr "無法讀取 %s 的時間值,替代為 %5.3f" #: ../src/xml.c:201 ../src/xml.c:242 msgid "Couldn't allocate memory space for time data" msgstr "無法配置記憶體空間給時間資料" #: ../src/xml.c:233 msgid "XIF File appears corrupted, setting frame durations to 1" msgstr "XIF 檔案出現損壞,設定影格持續時間為 1" #: ../src/xml.c:240 #, c-format msgid "Couldn't read value for %s, substituting 1" msgstr "無法讀取 %s 的值,替代為 1" #: ../src/xml.c:287 #, c-format msgid "Couldn't read value for %s, substituting %5.3f" msgstr "無法讀取 %s 的值,替代為 %5.3f" #: ../src/xml.c:349 #, c-format msgid "Couldn't read value for %s, substituting FALSE" msgstr "無法讀取 %s 的值,替代為 FALSE" #: ../src/xml.c:385 #, c-format msgid "Couldn't read value for %s, substituting %d" msgstr "無法讀取 %s 的值,替代為 %d" #: ../src/xml.c:426 #, c-format msgid "Couldn't read value for %s, substituting 0x%llx 0x%llx" msgstr "無法讀取 %s 的值,替代為 0x%llx 0x%llx" #: ../src/xml.c:663 #, c-format msgid "Couldn't Parse AMIDE xml file %s" msgstr "無法剖析 AMIDE xml 檔案 %s" #: ../src/xml.c:687 #, c-format msgid "Could not seek to location %lx in file." msgstr "無法尋指到檔案中的位置 %lx。" #: ../src/xml.c:693 #, c-format msgid "Only read %x bytes from file, expected %x" msgstr "只從檔案讀取了 %x 位元組,預期為 %x" amide-1.0.6/amide-current/src/000077500000000000000000000000001423227705100161265ustar00rootroot00000000000000amide-1.0.6/amide-current/src/Makefile.am000066400000000000000000000326761423227705100202000ustar00rootroot00000000000000if AMIDE_OS_WIN32 AMIDE_LDADD_WIN32 = -lwsock32 ../win32/amiderc.o AMIDE_LDFLAGS_WIN32 = -mwindows #INCLUDES = \ # -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" else AMIDE_LDADD_WIN32 = AMIDE_LDFLAGS_WIN32 = endif AM_CPPFLAGS = \ -DAMIDE_PREFIX=\""$(prefix)"\" \ -DAMIDE_SYSCONFDIR=\""$(sysconfdir)"\" \ -DAMIDE_DATADIR=\""$(datadir)"\" \ -DAMIDE_LIBDIR=\""$(libdir)"\" ## -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ AM_CFLAGS = \ $(OPTIMIZATION_CFLAGS) \ $(GSL_CFLAGS) \ $(LIBFAME_CFLAGS) \ $(AMIDE_GTK_CFLAGS) \ $(AMIDE_DEBUG_CFLAGS) \ $(AMIDE_CHECK_OBSOLETE_CFLAGS) \ $(AMIDE_LIBDCMDATA_CFLAGS) \ -I/usr/local/include \ $(XMEDCON_CFLAGS) \ $(FFMPEG_CFLAGS) \ $(VISTAIO_CFLAGS) \ $(LIBOPENJP2_CFLAGS) ## c++ gets the same includes AM_CXXFLAGS = $(AM_CFLAGS) bin_PROGRAMS = amide # for some reason, the -wsock32 added by AMIDE_LDADD_WIN32 on windows has # to be behind the DCMTK stuff amide_LDADD = \ $(GSL_LIBS) \ $(LIBFAME_LIBS) \ $(AMIDE_LIBECAT_LIBS) \ $(AMIDE_LIBVOLPACK_LIBS) \ $(AMIDE_GTK_LIBS) \ $(XMEDCON_LIBS) \ $(FFMPEG_LIBS) \ $(AMIDE_LIBDCMDATA_LIBS) \ $(VISTAIO_LIBS) \ $(LIBOPENJP2_LIBS) \ $(AMIDE_LDADD_WIN32) ## 2007.10.28, gcc 3.4.4 the below may no longer be an issue, as ## xmedcon can now be glib2/gtk2 based. But haven't tested ## ## 2005.01.08, gcc 3.3.3 ## note, for some reason, if XMEDCON_LIBS is before AMIDE_GTK_LIBS, ## an executable is made that dumps core on startup.... ## this is probably because xmedcon is linked with glib 1.2... while ## amide needs glib 2.*, and something is clashing in name space amide_LDFLAGS = \ $(AMIDE_LDFLAGS_WIN32) amide_SOURCES = \ $(MARSHAL_SOURCES) \ $(TYPE_BUILTINS_SOURCES) \ $(AMITK_RAW_DATA_VARIABLE_H) \ $(AMITK_RAW_DATA_VARIABLE_C) \ $(AMITK_DATA_SET_VARIABLE_H) \ $(AMITK_DATA_SET_VARIABLE_C) \ $(AMITK_ROI_VARIABLE_H) \ $(AMITK_ROI_VARIABLE_C) \ $(AMITK_H_SOURCES) \ amide.h \ amide.c \ amide_intl.h \ amide_gconf.c \ amide_gconf.h \ amide_gnome.c \ amide_gnome.h \ amitk_common.c \ amitk_common.h \ amitk_canvas.c \ amitk_canvas_object.c \ amitk_color_table.c \ amitk_color_table_menu.c \ amitk_data_set.c \ amitk_dial.c \ amitk_fiducial_mark.c \ amitk_filter.c \ amitk_line_profile.c \ amitk_object.c \ amitk_object_dialog.c \ amitk_point.c \ amitk_preferences.c \ amitk_progress_dialog.c \ amitk_raw_data.c \ amitk_roi.c \ amitk_space.c \ amitk_space_edit.c \ amitk_study.c \ amitk_threshold.c \ amitk_tree_view.c \ amitk_volume.c \ amitk_window_edit.c \ alignment_mutual_information.c \ alignment_mutual_information.h \ alignment_procrustes.c \ alignment_procrustes.h \ analysis.c \ analysis.h \ dcmtk_interface.cc \ dcmtk_interface.h \ fads.c \ fads.h \ image.c \ image.h \ legacy.c \ legacy.h \ libecat_interface.c \ libecat_interface.h \ libmdc_interface.c \ libmdc_interface.h \ mpeg_encode.c \ mpeg_encode.h \ pixmaps.c \ pixmaps.h \ raw_data_import.c \ raw_data_import.h \ render.c \ render.h \ tb_alignment.c \ tb_alignment.h \ tb_crop.c \ tb_crop.h \ tb_distance.c \ tb_distance.h \ tb_export_data_set.c \ tb_export_data_set.h \ tb_fads.c \ tb_fads.h \ tb_filter.c \ tb_filter.h \ tb_fly_through.c \ tb_fly_through.h \ tb_math.c \ tb_math.h \ tb_profile.c \ tb_profile.h \ tb_roi_analysis.c \ tb_roi_analysis.h \ ui_common.c \ ui_common.h \ ui_gate_dialog.c \ ui_gate_dialog.h \ ui_preferences_dialog.c \ ui_preferences_dialog.h \ ui_render.c \ ui_render.h \ ui_render_dialog.c \ ui_render_dialog.h \ ui_render_movie.c \ ui_render_movie.h \ ui_series.c \ ui_series.h \ ui_study.c \ ui_study.h \ ui_study_cb.c \ ui_study_cb.h \ ui_time_dialog.c \ ui_time_dialog.h \ vistaio_interface.c \ vistaio_interface.h \ xml.c \ xml.h AMITK_H_SOURCES = \ amitk_canvas.h \ amitk_canvas_object.h \ amitk_color_table.h \ amitk_color_table_menu.h \ amitk_common.h \ amitk_dial.h \ amitk_data_set.h \ amitk_fiducial_mark.h \ amitk_filter.h \ amitk_line_profile.h \ amitk_object.h \ amitk_object_dialog.h \ amitk_point.h \ amitk_preferences.h \ amitk_progress_dialog.h \ amitk_raw_data.h \ amitk_roi.h \ amitk_space_edit.h \ amitk_space.h \ amitk_study.h \ amitk_threshold.h \ amitk_tree_view.h \ amitk_type.h \ amitk_volume.h \ amitk_window_edit.h AMITK_ROI_VARIABLE_C = \ amitk_roi_ELLIPSOID.c \ amitk_roi_CYLINDER.c \ amitk_roi_BOX.c \ amitk_roi_ISOCONTOUR_2D.c \ amitk_roi_ISOCONTOUR_3D.c \ amitk_roi_FREEHAND_2D.c \ amitk_roi_FREEHAND_3D.c AMITK_ROI_VARIABLE_H = \ amitk_roi_ELLIPSOID.h \ amitk_roi_CYLINDER.h \ amitk_roi_BOX.h \ amitk_roi_ISOCONTOUR_2D.h \ amitk_roi_ISOCONTOUR_3D.h \ amitk_roi_FREEHAND_2D.h \ amitk_roi_FREEHAND_3D.h AMITK_RAW_DATA_VARIABLE_C = \ amitk_raw_data_UBYTE.c \ amitk_raw_data_SBYTE.c \ amitk_raw_data_USHORT.c \ amitk_raw_data_SSHORT.c \ amitk_raw_data_UINT.c \ amitk_raw_data_SINT.c \ amitk_raw_data_FLOAT.c \ amitk_raw_data_DOUBLE.c AMITK_RAW_DATA_VARIABLE_H = \ amitk_raw_data_UBYTE.h \ amitk_raw_data_SBYTE.h \ amitk_raw_data_USHORT.h \ amitk_raw_data_SSHORT.h \ amitk_raw_data_UINT.h \ amitk_raw_data_SINT.h \ amitk_raw_data_FLOAT.h \ amitk_raw_data_DOUBLE.h AMITK_DATA_SET_VARIABLE_C = \ amitk_data_set_UBYTE_0D_SCALING.c \ amitk_data_set_UBYTE_1D_SCALING.c \ amitk_data_set_UBYTE_2D_SCALING.c \ amitk_data_set_SBYTE_0D_SCALING.c \ amitk_data_set_SBYTE_1D_SCALING.c \ amitk_data_set_SBYTE_2D_SCALING.c \ amitk_data_set_USHORT_0D_SCALING.c \ amitk_data_set_USHORT_1D_SCALING.c \ amitk_data_set_USHORT_2D_SCALING.c \ amitk_data_set_SSHORT_0D_SCALING.c \ amitk_data_set_SSHORT_1D_SCALING.c \ amitk_data_set_SSHORT_2D_SCALING.c \ amitk_data_set_UINT_0D_SCALING.c \ amitk_data_set_UINT_1D_SCALING.c \ amitk_data_set_UINT_2D_SCALING.c \ amitk_data_set_SINT_0D_SCALING.c \ amitk_data_set_SINT_1D_SCALING.c \ amitk_data_set_SINT_2D_SCALING.c \ amitk_data_set_FLOAT_0D_SCALING.c \ amitk_data_set_FLOAT_1D_SCALING.c \ amitk_data_set_FLOAT_2D_SCALING.c \ amitk_data_set_DOUBLE_0D_SCALING.c \ amitk_data_set_DOUBLE_1D_SCALING.c \ amitk_data_set_DOUBLE_2D_SCALING.c \ amitk_data_set_UBYTE_0D_SCALING_INTERCEPT.c \ amitk_data_set_UBYTE_1D_SCALING_INTERCEPT.c \ amitk_data_set_UBYTE_2D_SCALING_INTERCEPT.c \ amitk_data_set_SBYTE_0D_SCALING_INTERCEPT.c \ amitk_data_set_SBYTE_1D_SCALING_INTERCEPT.c \ amitk_data_set_SBYTE_2D_SCALING_INTERCEPT.c \ amitk_data_set_USHORT_0D_SCALING_INTERCEPT.c \ amitk_data_set_USHORT_1D_SCALING_INTERCEPT.c \ amitk_data_set_USHORT_2D_SCALING_INTERCEPT.c \ amitk_data_set_SSHORT_0D_SCALING_INTERCEPT.c \ amitk_data_set_SSHORT_1D_SCALING_INTERCEPT.c \ amitk_data_set_SSHORT_2D_SCALING_INTERCEPT.c \ amitk_data_set_UINT_0D_SCALING_INTERCEPT.c \ amitk_data_set_UINT_1D_SCALING_INTERCEPT.c \ amitk_data_set_UINT_2D_SCALING_INTERCEPT.c \ amitk_data_set_SINT_0D_SCALING_INTERCEPT.c \ amitk_data_set_SINT_1D_SCALING_INTERCEPT.c \ amitk_data_set_SINT_2D_SCALING_INTERCEPT.c \ amitk_data_set_FLOAT_0D_SCALING_INTERCEPT.c \ amitk_data_set_FLOAT_1D_SCALING_INTERCEPT.c \ amitk_data_set_FLOAT_2D_SCALING_INTERCEPT.c \ amitk_data_set_DOUBLE_0D_SCALING_INTERCEPT.c \ amitk_data_set_DOUBLE_1D_SCALING_INTERCEPT.c \ amitk_data_set_DOUBLE_2D_SCALING_INTERCEPT.c AMITK_DATA_SET_VARIABLE_H = \ amitk_data_set_UBYTE_0D_SCALING.h \ amitk_data_set_UBYTE_1D_SCALING.h \ amitk_data_set_UBYTE_2D_SCALING.h \ amitk_data_set_SBYTE_0D_SCALING.h \ amitk_data_set_SBYTE_1D_SCALING.h \ amitk_data_set_SBYTE_2D_SCALING.h \ amitk_data_set_USHORT_0D_SCALING.h \ amitk_data_set_USHORT_1D_SCALING.h \ amitk_data_set_USHORT_2D_SCALING.h \ amitk_data_set_SSHORT_0D_SCALING.h \ amitk_data_set_SSHORT_1D_SCALING.h \ amitk_data_set_SSHORT_2D_SCALING.h \ amitk_data_set_UINT_0D_SCALING.h \ amitk_data_set_UINT_1D_SCALING.h \ amitk_data_set_UINT_2D_SCALING.h \ amitk_data_set_SINT_0D_SCALING.h \ amitk_data_set_SINT_1D_SCALING.h \ amitk_data_set_SINT_2D_SCALING.h \ amitk_data_set_FLOAT_0D_SCALING.h \ amitk_data_set_FLOAT_1D_SCALING.h \ amitk_data_set_FLOAT_2D_SCALING.h \ amitk_data_set_DOUBLE_0D_SCALING.h \ amitk_data_set_DOUBLE_1D_SCALING.h \ amitk_data_set_DOUBLE_2D_SCALING.h VARIABLE_INPUT = \ variable_type.m4 AMITK_ROI_VARIABLE_C_SRC = amitk_roi_variable_type.c AMITK_ROI_VARIABLE_H_SRC = amitk_roi_variable_type.h AMITK_RAW_DATA_VARIABLE_C_SRC = amitk_raw_data_variable_type.c AMITK_RAW_DATA_VARIABLE_H_SRC = amitk_raw_data_variable_type.h AMITK_DATA_SET_VARIABLE_C_SRC = amitk_data_set_variable_type.c AMITK_DATA_SET_VARIABLE_H_SRC = amitk_data_set_variable_type.h $(AMITK_ROI_VARIABLE_H): $(VARIABLE_INPUT) $(AMITK_ROI_VARIABLE_H_SRC) @for i in $(AMITK_ROI_VARIABLE_H) ; \ do \ rm -f $$i ;\ echo "$(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i" ;\ $(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i; \ chmod -w $$i; \ done $(AMITK_ROI_VARIABLE_C): $(VARIABLE_INPUT) $(AMITK_ROI_VARIABLE_C_SRC) $(AMITK_ROI_VARIABLE_H) @for i in $(AMITK_ROI_VARIABLE_C) ; \ do \ rm -f $$i ;\ echo "$(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i" ;\ $(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i; \ chmod -w $$i; \ done $(AMITK_RAW_DATA_VARIABLE_C): $(VARIABLE_INPUT) $(AMITK_RAW_DATA_VARIABLE_C_SRC) $(AMITK_RAW_DATA_VARIABLE_H) @for i in $(AMITK_RAW_DATA_VARIABLE_C) ; \ do \ rm -f $$i ;\ echo "$(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i" ;\ $(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i; \ chmod -w $$i; \ done $(AMITK_RAW_DATA_VARIABLE_H): $(VARIABLE_INPUT) $(AMITK_RAW_DATA_VARIABLE_H_SRC) @for i in $(AMITK_RAW_DATA_VARIABLE_H) ; \ do \ rm -f $$i ;\ echo "$(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i" ;\ $(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i; \ chmod -w $$i; \ done $(AMITK_DATA_SET_VARIABLE_C): $(VARIABLE_INPUT) $(AMITK_DATA_SET_VARIABLE_C_SRC) $(AMITK_DATA_SET_VARIABLE_H) @for i in $(AMITK_DATA_SET_VARIABLE_C) ; \ do \ rm -f $$i ;\ echo "$(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i" ;\ $(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i; \ chmod -w $$i; \ done $(AMITK_DATA_SET_VARIABLE_H): $(VARIABLE_INPUT) $(AMITK_DATA_SET_VARIABLE_H_SRC) @for i in $(AMITK_DATA_SET_VARIABLE_H) ; \ do \ rm -f $$i ;\ echo "$(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i" ;\ $(M4) -P -Dm4_SourceFile=$$i $(VARIABLE_INPUT) > $$i; \ chmod -w $$i; \ done ## $(amide_la_OBJECTS): $(MARSHAL_SOURCES) ## BUILT_SOURCES = \ ## $(MARSHAL_SOURCES) \ ## $(TYPE_BUILTINS_SOURCES) \ MARSHAL_SOURCES = \ amitk_marshal.c \ amitk_marshal.h amitk_marshal.h: amitk_marshal.list $(GLIB_GENMARSHAL) $(GLIB_GENMARSHAL) $< --header --prefix=amitk_marshal > $@ amitk_marshal.c: amitk_marshal.list $(GLIB_GENMARSHAL) amitk_marshal.h $(GLIB_GENMARSHAL) $< --body --prefix=amitk_marshal > $@ TYPE_BUILTINS_SOURCES = \ amitk_type_builtins.h \ amitk_type_builtins.c TEMP_FILES = \ xgen-atbh \ xgen-atbc STAMP_FILES = \ stamp-amitk_type_builtins.h \ stamp-amitk_type_builtins.c ## fancy rebuild rules stolen from the Makefile.am from gtk-2.0 $(srcdir)/amitk_type_builtins.h: stamp-amitk_type_builtins.h $(AMITK_DATA_SET_VARIABLE_H) $(AMITK_RAW_DATA_VARIABLE_H) @true stamp-amitk_type_builtins.h: $(AMITK_H_SOURCES) Makefile ( cd $(srcdir) && glib-mkenums \ --fhead "#ifndef __AMITK_TYPE_BUILTINS_H__\n#define __AMITK_TYPE_BUILTINS_H__\n\n#include \n\nG_BEGIN_DECLS\n" \ --fprod "/* enumerations from \"@filename@\" */\n" \ --vhead "GType @enum_name@_get_type (void);\n#define AMITK_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ --ftail "G_END_DECLS\n\n#endif /* __AMITK_TYPE_BUILTINS_H__ */" \ $(AMITK_H_SOURCES)) >> xgen-atbh \ && (cmp -s xgen-atbh $(srcdir)/amitk_type_builtins.h || cp xgen-atbh $(srcdir)/amitk_type_builtins.h ) \ && rm -f xgen-atbh \ && echo timestamp > $(@F) $(srcdir)/amitk_type_builtins.c: stamp-amitk_type_builtins.c @true stamp-amitk_type_builtins.c: $(AMITK_H_SOURCES) Makefile amitk_type_builtins.h ( cd $(srcdir) && glib-mkenums \ --fhead "#include \n#include \"amide_config.h\"\n#include \"amitk_common.h\"\n#include \"amitk_canvas.h\"\n#include \"amitk_data_set.h\"\n#include \"amitk_filter.h\"\n#include \"amitk_object.h\"\n#include \"amitk_point.h\"\n#include \"amitk_raw_data.h\"\n#include \"amitk_roi.h\"\n#include \"amitk_space.h\"\n#include \"amitk_threshold.h\"\n#include \"amitk_tree_view.h\"\n" \ --fprod "\n/* enumerations from \"@filename@\" */" \ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ $(AMITK_H_SOURCES) ) > xgen-atbc \ && cp xgen-atbc $(srcdir)/amitk_type_builtins.c \ && rm -f xgen-atbc \ && echo timestamp > $(@F) CLEANFILES = \ $(AMITK_ROI_VARIABLE_C) \ $(AMITK_ROI_VARIABLE_H) \ $(AMITK_DATA_SET_VARIABLE_C) \ $(AMITK_DATA_SET_VARIABLE_H) \ $(AMITK_RAW_DATA_VARIABLE_C) \ $(AMITK_RAW_DATA_VARIABLE_H) \ $(MARSHAL_SOURCES) \ $(TYPE_BUILTINS_SOURCES) \ $(TEMP_FILES) \ $(STAMP_FILES) DISTCLEANFILES = *~ amide-1.0.6/amide-current/src/alignment_mutual_information.c000066400000000000000000000461071423227705100242540ustar00rootroot00000000000000/* alignment_mutual_information.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2011-2012 Ian Miller * */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amitk_data_set.h" #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include "alignment_mutual_information.h" /* this algorithm will calculate the amount of mutual information between two data sets in their current orientations */ /* it is a re-write of the original algorithm for purposes of improved speed. the hope is that it won't affect accuracy. */ /* rather than computing mutual information for the whole volume of data, the algorithm computes it for three orthogonal */ /* slices: axial, sagittal, and coronal */ #define NUM_BINS 50 gdouble calculate_mutual_information(AmitkDataSet * fixed_ds, AmitkDataSet * moving_ds, AmitkSpace * new_space, gint granularity, gboolean * pfixed_slices_current, AmitkDataSet ** fixed_slice, AmitkPoint view_center, amide_real_t thickness, amide_time_t view_start_time, amide_time_t view_duration) { /* variables related to datasets, their volumes, coordinate spaces, etc */ amide_data_t value_fixed, value_moving; AmitkCanvasPoint pixel_size; /* variables related to binning and mutual information determination*/ gdouble bin_width_moving; // mutual information will be calculated bin-wise gdouble bin_width_fixed; // these values determine the size of the bins gint current_bin_number_moving; // the number of bins for the first dataset gint current_bin_number_fixed; // the number of bins for the second dataset gint mutual_information_array[NUM_BINS][NUM_BINS] = {{ 0 }} ; gint margin_moving[NUM_BINS] = { 0 }; gint margin_fixed[NUM_BINS] = { 0 }; gint margin_total = 0; gint mi_nan_count; gdouble voxel_probability; // the probability contribution of a single voxel gdouble incremental_mi; gdouble mutual_information = 0.0; // this is the return value; the amount of MI computed in the two data sets; default to zero AmitkSpace * temp_space; GList * fixed_dss; AmitkVolume * view_volume; AmitkDataSet * moving_slice; AmitkPoint temp_offset; /* loop counters */ AmitkView i_view; AmitkVoxel i_voxel; gint i, j; // temporary counters to iterate through the bins for the two datasets amide_data_t moving_global_min; amide_data_t fixed_global_min; /* use the range of values present in the data and the number of bins desired in order to determine how wide the bins should be */ moving_global_min = amitk_data_set_get_global_min(moving_ds); fixed_global_min = amitk_data_set_get_global_min(fixed_ds); bin_width_moving = (amitk_data_set_get_global_max(moving_ds) - moving_global_min) / NUM_BINS; bin_width_fixed = (amitk_data_set_get_global_max(fixed_ds) - fixed_global_min) / NUM_BINS; /* iterate through the dataset, and build up a frequency matrix for binned values */ /* granularity determines whether we look at all the voxels, or just a subset. */ /* we look at every nth voxel, where n is granularity */ pixel_size.x = pixel_size.y = granularity * point_min_dim(AMITK_DATA_SET_VOXEL_SIZE(fixed_ds)); /* iterate over the orthogonal directions */ for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { /* create a volume for the slice we're going to work on */ view_volume = amitk_volume_new(); temp_space = amitk_space_get_view_space(i_view, AMITK_LAYOUT_LINEAR); /* figure out the dimensions of the slice volume */ fixed_dss = g_list_append(NULL, amitk_object_ref(fixed_ds)); /* note, we don't bother with FOV, as that's actually computed based on all visible data sets, and we only have two of the data sets here. We'll just use 100% FOV */ amitk_volumes_calc_display_volume(fixed_dss, temp_space, view_center, thickness, 100.0, view_volume); amitk_objects_unref(fixed_dss); g_object_unref(temp_space); /* (re)calculate the fixed slice if we need to */ if ((fixed_slice[i_view] == NULL) || (*pfixed_slices_current == FALSE)) { #ifdef AMIDE_DEBUG g_print("recompute fixed slice for view %d with pixel size %f\n", i_view, pixel_size.x); #endif if (fixed_slice[i_view] != NULL) amitk_object_unref(AMITK_OBJECT(fixed_slice[i_view])); /* compute the fixed slices of data */ fixed_slice[i_view] = amitk_data_set_get_slice(fixed_ds, view_start_time, view_duration, -1, pixel_size, view_volume); } /* update the view volume by a transform to take into account the rotations/translations we're doing */ /* first take care of the axis rotation */ temp_offset = AMITK_SPACE_OFFSET(view_volume); temp_space = amitk_space_calculate_transform(new_space, AMITK_SPACE(moving_ds)); amitk_space_transform(AMITK_SPACE(view_volume), temp_space); g_object_unref(temp_space); /* second, take care of adjusting the view volume's offset. */ temp_offset = amitk_space_b2s(AMITK_SPACE(new_space), temp_offset); temp_offset = amitk_space_s2b(AMITK_SPACE(moving_ds), temp_offset); amitk_space_set_offset(AMITK_SPACE(view_volume), temp_offset); /* now calculate the slice from the moving data set, and calculate the corresponding MI */ moving_slice = amitk_data_set_get_slice(moving_ds, view_start_time, view_duration, -1, pixel_size, view_volume); /* calculate the mutual information */ i_voxel = zero_voxel; for (i_voxel.y = 0; i_voxel.y < AMITK_DATA_SET_DIM_Y(fixed_slice[i_view]); i_voxel.y++) { for (i_voxel.x = 0; i_voxel.x < AMITK_DATA_SET_DIM_X(fixed_slice[i_view]); i_voxel.x++) { /* DOUBLE_0D is the type of the slice data sets */ value_fixed = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(fixed_slice[i_view]), i_voxel); value_moving = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(moving_slice), i_voxel); /* treat any NaN or "out of volume" values as zeros */ if (isnan(value_fixed)) value_fixed = 0; if (isnan(value_moving)) value_moving = 0; current_bin_number_fixed = floor((value_fixed-fixed_global_min)/bin_width_fixed); current_bin_number_moving = floor((value_moving-moving_global_min)/bin_width_moving); g_assert(current_bin_number_fixed < NUM_BINS); g_assert(current_bin_number_moving < NUM_BINS); /* Update the count in this particular bin combination by incrementing the counter*/ mutual_information_array[current_bin_number_fixed][current_bin_number_moving]++; /* Update the *marginal* count. We could derive this, but we'll need it later, and computing it one time only should improve computation speed */ margin_fixed[current_bin_number_fixed]++; margin_moving[current_bin_number_moving]++; margin_total++; } } /* garbage collection */ amitk_object_unref(AMITK_OBJECT(view_volume)); amitk_object_unref(AMITK_OBJECT(moving_slice)); } /* mark that we may not need to recompute the fixed slices next time around */ *pfixed_slices_current = TRUE; /* calculate the "probability weight" of a single voxel */ voxel_probability = (1.0 / margin_total); /* this is an idea for later: add the MI array to the study as a data set if (mi_matrix != NULL) { // and add the mutual information matrix to the study amitk_object_add_child(AMITK_OBJECT(fixed_ds), AMITK_OBJECT(mi_matrix)); // this adds a reference to the data set amitk_object_unref(mi_matrix); // so remove a reference } else { g_warning("Failed to generate filtered data set"); } */ mutual_information = 0; /* // print the column headings in order to debug the matrix g_print("\t%i", margin_moving[0]); for (j = 1; j < NUM_BINS ; j++) { g_print("\t%i", margin_moving[j]); } */ mi_nan_count=0; for (i = 0; i < NUM_BINS ; i++) { // g_print("\n%i", margin_fixed[i]); // print the row headings in order to debug the matrix for (j = 0; j < NUM_BINS ; j++) { /* when the probability of (x AND y) == 0, then the log (x AND y) is NaN. Therefore, test for this condition, and add a zero in order to avoid blowing up the equation */ if (mutual_information_array[i][j] != 0) { incremental_mi = (mutual_information_array[i][j]*voxel_probability)*(log2((mutual_information_array[i][j] * voxel_probability) /( (margin_fixed[i] * voxel_probability)*(margin_moving[j] * voxel_probability)))); } else { // how do we deal with zero probability? There is probably a theoretical "best" answer, but this should be practical. // we are trying to avoid complete lack of overlap from looking like a "good fit" // things I've tried that *don't* work are i_mi=log2(EPSILON) and =log2(voxel_probability) incremental_mi = 0; mi_nan_count++; } /* you can choose either of the following g_print commands for debugging the matrix */ //g_print("\t\%i", mutual_information_array[i][j] ); // for point-wise counts // g_print("\t\%4.3f", incremental_mi ); // for point-wise probability if (isinf(incremental_mi)) { //count it (because lots and lots of zeroes mean bad registration) and go to the next loop mi_nan_count++; // this is most often a problem when the incemental MI is infinity, due to divide by zero } else { // add it to the mutual information metric mutual_information += (incremental_mi); } /* // debugging code g_print("Current indices are: %i, %i\n", i, j); g_print("Current prob(x,y) is: %e\n", mutual_information_array[i][j] * voxel_probability); g_print("Current prob(x) is: %e\n", margin_moving[i] * voxel_probability); g_print("Current prob(y) is: %e\n", margin_fixed[j] * voxel_probability); if (margin_moving[i] == 0 || margin_fixed[j] == 0 ) { g_print("there is a zero at i=%i, j=%i!\n", i, j); } g_print("Incremental mutual information is: %e\n", incremental_mi); if (margin_moving[i] == 0 || margin_fixed[j] == 0 ) { g_print("there is a zero at i=%i, j=%i!\n", i, j); } g_print("Incremental mutual information is: %e\n", incremental_mi); */ } } // g_print("\nThe mutual information sum is %f\n", mutual_information); // g_print("the count of NAN in the MI algorithm was\t%d\n", mi_nan_count); return mutual_information; } /* rot_x, y, and z are angles about the respective axes, in radians */ void rotate(AmitkPoint rotation, AmitkSpace * moving_space) { // apply the rotation to the data set if (rotation.x !=0) amitk_space_rotate_on_vector(AMITK_SPACE(moving_space), base_axes[AMITK_AXIS_X], rotation.x, zero_point ); if (rotation.y !=0) amitk_space_rotate_on_vector(AMITK_SPACE(moving_space), base_axes[AMITK_AXIS_Y], rotation.y, zero_point ); if (rotation.z !=0) amitk_space_rotate_on_vector(AMITK_SPACE(moving_space), base_axes[AMITK_AXIS_Z], rotation.z, zero_point ); } /* This is the algorithm responsible for computing the transform which provides the maximum amount of mutual information for coregistration */ AmitkSpace * alignment_mutual_information(AmitkDataSet * moving_ds, AmitkDataSet * fixed_ds, AmitkPoint view_center, amide_real_t thickness, amide_time_t view_start_time, amide_time_t view_duration, gdouble * pointer_mutual_information_error, AmitkUpdateFunc update_func, gpointer update_data) { #define ITERATIONS_PER_LEVEL 3 #define TRANSLATION_MAX_DISTANCE 10 #define TRANSLATION_TARGET_PRECISION 0.001 // twenty degrees: #define ROTATION_MAX_ANGLE (20*(M_PI/180)) #define ROTATION_TARGET_PRECISION (0.1*(M_PI/180)) #define INITIAL_STEP_SIZE 8 #define MIN_STEP_SIZE 8 AmitkSpace * transform_space; AmitkSpace * new_space; AmitkSpace * last_best_space; gdouble translation_precision, rotation_precision, step_size; // GRand * random_generator; gdouble current_mi = 0, best_mi = 0; AmitkPoint best_shift, best_rotation; AmitkPoint current_shift, current_rotation; gchar * temp_string; gboolean continue_work = TRUE; AmitkDataSet * fixed_slice[AMITK_VIEW_NUM] = {NULL, NULL, NULL}; gboolean fixed_slices_current; AmitkView i_view; // random_generator = g_rand_new(); /* =======================================================================================*/ /* determine the translation which maximizes shared information */ /* first pass of pyramidal descent (course alignment followed by fine alignment */ /* =======================================================================================*/ new_space = amitk_space_copy(AMITK_SPACE(moving_ds)); last_best_space = amitk_space_copy(new_space); translation_precision = TRANSLATION_MAX_DISTANCE; rotation_precision = ROTATION_MAX_ANGLE; step_size = INITIAL_STEP_SIZE; fixed_slices_current = FALSE; /* set baseline characteristics, including baseline space and initial error */ best_mi = calculate_mutual_information(fixed_ds, moving_ds, new_space, step_size, &fixed_slices_current, fixed_slice, view_center, thickness, view_start_time, view_duration); #ifdef AMIDE_DEBUG g_print("initial mi %f\n", best_mi); #endif if (update_func != NULL) { temp_string = g_strdup_printf(_("Maximizing the mutual information")); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } while (continue_work && ((translation_precision > TRANSLATION_TARGET_PRECISION) || (rotation_precision > ROTATION_TARGET_PRECISION) || ( step_size > MIN_STEP_SIZE ))) { #ifdef AMIDE_DEBUG g_print("starting descent\ttranslation precision=\t%4.4f\n\t\t\trotation precision=\t%4.4f\tdegrees\n", translation_precision, rotation_precision*180/M_PI ); #endif if (update_func != NULL) continue_work = (*update_func)(update_data, NULL, (gdouble) -1.0); best_shift = zero_point; /* current_step_size = current_iteration * translation_precision / ITERATIONS_PER_LEVEL; // * current_step_size = g_rand_double_range(random_generator, 0, translation_precision ); */ for ( current_shift.z = -translation_precision ; current_shift.z < translation_precision; current_shift.z += translation_precision / ITERATIONS_PER_LEVEL ) { for ( current_shift.y = -translation_precision; current_shift.y < translation_precision; current_shift.y += translation_precision / ITERATIONS_PER_LEVEL ) { for ( current_shift.x = -translation_precision; current_shift.x < translation_precision; current_shift.x += translation_precision / ITERATIONS_PER_LEVEL ) { /* first test whether offset increases the mutual information */ amitk_space_shift_offset(AMITK_SPACE(new_space), current_shift); current_mi = calculate_mutual_information( fixed_ds, moving_ds, new_space, step_size, &fixed_slices_current, fixed_slice, view_center, thickness, view_start_time, view_duration); /*if this location gives a better mutual information, then keep it */ if (current_mi > best_mi ) { #ifdef AMIDE_DEBUG g_print("better translation fit at %4.4f\t%4.4f\t%4.4f with mi=\t%4.4f\n", current_shift.x, current_shift.y, current_shift.z, current_mi); #endif best_mi = current_mi; best_shift = current_shift; } /* and unroll the transformation */ g_object_unref(new_space); new_space = amitk_space_copy(last_best_space); } } } /* apply/store the transform that worked best */ amitk_space_shift_offset(AMITK_SPACE(new_space), best_shift); g_object_unref(last_best_space); last_best_space = amitk_space_copy(new_space); /* =======================================================================================*/ /* determine the rotation which maximizes shared information */ /* =======================================================================================*/ best_rotation = zero_point; for ( current_rotation.z = -rotation_precision ; current_rotation.z < rotation_precision; current_rotation.z += rotation_precision / ITERATIONS_PER_LEVEL ) { for ( current_rotation.y = -rotation_precision; current_rotation.y < rotation_precision; current_rotation.y += rotation_precision / ITERATIONS_PER_LEVEL ) { for ( current_rotation.x = -rotation_precision; current_rotation.x < rotation_precision; current_rotation.x += rotation_precision / ITERATIONS_PER_LEVEL ) { /* first test whether offset increases the mutual information */ rotate(current_rotation, AMITK_SPACE(new_space)); current_mi = calculate_mutual_information( fixed_ds, moving_ds, new_space, step_size, &fixed_slices_current, fixed_slice, view_center, thickness, view_start_time, view_duration); /*if this location gives a better mutual information, then keep it */ if (current_mi > best_mi ) { #ifdef AMIDE_DEBUG g_print("better rotation fit at %4.4f\t%4.4f\t%4.4f\t with mi=\t%4.4f\n", current_rotation.x, current_rotation.y, current_rotation.z, current_mi); #endif best_mi = current_mi; best_rotation = current_rotation; } /* and unroll the transformation */ g_object_unref(new_space); new_space = amitk_space_copy(last_best_space); } } } /* apply/store the transform that worked best */ rotate(best_rotation, AMITK_SPACE(new_space)); g_object_unref(last_best_space); last_best_space = amitk_space_copy(new_space); /* update loop variables for next iteration */ translation_precision = translation_precision * 0.70; rotation_precision = rotation_precision * 0.70; if (step_size != MIN_STEP_SIZE) { step_size = step_size / 2.0; if (step_size < MIN_STEP_SIZE ) step_size = MIN_STEP_SIZE; fixed_slices_current = FALSE; } } if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); /* calculate the transform we'll need to apply */ transform_space = amitk_space_calculate_transform(AMITK_SPACE(moving_ds), new_space); /* garbage collection */ if (last_best_space != NULL) g_object_unref(last_best_space); if (new_space != NULL) g_object_unref(new_space); for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { if (fixed_slice[i_view] != NULL) amitk_object_unref(AMITK_OBJECT(fixed_slice[i_view])); } *pointer_mutual_information_error = best_mi; return transform_space; } amide-1.0.6/amide-current/src/alignment_mutual_information.h000066400000000000000000000031501423227705100242500ustar00rootroot00000000000000/* alignment_mutual_information.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2011-2012 Ian Miller * */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __ALIGNMENT_MUTUAL_INFORMATION_H__ #define __ALIGNMENT_MUTUAL_INFORMATION_H__ /* header files that are always needed with this file */ #include "amitk_data_set.h" /* external functions */ /* the space returned is the transform needed to change moving_ds's space to the aligned space, incoding an axes rotation, as well as the necessary shift with respect to the dataset's center */ AmitkSpace * alignment_mutual_information(AmitkDataSet * moving_ds, AmitkDataSet * fixed_ds, AmitkPoint view_center, amide_real_t thickness, amide_time_t view_start_time, amide_time_t view_duration, gdouble * pointer_mutual_information_error, AmitkUpdateFunc update_func, gpointer update_data); #endif /* __ALIGNMENT_MUTUAL_INFORMATION_H__ */ amide-1.0.6/amide-current/src/alignment_procrustes.c000066400000000000000000000306201423227705100225420ustar00rootroot00000000000000/* alignment.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBGSL_SUPPORT #include #include #include #include #include "alignment_procrustes.h" #include "amitk_fiducial_mark.h" /* convient functions that gsl doesn't supply */ static gsl_matrix * matrix_mult(gsl_matrix * matrix1, gsl_matrix * matrix2) { gsl_matrix * matrix_r = NULL; gint i,j,k; gdouble temp_value; g_return_val_if_fail(matrix1->size2 == matrix2->size1, NULL); matrix_r = gsl_matrix_alloc(matrix1->size1,matrix2->size2); for (i=0; isize1; i++) for (j=0; jsize2; j++) { temp_value = 0; for (k=0; ksize2; k++) temp_value += gsl_matrix_get(matrix1, i, k) * gsl_matrix_get(matrix2, k, j); gsl_matrix_set(matrix_r, i, j, temp_value); } return matrix_r; } static AmitkPoint matrix_mult_point(gsl_matrix * matrix, AmitkPoint rp) { AmitkPoint return_point; g_return_val_if_fail(matrix->size1 == AMITK_AXIS_NUM, rp); g_return_val_if_fail(matrix->size2 == AMITK_AXIS_NUM, rp); return_point.x = \ gsl_matrix_get(matrix, 0, 0)*rp.x + gsl_matrix_get(matrix, 0, 1)*rp.y + gsl_matrix_get(matrix, 0, 2)*rp.z; return_point.y = \ gsl_matrix_get(matrix, 1, 0)*rp.x + gsl_matrix_get(matrix, 1, 1)*rp.y + gsl_matrix_get(matrix, 1, 2)*rp.z; return_point.z = \ gsl_matrix_get(matrix, 2, 0)*rp.x + gsl_matrix_get(matrix, 2, 1)*rp.y + gsl_matrix_get(matrix, 2, 2)*rp.z; return return_point; } /* this is the procrustes rigid registration algorithm, derived from the review article: "Medical Image Registration", Hill, Batchelor, Holden, and Hawkes Phys. Med. Biol 46 (2001) R1-R45 */ AmitkSpace * alignment_procrustes(AmitkDataSet * moving_ds, AmitkDataSet * fixed_ds, GList * marks, gdouble *pointer_fiducial_reference_error) { AmitkSpace * transform_space=NULL; guint count = 0; GList * moving_fiducial_marks = NULL; GList * fixed_fiducial_marks = NULL; GList * moving_temp_list; GList * fixed_temp_list; AmitkObject * moving_fiducial_mark; AmitkObject * fixed_fiducial_mark; AmitkFiducialMark * fiducial_mark; AmitkPoint moving_centroid = zero_point; AmitkPoint fixed_centroid = zero_point; AmitkPoint temp_point; AmitkPoint shift; AmitkPoint offset_shift; AmitkAxes axis; AmitkPoint moving_center; AmitkPoint fixed_center; gsl_matrix * fixed_matrix=NULL; gsl_matrix * moving_matrixt=NULL; gsl_matrix * matrix_a; gsl_matrix * matrix_v; gsl_matrix * matrix_r=NULL; gsl_matrix * matrix_temp; gsl_matrix * matrix_diag; gsl_permutation * permutation; gsl_vector * vector_s; gsl_vector * vector_w; gint i; gint signum; gdouble det; gdouble fre; gint status; const char * mark_name; g_return_val_if_fail(AMITK_IS_DATA_SET(moving_ds), NULL); g_return_val_if_fail(AMITK_IS_DATA_SET(fixed_ds), NULL); g_return_val_if_fail(marks != NULL, NULL); /* get the two lists of points */ while (marks != NULL) { fiducial_mark = marks->data; if (AMITK_IS_FIDUCIAL_MARK(fiducial_mark) || AMITK_IS_VOLUME(fiducial_mark)) { mark_name = AMITK_OBJECT_NAME(fiducial_mark); moving_fiducial_mark = amitk_objects_find_object_by_name(AMITK_OBJECT_CHILDREN(moving_ds), mark_name); fixed_fiducial_mark = amitk_objects_find_object_by_name(AMITK_OBJECT_CHILDREN(fixed_ds), mark_name); if ((AMITK_IS_FIDUCIAL_MARK(moving_fiducial_mark) || AMITK_IS_VOLUME(moving_fiducial_mark)) && (AMITK_IS_FIDUCIAL_MARK(fixed_fiducial_mark) || AMITK_IS_VOLUME(moving_fiducial_mark))) { moving_fiducial_marks = g_list_append(moving_fiducial_marks, amitk_object_ref(moving_fiducial_mark)); if (AMITK_IS_FIDUCIAL_MARK(moving_fiducial_mark)) moving_center = AMITK_FIDUCIAL_MARK_GET(moving_fiducial_mark); else /* (AMITK_IS_VOLUME(moving_fiducial_mark) - maybe someday data sets will be fiducials */ moving_center = amitk_volume_get_center(AMITK_VOLUME(moving_fiducial_mark)); moving_centroid = point_add(moving_centroid, moving_center); fixed_fiducial_marks = g_list_append(fixed_fiducial_marks, amitk_object_ref(fixed_fiducial_mark)); if (AMITK_IS_FIDUCIAL_MARK(fixed_fiducial_mark)) fixed_center = AMITK_FIDUCIAL_MARK_GET(fixed_fiducial_mark); else /* (AMITK_IS_VOLUME(fixed_fiducial_mark) - maybe someday data sets will be fiducials */ fixed_center = amitk_volume_get_center(AMITK_VOLUME(fixed_fiducial_mark)); fixed_centroid = point_add(fixed_centroid, fixed_center); count++; } } marks = marks->next; } /* calculate the centroid of each point set */ moving_centroid = point_cmult((1.0/(gdouble) count), moving_centroid); fixed_centroid = point_cmult((1.0/(gdouble) count), fixed_centroid); /* sanity check */ if (count < 3) { g_warning(_("Cannot perform an alignment with %d points, need at least 3"),count); goto ending; } /* translate the points into data structures that GSL can handle */ /* also demean the alignment points so the centroid of each set is the origin */ /* the matrix are constructed such that each row is a point */ /* moving_matrixt is the transpose of the moving matrix */ moving_matrixt = gsl_matrix_alloc(AMITK_AXIS_NUM, count); fixed_matrix = gsl_matrix_alloc(count, AMITK_AXIS_NUM); moving_temp_list = moving_fiducial_marks; fixed_temp_list = fixed_fiducial_marks; for (i=0;idata; moving_temp_list = moving_temp_list->next; fixed_fiducial_mark = fixed_temp_list->data; fixed_temp_list = fixed_temp_list->next; if (AMITK_IS_FIDUCIAL_MARK(moving_fiducial_mark)) moving_center = AMITK_FIDUCIAL_MARK_GET(moving_fiducial_mark); else /* (AMITK_IS_VOLUME(moving_fiducial_mark) - maybe someday data sets will be fiducials */ moving_center = amitk_volume_get_center(AMITK_VOLUME(moving_fiducial_mark)); temp_point = point_sub(moving_center, moving_centroid); gsl_matrix_set(moving_matrixt, AMITK_AXIS_X, i, temp_point.x); gsl_matrix_set(moving_matrixt, AMITK_AXIS_Y, i, temp_point.y); gsl_matrix_set(moving_matrixt, AMITK_AXIS_Z, i, temp_point.z); if (AMITK_IS_FIDUCIAL_MARK(fixed_fiducial_mark)) fixed_center = AMITK_FIDUCIAL_MARK_GET(fixed_fiducial_mark); else /* (AMITK_IS_VOLUME(fixed_fiducial_mark) - maybe someday data sets will be fiducials */ fixed_center = amitk_volume_get_center(AMITK_VOLUME(fixed_fiducial_mark)); temp_point = point_sub(fixed_center,fixed_centroid); gsl_matrix_set(fixed_matrix, i, AMITK_AXIS_X, temp_point.x); gsl_matrix_set(fixed_matrix, i, AMITK_AXIS_Y, temp_point.y); gsl_matrix_set(fixed_matrix, i, AMITK_AXIS_Z, temp_point.z); } if ((fixed_temp_list != NULL) || (moving_temp_list != NULL)) { g_warning(_("points lists not completely used in %s at %d"), __FILE__, __LINE__); goto ending; } /* calculate the correlation matrix */ matrix_a = matrix_mult(moving_matrixt, fixed_matrix); /* get the singular value decomposition of the correlation matrix -> matrix_a = U*S*Vt notes: the function will place the value of U into matrix_a gsl_linalg_SV_decomp_jacobi will return an unsuitable matrix_v, don't use it */ matrix_v = gsl_matrix_alloc(AMITK_AXIS_NUM, AMITK_AXIS_NUM); vector_s = gsl_vector_alloc(AMITK_AXIS_NUM); vector_w = gsl_vector_alloc(AMITK_AXIS_NUM); status = gsl_linalg_SV_decomp(matrix_a, matrix_v, vector_s, vector_w); if (status != 0) g_warning(_("SV decomp returned error: %s"), gsl_strerror(status)); gsl_vector_free(vector_s); gsl_vector_free(vector_w); /* get U transpose */ status = gsl_matrix_transpose(matrix_a); if (status != 0) g_warning(_("transpose returned error: %s"), gsl_strerror(status)); /* figure out the determinant of V*Ut */ matrix_temp = matrix_mult(matrix_v, matrix_a); permutation = gsl_permutation_alloc(AMITK_AXIS_NUM); status = gsl_linalg_LU_decomp(matrix_temp, permutation, &signum); if (status != 0) g_warning(_("LU decomp returned error: %s"), gsl_strerror(status)); det = gsl_linalg_LU_det(matrix_temp, signum); g_return_val_if_fail(fabs(det) > 0.1, NULL); /* needs to be -1 or 1 */ gsl_permutation_free(permutation); gsl_matrix_free(matrix_temp); /* compute the rotation r = V * delta * Ut, where delta = diag(1,1,det(V,Ut))*/ matrix_diag = gsl_matrix_alloc(AMITK_AXIS_NUM, AMITK_AXIS_NUM); gsl_matrix_set_identity (matrix_diag); if (fabs(det) > 0.1) gsl_matrix_set(matrix_diag, AMITK_AXIS_NUM-1, AMITK_AXIS_NUM-1, det); matrix_temp = matrix_mult(matrix_diag, matrix_a); matrix_r = matrix_mult(matrix_v, matrix_temp); gsl_matrix_free(matrix_temp); gsl_matrix_free(matrix_diag); gsl_matrix_free(matrix_a); gsl_matrix_free(matrix_v); transform_space = amitk_space_new(); /* transfer over the rotation matrix */ for (i=0;idata; moving_temp_list = moving_temp_list->next; fixed_fiducial_mark = fixed_temp_list->data; fixed_temp_list = fixed_temp_list->next; if (AMITK_IS_FIDUCIAL_MARK(moving_fiducial_mark)) moving_center = AMITK_FIDUCIAL_MARK_GET(moving_fiducial_mark); else /* (AMITK_IS_VOLUME(moving_fiducial_mark) - maybe someday data sets will be fiducials */ moving_center = amitk_volume_get_center(AMITK_VOLUME(moving_fiducial_mark)); if (AMITK_IS_FIDUCIAL_MARK(fixed_fiducial_mark)) fixed_center = AMITK_FIDUCIAL_MARK_GET(fixed_fiducial_mark); else /* (AMITK_IS_VOLUME(fixed_fiducial_mark) - maybe someday data sets will be fiducials */ fixed_center = amitk_volume_get_center(AMITK_VOLUME(fixed_fiducial_mark)); moving_center = amitk_space_b2s(AMITK_SPACE(moving_ds), moving_center); moving_center = amitk_space_s2b(new_space,moving_center); fre += point_mag(point_sub(moving_center, fixed_center)); } fre = fre/((gdouble) count); *pointer_fiducial_reference_error = fre; if (new_space != NULL) g_object_unref(new_space); } ending: /* garbage collection */ if (matrix_r != NULL) gsl_matrix_free(matrix_r); if (moving_fiducial_marks != NULL) amitk_objects_unref(moving_fiducial_marks); if (fixed_fiducial_marks != NULL) amitk_objects_unref(fixed_fiducial_marks); if (fixed_matrix != NULL) gsl_matrix_free(fixed_matrix); if (moving_matrixt != NULL) gsl_matrix_free(moving_matrixt); return transform_space; } #endif /* AMIDE_LIBGSL_SUPPORT */ amide-1.0.6/amide-current/src/alignment_procrustes.h000066400000000000000000000027631423227705100225560ustar00rootroot00000000000000/* alignment.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBGSL_SUPPORT #ifndef __ALIGNMENT_PROCRUSTES_H__ #define __ALIGNMENT_PROCRUSTES_H__ /* header files that are always needed with this file */ #include "amitk_data_set.h" /* external functions */ /* the space returned is the transform needed to change moving_ds's space to the aligned space, incoding an axes rotation, as well as the necessary shift with respect to the dataset's center */ AmitkSpace * alignment_procrustes(AmitkDataSet * moving_ds, AmitkDataSet * fixed_ds, GList * marks, gdouble * pointer_fiducial_registration_error); #endif /* __ALIGNMENT_PROCRUSTE_H__ */ #endif /* AMIDE_LIBGSL_SUPPORT */ amide-1.0.6/amide-current/src/amide.c000066400000000000000000000252441423227705100173600ustar00rootroot00000000000000/* amide.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" //#include #include #include //#include //#include #include "amide.h" #include "amide_gconf.h" #include "amide_gnome.h" //#include "amitk_type_builtins.h" #include "amitk_common.h" #include "amitk_study.h" #include "pixmaps.h" #include "ui_study.h" #include "ui_common.h" /* external variables */ gchar * object_menu_names[] = { N_("_Study"), N_("Selected _Data Sets"), N_("Selected _ROIs"), N_("Selected _Alignment Points") }; void amide_log_handler_nopopup(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { AmitkPreferences * preferences = user_data; if (AMITK_PREFERENCES_WARNINGS_TO_CONSOLE(preferences)) g_print("AMIDE WARNING: %s\n", message); return; } void amide_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { AmitkPreferences * preferences = user_data; GtkWidget * dialog; GtkWidget * message_area; GtkWidget * scrolled; GtkWidget * label; if (AMITK_PREFERENCES_WARNINGS_TO_CONSOLE(preferences)) { if (log_level & G_LOG_LEVEL_MESSAGE) g_print("AMIDE MESSAGE: %s\n", message); else if (log_level & G_LOG_LEVEL_WARNING) /* G_LOG_LEVEL_WARNING */ g_print("AMIDE WARNING: %s\n", message); else if (log_level & G_LOG_LEVEL_INFO) /* G_LOG_LEVEL_WARNING */ g_print("AMIDE INFO: %s\n", message); else if (log_level & G_LOG_LEVEL_DEBUG) /* G_LOG_LEVEL_WARNING */ g_print("AMIDE DEBUG: %s\n", message); } else { dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, (log_level == G_LOG_LEVEL_MESSAGE) ? GTK_MESSAGE_INFO : GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "AMIDE %s", (log_level == G_LOG_LEVEL_MESSAGE) ? _("MESSAGE") : _("WARNING")); message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_widget_set_size_request(scrolled, -1, 75); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(message_area), scrolled, TRUE, TRUE, Y_PADDING); label = gtk_label_new(message); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), label); gtk_widget_show_all(message_area); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } return; } void missing_functionality_warning(AmitkPreferences * preferences) { gchar * comments; gchar * already_warned; #if (AMIDE_LIBGSL_SUPPORT && AMIDE_LIBMDC_SUPPORT && AMIDE_LIBDCMDATA_SUPPORT && AMIDE_LIBVOLPACK_SUPPORT && (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT)) return; /* nothing to complain about */ #endif already_warned = amide_gconf_get_string_with_default("MISSING_FUNCTIONALITY", "AlreadyWarned", "0.0.0"); if (g_strcmp0(already_warned, VERSION) == 0) return; else { comments = g_strconcat(_("This version of AMIDE has been compiled without the following functionality:"), "\n\n", #ifndef AMIDE_LIBGSL_SUPPORT _("Line profiles, factor analysis, some filtering, and some alignment (missing libgsl)."),")\n", #endif #ifndef AMIDE_LIBMDC_SUPPORT _("Reading of most medical imaging formats except raw and DICOM (missing libmdc)."),"\n", #endif #ifndef AMIDE_LIBDCMDATA_SUPPORT _("Reading of most DICOM files (missing libdcmdata/dcmtk)."),"\n", #endif #ifndef AMIDE_LIBVOLPACK_SUPPORT _("Volume rendering (missing libvolpack)."),")\n", #endif #if !(defined(AMIDE_FFMPEG_SUPPORT) || defined(AMIDE_LIBFAME_SUPPORT)) _("Saving MPEG output (missing ffmpeg and missing libfame)."),")\n", #endif NULL); g_warning("%s", comments); g_free(comments); amide_gconf_set_string("MISSING_FUNCTIONALITY", "AlreadyWarned", VERSION); return; } } static gchar **remaining_args = NULL; static GOptionEntry command_line_entries[] = { // { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &remaining_args, "Special option that collects any remaining arguments for us" }, { NULL } }; /********************************************* */ int main (int argc, char *argv []) { gint studies_launched=0; AmitkPreferences * preferences; struct stat file_info; AmitkStudy * imported_study = NULL; AmitkStudy * study = NULL; const gchar * input_filename; GList * new_data_sets; AmitkDataSet * new_ds; amide_real_t min_voxel_size; gint i; gint num_args; gchar * studyname=NULL; // GOptionContext *context; /* setup i18n */ // setlocale(LC_ALL, ""); // // setlocale(LC_NUMERIC, "POSIX"); /* don't switch radix sign (it's a period not a comma dammit */ // bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR); // textdomain(GETTEXT_PACKAGE); #if defined (G_PLATFORM_WIN32) /* if setlocale is called on win32, we can't seem to reset the locale back to "C" to allow correct reading in of text data */ gtk_disable_setlocale(); /* prevent gtk_init from calling setlocale, etc. */ #endif if (!gtk_init_with_args(&argc, &argv, _("[FILE1] [FILE2] ..."), command_line_entries, NULL, NULL)) { return 1; } // context = g_option_context_new ("- analyize medical images"); // g_option_context_add_main_entries (context, command_line_entries, GETTEXT_PACKAGE); // g_option_context_add_group (context, gtk_get_option_group (TRUE)); // g_option_context_parse (context, &argc, &argv, NULL); amide_gconf_init(); /* translations */ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); #ifdef AMIDE_DEBUG /* restore the normal segmentation fault signalling so we can get core dumps and don't get the gnome crash dialog */ signal(SIGSEGV, SIG_DFL); #endif /* load in the default preferences */ preferences = amitk_preferences_new(); /* specify my own error handler */ //g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, amide_log_handler, preferences); /* specify my message handler */ g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, amide_log_handler, preferences); /* specify the default directory */ ui_common_set_last_path_used(AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences)); #ifdef OLD_WIN32_HACKS /* ignore gdk warnings on win32 */ /* as of gtk 2.2.4, get "General case not implemented" warnings from gdkproperty-win32.c that appear to be unwarrented */ g_log_set_handler ("Gdk", G_LOG_LEVEL_WARNING, amide_log_handler_nopopup, preferences); /* have those annoying UTF-8 error warnings go to a console, instead of distracting the user */ g_log_set_handler ("Pango", G_LOG_LEVEL_WARNING, amide_log_handler_nopopup, preferences); #endif /* startup initializations */ amitk_common_font_init(); pixmaps_initialize_icons(); /* complain about important missing functionality if appropriate */ missing_functionality_warning(preferences); /* if we specified files on the command line, load them in */ if (remaining_args != NULL) { num_args = g_strv_length (remaining_args); for (i = 0; i < num_args; ++i) { /* input_filename is just pointers into the amide_ctx structure, and shouldn't be freed */ input_filename = remaining_args[i]; /* check to see that the filename exists and it's a directory */ if (stat(input_filename, &file_info) != 0) { g_warning(_("%s does not exist"),input_filename); } else if (amitk_is_xif_flat_file(input_filename, NULL, NULL) || amitk_is_xif_directory(input_filename, NULL, NULL)) { if ((study=amitk_study_load_xml(input_filename)) == NULL) g_warning(_("Failed to load in as XIF file: %s"), input_filename); } else if (!S_ISDIR(file_info.st_mode)) { /* not a directory... maybe an import file? */ if ((new_data_sets = amitk_data_set_import_file(AMITK_IMPORT_METHOD_GUESS, 0, input_filename, &studyname, preferences, NULL, NULL)) != NULL) { while (new_data_sets != NULL) { new_ds = new_data_sets->data; if (imported_study == NULL) { imported_study = amitk_study_new(preferences); if (studyname != NULL) { amitk_study_suggest_name(imported_study, studyname); g_free(studyname); studyname = NULL; } else if (AMITK_DATA_SET_SUBJECT_NAME(new_ds) != NULL) amitk_study_suggest_name(imported_study, AMITK_DATA_SET_SUBJECT_NAME(new_ds)); else amitk_study_suggest_name(imported_study, AMITK_OBJECT_NAME(new_ds)); } amitk_object_add_child(AMITK_OBJECT(imported_study), AMITK_OBJECT(new_ds)); min_voxel_size = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(imported_study)); amitk_study_set_view_thickness(imported_study, min_voxel_size); new_data_sets = g_list_remove(new_data_sets, new_ds); new_ds = amitk_object_unref(new_ds); } } else g_warning(_("%s is not an AMIDE study or importable file type"), input_filename); } else { g_warning(_("%s is not an AMIDE XIF Directory"), input_filename); } if (study != NULL) { /* each whole study gets it's own window */ ui_study_create(study, preferences); studies_launched++; study = amitk_object_unref(study); } } g_strfreev (remaining_args); remaining_args = NULL; } if (imported_study != NULL) { /* all imported data sets go into one study */ ui_study_create(imported_study, preferences); studies_launched++; imported_study = amitk_object_unref(imported_study); } /* start up an empty study if we haven't loaded in anything */ if (studies_launched < 1) ui_study_create(NULL, preferences); /* remove left over references */ g_object_unref(preferences); /* the main event loop */ gtk_main(); /* clean-up */ amide_gconf_shutdown(); return 0; } amide-1.0.6/amide-current/src/amide.h000066400000000000000000000025051423227705100173600ustar00rootroot00000000000000/* amide.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMIDE_H__ #define __AMIDE_H__ #include #include #include "amide_intl.h" G_BEGIN_DECLS /* some basic defines for packing tables */ #define X_PACKING_OPTIONS GTK_EXPAND #define Y_PACKING_OPTIONS GTK_EXPAND #define X_PADDING 5 #define Y_PADDING 5 typedef enum { AMIDE_EYE_LEFT, AMIDE_EYE_RIGHT, AMIDE_EYE_NUM } AmideEye; /* external variables */ extern gchar * object_menu_names[]; G_END_DECLS #endif /* __AMIDE_H__ */ amide-1.0.6/amide-current/src/amide_gconf.c000066400000000000000000000463341423227705100205370ustar00rootroot00000000000000/* amide_gconf.c * * Part of amide - Amide's a Medical Image Dataset Examiner * * Copyright (C) 2007-2017 Andy Loening except as follows * win32 registery code is derived directly from gnumeric * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_gconf.h" #if defined (G_PLATFORM_WIN32) /* --------------------------- win32 version --------------------------- */ /* Note, this stuff has been adapted from gnumeric, specifically the file gnm-conf-win32.c */ #include #include #ifndef ERANGE /* mingw has not defined ERANGE (yet), MSVC has it though */ # define ERANGE 34 #endif typedef struct _GOConfNode GOConfNode; struct _GOConfNode { HKEY hKey; gchar *path; }; static GOConfNode *root = NULL; static void go_conf_win32_clone (HKEY hSrcKey, gchar *key, HKEY hDstKey, gchar *buf1, gchar *buf2, gchar *buf3) { #define WIN32_MAX_REG_KEYNAME_LEN 256 #define WIN32_MAX_REG_VALUENAME_LEN 32767 #define WIN32_INIT_VALUE_DATA_LEN 2048 gint i; gchar *subkey, *value_name, *data; DWORD name_size, type, data_size; HKEY hSrcSK, hDstSK; FILETIME ft; LONG ret; if (RegOpenKeyEx (hSrcKey, key, 0, KEY_READ, &hSrcSK) != ERROR_SUCCESS) return; if (!buf1) { subkey = g_malloc (WIN32_MAX_REG_KEYNAME_LEN); value_name = g_malloc (WIN32_MAX_REG_VALUENAME_LEN); data = g_malloc (WIN32_INIT_VALUE_DATA_LEN); } else { subkey = buf1; value_name = buf2; data = buf3; } ret = ERROR_SUCCESS; for (i = 0; ret == ERROR_SUCCESS; ++i) { name_size = WIN32_MAX_REG_KEYNAME_LEN; ret = RegEnumKeyEx (hSrcSK, i, subkey, &name_size, NULL, NULL, NULL, &ft); if (ret != ERROR_SUCCESS) continue; if (RegCreateKeyEx (hDstKey, subkey, 0, NULL, 0, KEY_WRITE, NULL, &hDstSK, NULL) == ERROR_SUCCESS) { go_conf_win32_clone (hSrcSK, subkey, hDstSK, subkey, value_name, data); RegCloseKey (hDstSK); } } ret = ERROR_SUCCESS; for (i = 0; ret == ERROR_SUCCESS; ++i) { name_size = WIN32_MAX_REG_KEYNAME_LEN; data_size = WIN32_MAX_REG_VALUENAME_LEN; while ((ret = RegEnumValue (hSrcSK, i, value_name, &name_size, NULL, &type, data, &data_size)) == ERROR_MORE_DATA) data = g_realloc (data, data_size); if (ret != ERROR_SUCCESS) continue; RegSetValueEx (hDstKey, value_name, 0, type, data, data_size); } RegCloseKey (hSrcSK); if (!buf1) { g_free (subkey); g_free (value_name); g_free (data); } } static gboolean go_conf_win32_get_node (GOConfNode *node, HKEY *phKey, const gchar *key, gboolean *is_new) { gchar *path, *c; LONG ret; DWORD disposition; path = g_strconcat (node ? "" : "Software\\", key, NULL); for (c = path; *c; ++c) { if (*c == '/') *c = '\\'; } ret = RegCreateKeyEx (node ? node->hKey : HKEY_CURRENT_USER, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, phKey, &disposition); g_free (path); if (is_new) *is_new = disposition == REG_CREATED_NEW_KEY; #ifdef AMIDE_DEBUG if (ret != ERROR_SUCCESS) { LPTSTR msg_buf; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ret, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg_buf, 0, NULL); g_warning("Unable to save key '%s' : because %s", key, msg_buf); } #endif return ret == ERROR_SUCCESS; } GOConfNode * go_conf_get_node (GOConfNode *parent, const gchar *key) { HKEY hKey; GOConfNode *node = NULL; gboolean is_new; if (go_conf_win32_get_node (parent, &hKey, key, &is_new)) { if (!parent && is_new) { gchar *path; path = g_strconcat (".DEFAULT\\Software\\", key, NULL); go_conf_win32_clone (HKEY_USERS, path, hKey, NULL, NULL, NULL); g_free (path); } node = g_malloc (sizeof (GOConfNode)); node->hKey = hKey; node->path = g_strdup (key); } return node; } static gboolean go_conf_win32_set (GOConfNode *node, const gchar *key, gint type, guchar *data, gint size) { gchar *last_sep, *path = NULL; HKEY hKey; gboolean ok; gboolean newpath=FALSE; if ((last_sep = strrchr (key, '/')) != NULL) { path = g_strndup (key, last_sep - key); ok = go_conf_win32_get_node (node, &hKey, path, NULL); g_free (path); newpath=TRUE; if (!ok) { return FALSE; } key = last_sep + 1; } else hKey = node->hKey; ok = RegSetValueEx (hKey, key, 0, type, data, size); if (ok != ERROR_SUCCESS) { #ifdef AMIDE_DEBUG LPTSTR msg_buf; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ok, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg_buf, 0, NULL); g_warning("Unable to save key '%s' : because %s", key, msg_buf); #endif return FALSE; } if (newpath) RegCloseKey (hKey); return TRUE; } static gboolean go_conf_win32_get (GOConfNode *node, const gchar *key, gulong *type, guchar **data, gulong *size, gboolean realloc, gint *ret_code) { gchar *last_sep, *path = NULL; HKEY hKey; LONG ret; gboolean ok; if ((last_sep = strrchr (key, '/')) != NULL) { path = g_strndup (key, last_sep - key); ok = go_conf_win32_get_node (node, &hKey, path, NULL); g_free (path); if (!ok) { return FALSE; } key = last_sep + 1; } else hKey = node->hKey; if (!*data && realloc) { RegQueryValueEx (hKey, key, NULL, type, NULL, size); *data = g_new (guchar, *size); } while ((ret = RegQueryValueEx (hKey, key, NULL, type, *data, size)) == ERROR_MORE_DATA && realloc) *data = g_realloc (*data, *size); if (path) RegCloseKey (hKey); if (ret_code) *ret_code = ret; return ret == ERROR_SUCCESS; } static guchar * go_conf_get (GOConfNode *node, const gchar *key, gulong expected) { gulong type, size = 0; guchar *ptr = NULL; gint ret_code; if (!go_conf_win32_get (node, key, &type, &ptr, &size, TRUE, &ret_code)) { #ifdef AMIDE_DEBUG LPTSTR msg_buf; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ret_code, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg_buf, 0, NULL); g_warning("Unable to load key '%s' : because %s", key, msg_buf); LocalFree (msg_buf); #endif g_free (ptr); return NULL; } if (type != expected) { #ifdef AMIDE_DEBUG g_warning("Expected `%lu' got `%lu' for key %s of node %s", expected, type, key, node->path); #endif g_free (ptr); return NULL; } return ptr; } void amide_gconf_init(void) { root = go_conf_get_node (NULL, PACKAGE); return; } void amide_gconf_shutdown(void) { if (root) { RegCloseKey (root->hKey); g_free (root->path); g_free (root); } return; } gboolean amide_gconf_get_bool_with_default(const gchar * group, const gchar *key, gboolean default_val) { guchar * val; gboolean res; gchar * real_key; real_key = g_strdup_printf("%s/%s",group,key); val = go_conf_get (root, real_key, REG_BINARY); g_free(real_key); if (val) { res = (gboolean) *val; g_free (val); return res; } else { return default_val; } } gboolean amide_gconf_get_bool(const gchar * group, const gchar * key) { return amide_gconf_get_bool_with_default(group, key,FALSE); } gint amide_gconf_get_int_with_default(const gchar * group, const gchar *key, gint default_val) { guchar * val; gint res; gchar * real_key; real_key = g_strdup_printf("%s/%s",group,key); val = go_conf_get (root, real_key, REG_DWORD); g_free(real_key); if (val) { res = *(gint *) val; g_free (val); return res; } else { return default_val; } } gint amide_gconf_get_int(const gchar * group, const gchar * key) { return amide_gconf_get_int_with_default(group, key,0); } gdouble amide_gconf_get_float_with_default(const gchar * group, const gchar *key, gdouble default_val) { gdouble res = -1; gchar *val; gboolean valid=FALSE; gchar * real_key; real_key = g_strdup_printf("%s/%s",group,key); val = (gchar *) go_conf_get (root, real_key, REG_SZ); g_free(real_key); if (val) { res = g_ascii_strtod (val, NULL); if (errno != ERANGE) valid = TRUE; g_free(val); } if (!valid) return default_val; else return res; } gdouble amide_gconf_get_float(const gchar * group, const gchar * key) { return amide_gconf_get_float_with_default(group, key, 0.0); } /* returns an allocated string that'll need to be free'd */ gchar * amide_gconf_get_string_with_default(const gchar * group, const gchar * key, const gchar * default_str) { gchar * val; gchar * real_key; real_key = g_strdup_printf("%s/%s",group,key); val = (gchar *) go_conf_get(root, real_key, REG_SZ); g_free(real_key); if (val) return val; else return g_strdup(default_str); } /* returns an allocated string that'll need to be free'd */ gchar * amide_gconf_get_string (const gchar * group, const gchar *key) { return amide_gconf_get_string_with_default(group, key,NULL); } gboolean amide_gconf_set_int(const gchar * group, const gchar *key, gint val) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("%s/%s",group,key); return_val = go_conf_win32_set (root, real_key, REG_DWORD, (guchar *) &val, sizeof (DWORD)); g_free(real_key); return return_val; } gboolean amide_gconf_set_float(const gchar * group, const char *key, gdouble val) { gchar * real_key; gboolean return_val; gchar str[G_ASCII_DTOSTR_BUF_SIZE]; g_ascii_dtostr (str, sizeof (str), val); real_key = g_strdup_printf("%s/%s",group,key); return_val = go_conf_win32_set(root, real_key, REG_SZ, (guchar *) str, strlen (str) + 1); g_free(real_key); return return_val; } gboolean amide_gconf_set_bool(const gchar * group, const gchar *key, gboolean val) { gchar * real_key; gboolean return_val; guchar bool = val ? 1 : 0; real_key = g_strdup_printf("%s/%s",group,key); return_val = go_conf_win32_set (root, real_key, REG_BINARY, (guchar *) &bool, sizeof (bool)); g_free(real_key); return return_val; } gboolean amide_gconf_set_string (const gchar * group, const char *key, const gchar *str) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("%s/%s",group,key); return_val = go_conf_win32_set(root, real_key, REG_SZ, (guchar *) str, strlen (str) + 1); g_free(real_key); return return_val; } #elif defined(AMIDE_NATIVE_GTK_OSX) || !defined(AMIDE_USE_GCONF) /* --------------------- flatfile version ----------------- */ #include #include static GKeyFile *key_file = NULL; static gchar * rcfilename = NULL; void amide_gconf_init(void) { const gchar *home; home = g_get_home_dir(); g_return_if_fail(home != NULL); rcfilename = g_build_filename (home, ".amiderc", NULL); g_return_if_fail(rcfilename != NULL); /* generate the key file, and load it in if a prior .ammiderc file exists */ key_file = g_key_file_new(); g_key_file_load_from_file(key_file, rcfilename, G_KEY_FILE_NONE, NULL); return; } void amide_gconf_shutdown(void) { FILE *fp = NULL; gchar *key_data; g_return_if_fail(rcfilename != NULL); g_return_if_fail(key_file != NULL); fp = g_fopen (rcfilename, "w"); if (fp == NULL) { g_warning ("Couldn't write configuration info to %s", rcfilename); return; } key_data = g_key_file_to_data (key_file, NULL, NULL); if (key_data != NULL) { fputs (key_data, fp); g_free (key_data); } fclose (fp); return; } gboolean amide_gconf_get_bool_with_default(const gchar * group, const gchar *key, gboolean default_val) { gboolean val; GError *error=NULL; g_return_val_if_fail(key_file != NULL, default_val); val = g_key_file_get_boolean (key_file, group, key, &error); if (error != NULL) { g_error_free(error); return default_val; } else return val; } gboolean amide_gconf_get_bool(const gchar * group, const gchar * key) { return amide_gconf_get_bool_with_default(group,key,FALSE); } gint amide_gconf_get_int_with_default(const gchar * group, const gchar *key, gint default_val) { gint val; GError *error=NULL; g_return_val_if_fail(key_file != NULL, default_val); val = g_key_file_get_integer(key_file, group, key, &error); if (error != NULL) { g_error_free(error); return default_val; } else return val; } gint amide_gconf_get_int(const gchar * group, const gchar * key) { return amide_gconf_get_int_with_default(group, key,0); } gdouble amide_gconf_get_float_with_default(const gchar * group, const gchar *key,gdouble default_val) { gchar *ptr; gdouble val; GError *error=NULL; gboolean valid = FALSE; g_return_val_if_fail(key_file != NULL, default_val); ptr = g_key_file_get_value (key_file, group, key, &error); if ((ptr != NULL) && (error == NULL)) { val = g_ascii_strtod (ptr, NULL); if (errno != ERANGE) valid = TRUE; } if (ptr != NULL) g_free (ptr); if (!valid) val = default_val; return val; } gdouble amide_gconf_get_float(const gchar * group, const gchar * key) { return amide_gconf_get_float_with_default(group, key, 0.0); } /* returns an allocated string that'll need to be free'd */ gchar * amide_gconf_get_string_with_default(const gchar * group, const gchar * key, const gchar * default_val) { gchar *val; GError *error=NULL; g_return_val_if_fail(key_file != NULL, NULL); val = g_key_file_get_string(key_file, group, key, &error); if(error == NULL) return val; else return g_strdup(default_val); } /* returns an allocated string that'll need to be free'd */ gchar * amide_gconf_get_string (const gchar * group, const gchar *key) { return amide_gconf_get_string_with_default(group, key,NULL); } gboolean amide_gconf_set_bool(const gchar * group, const gchar *key, gboolean val) { g_return_val_if_fail(key_file != NULL, FALSE); g_key_file_set_boolean(key_file, group, key, val); return TRUE; } gboolean amide_gconf_set_int(const gchar * group, const gchar *key, gint val) { g_return_val_if_fail(key_file != NULL, FALSE); g_key_file_set_integer(key_file, group, key, val); return TRUE; } gboolean amide_gconf_set_float(const gchar * group, const char *key, gdouble val) { g_return_val_if_fail(key_file != NULL, FALSE); g_key_file_set_double(key_file, group, key, val); return TRUE; } gboolean amide_gconf_set_string (const gchar * group, const char *key, const gchar *val) { g_return_val_if_fail(key_file != NULL, FALSE); g_key_file_set_string (key_file, group, key, val); return TRUE; } #else /* ------------------- gconf version ---------------------- */ #include #include /* internal variables */ static GConfClient * client=NULL; void amide_gconf_init(void) { client = gconf_client_get_default(); return; } void amide_gconf_shutdown(void) { g_object_unref(client); return; } gint amide_gconf_get_int(const gchar * group, const gchar * key) { gchar * real_key; gint return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_get_int(client,real_key,NULL); g_free(real_key); return return_val; } gdouble amide_gconf_get_float(const gchar * group, const gchar * key) { gchar * real_key; gdouble return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_get_float(client,real_key,NULL); g_free(real_key); return return_val; } gboolean amide_gconf_get_bool(const gchar * group, const gchar * key) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_get_bool(client,real_key,NULL); g_free(real_key); return return_val; } gchar * amide_gconf_get_string(const gchar * group, const gchar * key) { gchar * real_key; gchar * return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_get_string(client,real_key,NULL); g_free(real_key); return return_val; } gboolean amide_gconf_set_int(const gchar * group, const gchar * key, gint val) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_set_int(client,real_key,val,NULL); g_free(real_key); return return_val; } gboolean amide_gconf_set_float(const gchar * group, const gchar * key, gdouble val) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_set_float(client,real_key,val,NULL); g_free(real_key); return return_val; } gboolean amide_gconf_set_bool(const gchar * group, const gchar * key, gboolean val) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); return_val = gconf_client_set_bool(client,real_key,val,NULL); g_free(real_key); return return_val; } gboolean amide_gconf_set_string(const gchar * group, const gchar * key, const gchar * val) { gchar * real_key; gboolean return_val; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group, key); return_val = gconf_client_set_string(client,real_key,val,NULL); g_free(real_key); return return_val; } /* it's pretty retarded that gconf doesn't have a function that can do this more easily */ static gboolean amide_gconf_has_value(const gchar * group, const gchar *key) { GConfValue * temp_val; gchar * real_key; real_key = g_strdup_printf("/apps/%s/%s/%s",PACKAGE,group,key); temp_val = gconf_client_get(client, real_key, NULL); g_free(real_key); if (temp_val == NULL) return FALSE; gconf_value_free(temp_val); return TRUE; } /* some helper functions */ gint amide_gconf_get_int_with_default(const gchar * group, const gchar * key, const gint default_int) { if (amide_gconf_has_value(group, key)) return amide_gconf_get_int(group, key); else return default_int; } gdouble amide_gconf_get_float_with_default(const gchar * group, const gchar * key, const gdouble default_float) { if (amide_gconf_has_value(group, key)) return amide_gconf_get_float(group, key); else return default_float; } gboolean amide_gconf_get_bool_with_default(const gchar * group, const gchar * key, const gboolean default_bool) { if (amide_gconf_has_value(group, key)) return amide_gconf_get_bool(group, key); else return default_bool; } /* returns an allocated string that'll need to be free'd */ gchar * amide_gconf_get_string_with_default(const gchar * group, const gchar * key, const gchar * default_str) { if (amide_gconf_has_value(group, key)) return amide_gconf_get_string(group, key); else return g_strdup(default_str); } #endif amide-1.0.6/amide-current/src/amide_gconf.h000066400000000000000000000042471423227705100205410ustar00rootroot00000000000000/* amide_gconf.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2007-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMIDE_GCONF_H__ #define __AMIDE_GCONF_H__ /* header files that are always needed with this file */ #include #include "amide_config.h" G_BEGIN_DECLS void amide_gconf_init(); void amide_gconf_shutdown(); gint amide_gconf_get_int (const char * group, const char * key); gdouble amide_gconf_get_float (const char * group, const char * key); gboolean amide_gconf_get_bool (const char * group, const char * key); gchar * amide_gconf_get_string(const char * group, const char * key); gboolean amide_gconf_set_int (const char * group, const char * key, gint val); gboolean amide_gconf_set_float (const char * group, const char * key, gdouble val); gboolean amide_gconf_set_bool (const char * group, const char * key, gboolean val); gboolean amide_gconf_set_string(const char * group, const char * key, const gchar * val); gint amide_gconf_get_int_with_default (const char * group, const gchar * key, const gint default_int); gdouble amide_gconf_get_float_with_default (const char * group, const gchar * key, const gdouble default_float); gboolean amide_gconf_get_bool_with_default (const char * group, const gchar * key, const gboolean default_bool); gchar * amide_gconf_get_string_with_default(const char * group, const gchar * key, const gchar * default_str); G_END_DECLS #endif /* __AMIDE_GCONF_H__ */ amide-1.0.6/amide-current/src/amide_gnome.c000066400000000000000000000251251423227705100205430ustar00rootroot00000000000000/* amide_gnome.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2007-2017 Andy Loening * * Author: Andy Loening * Code directly copied from libgnome */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* this file contains gnome functions that I still need but will hopefully have replacements at some point in the future */ #include #include #include #include "amitk_common.h" #include "amide_gnome.h" #if !defined(G_OS_WIN32) && !defined(AMIDE_NATIVE_GTK_OSX) && defined(AMIDE_USE_GNOME_VFS) #include #include //#else //#include #endif typedef enum { AMIDE_GNOME_URL_ERROR_PARSE, AMIDE_GNOME_URL_ERROR_LAUNCH, AMIDE_GNOME_URL_ERROR_URL, AMIDE_GNOME_URL_ERROR_NO_DEFAULT, AMIDE_GNOME_URL_ERROR_NOT_SUPPORTED, AMIDE_GNOME_URL_ERROR_VFS, AMIDE_GNOME_URL_ERROR_CANCELLED } AmideGnomeURLError; #define AMIDE_GNOME_URL_ERROR (amide_gnome_url_error_quark ()) GQuark amide_gnome_url_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) error_quark = g_quark_from_static_string ("amide-gnome-url-error-quark"); return error_quark; } static gboolean amide_gnome_url_show_with_env (const char *url, char **envp, GError **error) { #if !defined(G_OS_WIN32) && !defined(AMIDE_NATIVE_GTK_OSX) && defined(AMIDE_USE_GNOME_VFS) GnomeVFSResult result; GnomeVFSURI *vfs_uri; g_return_val_if_fail (url != NULL, FALSE); result = gnome_vfs_url_show_with_env (url, envp); switch (result) { case GNOME_VFS_OK: return TRUE; case GNOME_VFS_ERROR_INTERNAL: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_VFS, _("Unknown internal error while displaying this location.")); break; case GNOME_VFS_ERROR_BAD_PARAMETERS: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_URL, _("The specified location is invalid.")); break; case GNOME_VFS_ERROR_PARSE: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_PARSE, _("There was an error parsing the default action command associated " "with this location.")); break; case GNOME_VFS_ERROR_LAUNCH: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_LAUNCH, _("There was an error launching the default action command associated " "with this location.")); break; case GNOME_VFS_ERROR_NO_DEFAULT: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_NO_DEFAULT, _("There is no default action associated with this location.")); break; case GNOME_VFS_ERROR_NOT_SUPPORTED: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_NOT_SUPPORTED, _("The default action does not support this protocol.")); break; case GNOME_VFS_ERROR_CANCELLED: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_CANCELLED, _("The request was cancelled.")); break; case GNOME_VFS_ERROR_HOST_NOT_FOUND: { vfs_uri = gnome_vfs_uri_new (url); if (gnome_vfs_uri_get_host_name (vfs_uri) != NULL) { g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_VFS, _("The host \"%s\" could not be found."), gnome_vfs_uri_get_host_name (vfs_uri)); } else { g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_VFS, _("The host could not be found.")); } gnome_vfs_uri_unref (vfs_uri); } break; case GNOME_VFS_ERROR_INVALID_URI: case GNOME_VFS_ERROR_NOT_FOUND: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_VFS, _("The location or file could not be found.")); break; case GNOME_VFS_ERROR_LOGIN_FAILED: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_VFS, _("The login has failed.")); break; default: g_set_error (error, AMIDE_GNOME_URL_ERROR, AMIDE_GNOME_URL_ERROR_VFS, "%s", gnome_vfs_result_to_string (result)); } return FALSE; #else char *argv[] = { NULL, NULL, NULL }; /* TODO : handle translations when we generate them */ argv[0] = (char *)"hh"; argv[1] = url; g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, error); return TRUE; #endif } static gboolean amide_gnome_help_display_uri_with_env (const char *help_uri, char **envp, GError **error) { GError *real_error; gboolean retval; real_error = NULL; retval = amide_gnome_url_show_with_env (help_uri, envp, &real_error); if (real_error != NULL) g_propagate_error (error, real_error); return retval; } static char * locate_help_file (const char *path, const char *doc_name) { int i, j; char *exts[] = { "", ".xml", ".docbook", ".sgml", ".html", NULL }; const char * const * lang_list = g_get_language_names (); for (j = 0;lang_list[j] != NULL; j++) { const char *lang = lang_list[j]; /* This has to be a valid language AND a language with * no encoding postfix. The language will come up without * encoding next */ if (lang == NULL || strchr (lang, '.') != NULL) continue; for (i = 0; exts[i] != NULL; i++) { char *name; char *full; name = g_strconcat (doc_name, exts[i], NULL); full = g_build_filename (path, lang, name, NULL); g_free (name); if (g_file_test (full, G_FILE_TEST_EXISTS)) return full; g_free (full); } } return NULL; } /* returns an array of strings (strings can be potentially null) - array and strings need to be free'd */ static gchar ** amide_gnome_program_locate_help_file (const gchar *file_name, gboolean only_if_exists) { gchar *buf; gchar ** retvals; gchar ** dirs; const gchar * const * global_dirs; gint i; gint j; gint count=0; gint slots; g_return_val_if_fail (file_name != NULL, NULL); global_dirs = g_get_system_data_dirs(); while (global_dirs[count] != NULL) count++; /* count */ /* allocate the array of strings - extra spot for AMIDE_DATADIR, plus an extra spot if on win32, plus one at end for NULL termination */ #if defined (G_PLATFORM_WIN32) slots = count+3; #else slots = count+2; #endif dirs = g_try_new0(gchar *,slots); retvals = g_try_new0(gchar *,slots); g_return_val_if_fail((dirs != NULL) && (retvals != NULL), NULL); j=0; /* copy over the directories */ dirs[j] = g_strdup(AMIDE_DATADIR); /* first entry */ j++; /* FIXME, below function is now deprecated #if defined (G_PLATFORM_WIN32) dirs[j] = g_win32_get_package_installation_subdirectory(NULL, NULL,"share"); j++; #endif */ i=0; while (global_dirs[i] != NULL) { /* rest of the entries */ dirs[j] = g_strdup(global_dirs[i]); i++; j++; } /* Potentially add an absolute path */ if (g_path_is_absolute (file_name)) if (!only_if_exists || g_file_test (file_name, G_FILE_TEST_EXISTS)) { retvals[0] = g_strdup(file_name); return retvals; /* we're already done */ } /* use the prefix */ if (AMIDE_DATADIR == NULL) { g_warning (G_STRLOC ": Directory properties not set correctly. " "Cannot locate application specific files."); return retvals; } i=0; j=0; while (dirs[i] != NULL) { buf = g_strdup_printf ("%s%s%s%s%s%s%s", dirs[i], G_DIR_SEPARATOR_S,"gnome",G_DIR_SEPARATOR_S, "help", G_DIR_SEPARATOR_S,file_name); if (!only_if_exists || g_file_test (buf, G_FILE_TEST_EXISTS)) { retvals[j] = buf; j++; } else g_free(buf); i++; } i=0; while (dirs[i] != NULL) { g_free(dirs[i]); i++; } g_free(dirs); return retvals; } typedef enum { AMIDE_GNOME_HELP_ERROR_INTERNAL, AMIDE_GNOME_HELP_ERROR_NOT_FOUND } AmideGnomeHelpError; #define AMIDE_GNOME_HELP_ERROR (amide_gnome_help_error_quark ()) GQuark amide_gnome_help_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) error_quark = g_quark_from_static_string ("amide-gnome-help-error-quark"); return error_quark; } gboolean amide_gnome_help_display (const char *file_name, const char *link_id, GError **error) { gchar ** help_paths; gchar *file=NULL; struct stat help_st; gchar *uri=NULL; gboolean retval; const char *doc_id = PACKAGE; gint i; gchar * temp_str=NULL; g_return_val_if_fail (file_name != NULL, FALSE); retval = FALSE; help_paths = amide_gnome_program_locate_help_file (doc_id,FALSE); if (help_paths == NULL) { g_set_error (error, AMIDE_GNOME_HELP_ERROR, AMIDE_GNOME_HELP_ERROR_INTERNAL, _("Unable to find the app or global HELP domain")); goto out; } /* Try to access the help paths, first the app-specific help path * and then falling back to the global help path if the first one fails. */ i=0; while ((help_paths[i] != NULL) && (file == NULL)) { if (g_stat (help_paths[i], &help_st) == 0) { if (!S_ISDIR (help_st.st_mode)) goto error; file = locate_help_file (help_paths[i], file_name); } i++; } if (file == NULL) goto error; /* Now that we have a file name, try to display it in the help browser */ if (link_id) uri = g_strconcat ("ghelp://", file, "?", link_id, NULL); else uri = g_strconcat ("ghelp://", file, NULL); retval = amide_gnome_help_display_uri_with_env (uri, NULL, error); goto out; error: i=0; while (help_paths[i] != NULL) { amitk_append_str(&temp_str, "%s;", help_paths[i]); i++; } g_set_error (error, AMIDE_GNOME_HELP_ERROR, AMIDE_GNOME_HELP_ERROR_NOT_FOUND, _("Unable to find the help files in any of the following directories, " " or these are not valid directories: %s " ": Please check your installation"), temp_str); g_free(temp_str); out: if (help_paths != NULL) { i=0; while (help_paths[i] != NULL) { g_free(help_paths[i]); i++; } g_free(help_paths); } if (file != NULL) g_free (file); if (uri != NULL) g_free (uri); return retval; } amide-1.0.6/amide-current/src/amide_gnome.h000066400000000000000000000021261423227705100205440ustar00rootroot00000000000000/* amide_gnome.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2007-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMIDE_GNOME_H__ #define __AMIDE_GNOME_H__ #include G_BEGIN_DECLS gboolean amide_gnome_help_display (const char *file_name, const char *link_id, GError **error); G_END_DECLS #endif /* __AMIDE_GNOME_H__ */ amide-1.0.6/amide-current/src/amide_intl.h000066400000000000000000000012631423227705100204060ustar00rootroot00000000000000#ifndef __AMIDE_INTL_H__ #define __AMIDE_INTL_H__ #include "amide_config.h" #ifdef ENABLE_NLS #include #undef _ #define _(String) dgettext(GETTEXT_PACKAGE,String) #ifdef gettext_noop #define N_(String) gettext_noop(String) #else #define N_(String) (String) #endif #else /* NLS is disabled */ #undef _ #define _(String) (String) #undef N_ #define N_(String) (String) #undef textdomain #define textdomain(String) (String) #undef gettext #define gettext(String) (String) #undef dgettext #define dgettext(Domain,String) (String) #undef dcgettext #define dcgettext(Domain,String,Type) (String) #undef bindtextdomain #define bindtextdomain(Domain,Directory) (Domain) #endif #endif amide-1.0.6/amide-current/src/amitk_canvas.c000066400000000000000000004261331423227705100207430ustar00rootroot00000000000000/* amitk_canvas.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_study.h" #include "amide.h" #include "amitk_canvas.h" #include "amitk_canvas_object.h" #include "image.h" #include "ui_common.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #define BOX_SPACING 3 #define DEFAULT_CANVAS_TRIANGLE_WIDTH 8.0 #define DEFAULT_CANVAS_TRIANGLE_HEIGHT 8.0 #define DEFAULT_CANVAS_BORDER_WIDTH 12.0 #define DEFAULT_CANVAS_TRIANGLE_SEPARATION 2.0 /* distance between triangle and canvas */ #define DEFAULT_CANVAS_TRIANGLE_BORDER 2.0 /* should be DEFAULT_CANVAS_BORDER_WIDTH-DEFAULT_CANVAS_TRIANGLE_HEIGHT-DEFAULT_CANVAS_TRIANGLE_SEPARATION */ #define UPDATE_NONE 0x00 #define UPDATE_VIEW 0x01 #define UPDATE_ARROWS 0x02 #define UPDATE_LINE_PROFILE 0x04 #define UPDATE_DATA_SETS 0x08 #define UPDATE_SCROLLBAR 0x10 #define UPDATE_OBJECT 0x20 #define UPDATE_OBJECTS 0x40 #define UPDATE_TARGET 0x80 #define UPDATE_TIME 0x100 #define UPDATE_SUBJECT_ORIENTATION 0x200 #define UPDATE_ALL 0x2FF #define cp_2_p(canvas, canvas_cpoint) (canvas_point_2_point(AMITK_VOLUME_CORNER((canvas)->volume),\ (canvas)->pixbuf_width, \ (canvas)->pixbuf_height,\ (canvas)->border_width, \ (canvas)->border_width, \ (canvas_cpoint))) #define p_2_cp(canvas, canvas_cpoint) (point_2_canvas_point(AMITK_VOLUME_CORNER((canvas)->volume),\ (canvas)->pixbuf_width, \ (canvas)->pixbuf_height,\ (canvas)->border_width, \ (canvas)->border_width, \ (canvas_cpoint))) gchar * orientation_label[6] = { N_("A"), N_("P"), N_("L"), N_("R"), N_("S"), N_("I") }; enum { ANTERIOR, POSTERIOR, LEFT, RIGHT, SUPERIOR, INFERIOR }; enum { HELP_EVENT, VIEW_CHANGING, VIEW_CHANGED, ERASE_VOLUME, NEW_OBJECT, LAST_SIGNAL } amitk_canvas_signals; typedef enum { CANVAS_EVENT_NONE, CANVAS_EVENT_ENTER_OBJECT, CANVAS_EVENT_LEAVE, CANVAS_EVENT_PRESS_MOVE_VIEW, CANVAS_EVENT_PRESS_MINIMIZE_VIEW, CANVAS_EVENT_PRESS_RESIZE_VIEW, CANVAS_EVENT_PRESS_SHIFT_OBJECT, /* currently data set only */ CANVAS_EVENT_PRESS_ROTATE_OBJECT, /* currently study or data set only */ CANVAS_EVENT_PRESS_NEW_ROI, CANVAS_EVENT_PRESS_SHIFT_OBJECT_IMMEDIATE, /* currently roi/line_profile/fiducial only */ CANVAS_EVENT_PRESS_ROTATE_OBJECT_IMMEDIATE, /* currently roi/line_profile only */ /* 10 */ CANVAS_EVENT_PRESS_RESIZE_ROI, CANVAS_EVENT_PRESS_ENTER_DRAWING_MODE, CANVAS_EVENT_PRESS_LEAVE_DRAWING_MODE, CANVAS_EVENT_PRESS_DRAW_POINT, CANVAS_EVENT_PRESS_DRAW_LARGE_POINT, CANVAS_EVENT_PRESS_ERASE_POINT, CANVAS_EVENT_PRESS_ERASE_LARGE_POINT, CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR, CANVAS_EVENT_PRESS_ERASE_VOLUME_INSIDE_ROI, CANVAS_EVENT_PRESS_ERASE_VOLUME_OUTSIDE_ROI, CANVAS_EVENT_PRESS_NEW_OBJECT, CANVAS_EVENT_MOTION, CANVAS_EVENT_MOTION_MOVE_VIEW, CANVAS_EVENT_MOTION_MINIMIZE_VIEW, CANVAS_EVENT_MOTION_RESIZE_VIEW, CANVAS_EVENT_MOTION_SHIFT_OBJECT, CANVAS_EVENT_MOTION_ROTATE_OBJECT, CANVAS_EVENT_MOTION_NEW_ROI, CANVAS_EVENT_MOTION_RESIZE_ROI, CANVAS_EVENT_MOTION_DRAW_POINT, CANVAS_EVENT_MOTION_DRAW_LARGE_POINT, CANVAS_EVENT_MOTION_ERASE_POINT, CANVAS_EVENT_MOTION_ERASE_LARGE_POINT, CANVAS_EVENT_MOTION_CHANGE_ISOCONTOUR, CANVAS_EVENT_RELEASE_MOVE_VIEW, CANVAS_EVENT_RELEASE_MINIMIZE_VIEW, CANVAS_EVENT_RELEASE_RESIZE_VIEW, CANVAS_EVENT_RELEASE_SHIFT_OBJECT, CANVAS_EVENT_RELEASE_ROTATE_OBJECT, CANVAS_EVENT_RELEASE_NEW_ROI, CANVAS_EVENT_RELEASE_SHIFT_OBJECT_IMMEDIATE, /* currently roi/line_profie/fiducial only */ CANVAS_EVENT_RELEASE_ROTATE_OBJECT_IMMEDIATE, CANVAS_EVENT_RELEASE_RESIZE_ROI, CANVAS_EVENT_RELEASE_DRAW_POINT, CANVAS_EVENT_RELEASE_DRAW_LARGE_POINT, CANVAS_EVENT_RELEASE_ERASE_POINT, CANVAS_EVENT_RELEASE_ERASE_LARGE_POINT, CANVAS_EVENT_RELEASE_CHANGE_ISOCONTOUR, CANVAS_EVENT_CANCEL_SHIFT_OBJECT, CANVAS_EVENT_CANCEL_ROTATE_OBJECT, CANVAS_EVENT_CANCEL_CHANGE_ISOCONTOUR, CANVAS_EVENT_ENACT_SHIFT_OBJECT, CANVAS_EVENT_ENACT_ROTATE_OBJECT, CANVAS_EVENT_ENACT_CHANGE_ISOCONTOUR, CANVAS_EVENT_SCROLL_UP, CANVAS_EVENT_SCROLL_DOWN, } canvas_event_t; static void canvas_class_init (AmitkCanvasClass *klass); static void canvas_init (AmitkCanvas *canvas); static void canvas_destroy(GtkObject * object); static GnomeCanvasItem * canvas_find_item(AmitkCanvas * canvas, AmitkObject * object); static GList * canvas_add_current_objects(AmitkCanvas * canvas, GList * objects); static void canvas_space_changed_cb(AmitkSpace * space, gpointer canvas); static void canvas_object_selection_changed_cb(AmitkObject * object, gpointer canvas); static void canvas_object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data); static void canvas_object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data); static void canvas_view_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_roi_preference_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_general_preference_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_line_profile_changed_cb(AmitkLineProfile * line_profile, gpointer data); static void canvas_target_preference_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_layout_preference_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_study_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_target_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_time_changed_cb(AmitkStudy * study, gpointer canvas); static void canvas_volume_changed_cb(AmitkVolume * vol, gpointer canvas); static void canvas_roi_changed_cb(AmitkRoi * roi, gpointer canvas); static void canvas_fiducial_mark_changed_cb(AmitkFiducialMark * fm, gpointer canvas); static void canvas_data_set_invalidate_slice_cache(AmitkDataSet * ds, gpointer data); static void data_set_changed_cb(AmitkDataSet * ds, gpointer canvas); static void data_set_subject_orientation_changed_cb(AmitkDataSet * ds, gpointer canvas); static void data_set_thresholding_changed_cb(AmitkDataSet * ds, gpointer data); static void data_set_color_table_changed_cb(AmitkDataSet * ds, AmitkViewMode view_mode, gpointer data); static amide_real_t canvas_check_z_dimension(AmitkCanvas * canvas, amide_real_t z); static void canvas_create_isocontour_roi(AmitkCanvas * canvas, AmitkRoi * roi, AmitkPoint position, AmitkDataSet * active_slice); static gboolean canvas_create_freehand_roi(AmitkCanvas * canvas, AmitkRoi * roi, AmitkPoint position, AmitkDataSet * active_slice); static gboolean canvas_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void canvas_scrollbar_adjustment_cb(GtkObject * adjustment, gpointer data); static gboolean canvas_recalc_corners(AmitkCanvas * canvas); static void canvas_update_scrollbar(AmitkCanvas * canvas, AmitkPoint center, amide_real_t thickness); static void canvas_update_target(AmitkCanvas * canvas, AmitkCanvasTargetAction action, AmitkPoint center, amide_real_t thickness); static void canvas_update_arrows(AmitkCanvas * canvas); static void canvas_update_line_profile(AmitkCanvas * canvas); static void canvas_update_time_on_image(AmitkCanvas * canvas); static void canvas_update_subject_orientation(AmitkCanvas * canvas); static void canvas_update_pixbuf(AmitkCanvas * canvas); static void canvas_update_object(AmitkCanvas * canvas, AmitkObject * object); static void canvas_update_objects(AmitkCanvas * canvas, gboolean all); static void canvas_update_setup(AmitkCanvas * canvas); static void canvas_add_object_update(AmitkCanvas * canvas, AmitkObject * object); static void canvas_add_update(AmitkCanvas * canvas, guint update_type); static gboolean canvas_update_while_idle(gpointer canvas); static void canvas_add_object(AmitkCanvas * canvas, AmitkObject * object); static void canvas_remove_object(AmitkCanvas * canvas, AmitkObject * object); static GtkVBoxClass *canvas_parent_class; static guint canvas_signals[LAST_SIGNAL]; GType amitk_canvas_get_type (void) { static GType canvas_type = 0; if (!canvas_type) { static const GTypeInfo canvas_info = { sizeof (AmitkCanvasClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) canvas_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkCanvas), 0, /* # preallocs */ (GInstanceInitFunc) canvas_init, NULL /* value table */ }; canvas_type = g_type_register_static (GTK_TYPE_VBOX, "AmitkCanvas", &canvas_info, 0); } return canvas_type; } static void canvas_class_init (AmitkCanvasClass *klass) { GtkObjectClass *gtkobject_class; /* GtkWidgetClass *widget_class; GObjectClass *gobject_class; */ gtkobject_class = (GtkObjectClass*) klass; /* widget_class = (GtkWidgetClass*) klass; gobject_class = (GObjectClass *) klass; */ canvas_parent_class = g_type_class_peek_parent(klass); gtkobject_class->destroy = canvas_destroy; canvas_signals[HELP_EVENT] = g_signal_new ("help_event", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkCanvasClass, help_event), NULL,NULL, amitk_marshal_VOID__ENUM_BOXED_DOUBLE, G_TYPE_NONE, 3, AMITK_TYPE_HELP_INFO, AMITK_TYPE_POINT, AMITK_TYPE_DATA); canvas_signals[VIEW_CHANGING] = g_signal_new ("view_changing", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkCanvasClass, view_changing), NULL,NULL, amitk_marshal_VOID__BOXED_DOUBLE, G_TYPE_NONE, 2, AMITK_TYPE_POINT, AMITK_TYPE_REAL); canvas_signals[VIEW_CHANGED] = g_signal_new ("view_changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkCanvasClass, view_changed), NULL,NULL, amitk_marshal_VOID__BOXED_DOUBLE, G_TYPE_NONE, 2, AMITK_TYPE_POINT, AMITK_TYPE_REAL); canvas_signals[ERASE_VOLUME] = g_signal_new("erase_volume", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkCanvasClass, erase_volume), NULL,NULL, amitk_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, AMITK_TYPE_ROI, G_TYPE_BOOLEAN); canvas_signals[NEW_OBJECT] = g_signal_new ("new_object", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkCanvasClass, new_object), NULL,NULL, amitk_marshal_VOID__OBJECT_ENUM_BOXED, G_TYPE_NONE, 3, AMITK_TYPE_OBJECT, AMITK_TYPE_OBJECT_TYPE, AMITK_TYPE_POINT); } static void canvas_init (AmitkCanvas *canvas) { gint i; gtk_box_set_homogeneous(GTK_BOX(canvas), FALSE); /* initialize some critical stuff */ for (i=0;i<4;i++) canvas->arrows[i]=NULL; for (i=0;i<8;i++) canvas->target[i]=NULL; for (i=0;i<4;i++) canvas->orientation_label[i]=NULL; canvas->line_profile_item = NULL; canvas->type = AMITK_CANVAS_TYPE_NORMAL; canvas->volume = amitk_volume_new(); amitk_volume_set_corner(canvas->volume, one_point); canvas->center = zero_point; canvas->active_object = NULL; canvas->canvas = NULL; canvas->slice_cache = NULL; canvas->max_slice_cache_size = 15; canvas->slices=NULL; canvas->image=NULL; canvas->pixbuf=NULL; canvas->time_on_image=FALSE; canvas->time_label=NULL; canvas->pixbuf_width = 128; canvas->pixbuf_height = 128; canvas->study = NULL; canvas->undrawn_rois = NULL; canvas->object_items=NULL; canvas->next_update = 0; canvas->idle_handler_id = 0; canvas->next_update_objects = NULL; } static void canvas_destroy (GtkObject * object) { AmitkCanvas * canvas; g_return_if_fail (object != NULL); g_return_if_fail (AMITK_IS_CANVAS (object)); canvas = AMITK_CANVAS(object); if (canvas->idle_handler_id != 0) { g_source_remove(canvas->idle_handler_id); canvas->idle_handler_id = 0; } if (canvas->next_update_objects != NULL) { canvas->next_update_objects = amitk_objects_unref(canvas->next_update_objects); } if (canvas->volume != NULL) canvas->volume = amitk_object_unref(canvas->volume); if (canvas->slice_cache != NULL) { canvas->slice_cache = amitk_objects_unref(canvas->slice_cache); } if (canvas->slices != NULL) { canvas->slices = amitk_objects_unref(canvas->slices); } if (canvas->pixbuf != NULL) { g_object_unref(canvas->pixbuf); canvas->pixbuf = NULL; } if (canvas->undrawn_rois != NULL) { canvas->undrawn_rois = amitk_objects_unref(canvas->undrawn_rois); } if (canvas->study != NULL) { canvas_remove_object(canvas, AMITK_OBJECT(canvas->study)); canvas->study = NULL; } if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object); } static GnomeCanvasItem * canvas_find_item(AmitkCanvas * canvas, AmitkObject * object) { GList * items=canvas->object_items; while (items != NULL) { if (object == g_object_get_data(G_OBJECT(items->data), "object")) return items->data; items = items->next; } return NULL; } /* returns a referenced list of all the objects that currently have items on display. If objects != NULL, the returned list will be the concatenation of "objects" and currently appearing items not in "objects" */ static GList * canvas_add_current_objects(AmitkCanvas * canvas, GList * objects) { AmitkObject * object; GList * items=canvas->object_items; while (items != NULL) { object = g_object_get_data(G_OBJECT(items->data), "object"); if (object != NULL) if (g_list_index(objects, object) < 0) objects = g_list_append(objects, amitk_object_ref(object)); items = items->next; } return objects; } AmitkColorTable canvas_get_color_table(AmitkCanvas * canvas) { if (canvas->active_object != NULL) if (AMITK_IS_DATA_SET(canvas->active_object)) return amitk_data_set_get_color_table_to_use(AMITK_DATA_SET(canvas->active_object), AMITK_CANVAS_VIEW_MODE(canvas)); return AMITK_COLOR_TABLE_BW_LINEAR; /* default */ } static void canvas_space_changed_cb(AmitkSpace * space, gpointer data) { AmitkObject * object; AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); canvas_add_object_update(canvas, object); return; } static void canvas_object_selection_changed_cb(AmitkObject * object, gpointer data) { AmitkCanvas * canvas = data; GnomeCanvasItem * item; gboolean undrawn_roi=FALSE; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(object)); if (AMITK_IS_DATA_SET(object)) { /* update on select or unselect */ canvas_add_update(canvas, UPDATE_ALL); } else { if (AMITK_IS_ROI(object)) undrawn_roi = AMITK_ROI_UNDRAWN(object); if (amitk_object_get_selected(object, canvas->view_mode)) { if (undrawn_roi) { if (g_list_index(canvas->undrawn_rois, object) < 0) /* not yet in list */ canvas->undrawn_rois = g_list_prepend(canvas->undrawn_rois, amitk_object_ref(object)); } else { canvas_add_object_update(canvas, object); } } else { if (undrawn_roi) { if (g_list_index(canvas->undrawn_rois, object) >= 0) { canvas->undrawn_rois = g_list_remove(canvas->undrawn_rois, object); amitk_object_unref(object); } } else if ((item = canvas_find_item(canvas, object)) != NULL) { /* an unselect */ canvas->object_items = g_list_remove(canvas->object_items, item); gtk_object_destroy(GTK_OBJECT(item)); canvas_add_update(canvas, UPDATE_VIEW); /* needed to check if we need to reset the view slice */ } } } return; } static void canvas_object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(child)); canvas_add_object(AMITK_CANVAS(canvas), child); return; } static void canvas_object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(child)); canvas_remove_object(AMITK_CANVAS(canvas), child); return; } static void canvas_view_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; gboolean changed=FALSE; gboolean coords_changed = FALSE; AmitkPoint temp[2]; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(study)); if (!REAL_EQUAL(AMITK_STUDY_VIEW_THICKNESS(study), AMITK_VOLUME_Z_CORNER(canvas->volume))) { amitk_volume_set_z_corner(canvas->volume, AMITK_STUDY_VIEW_THICKNESS(study)); changed = TRUE; } temp[0] = amitk_space_b2s(AMITK_SPACE(canvas->volume), AMITK_STUDY_VIEW_CENTER(study)); temp[1] = amitk_space_b2s(AMITK_SPACE(canvas->volume), canvas->center); if (!REAL_EQUAL(temp[0].z, temp[1].z)) changed = TRUE; /* only need to update if z's changed */ else if (!POINT_EQUAL(temp[0], temp[1])) coords_changed = TRUE; canvas->center = AMITK_STUDY_VIEW_CENTER(study); if (changed) { canvas_add_update(canvas, UPDATE_ALL); } else if (coords_changed) { canvas_add_update(canvas, UPDATE_ARROWS); canvas_add_update(canvas, UPDATE_TARGET); canvas_add_update(canvas, UPDATE_LINE_PROFILE); } return; } static void canvas_roi_preference_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; canvas_add_update(canvas, UPDATE_OBJECTS); /* line_style, transparency, roi_width, fill_roi */ return; } static void canvas_general_preference_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; canvas_add_update(canvas, UPDATE_ALL); /* maintain_size */ return; } static void canvas_target_preference_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; canvas_add_update(canvas, UPDATE_TARGET); /* target_empty_area */ return; } static void canvas_layout_preference_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; amitk_space_set_view_space(AMITK_SPACE(canvas->volume), canvas->view, AMITK_STUDY_CANVAS_LAYOUT(canvas->study)); canvas_recalc_corners(canvas); /* make sure everything's specified correctly */ canvas_update_setup(canvas); return; } static void canvas_line_profile_changed_cb(AmitkLineProfile * line_profile, gpointer data) { AmitkCanvas * canvas = data; canvas_add_update(canvas, UPDATE_LINE_PROFILE); return; } static void canvas_study_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; canvas_add_update(canvas, UPDATE_ALL); return; } static void canvas_target_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; if (AMITK_STUDY_CANVAS_TARGET(study)) canvas->next_target_action = AMITK_CANVAS_TARGET_ACTION_LEAVE; else canvas->next_target_action = AMITK_CANVAS_TARGET_ACTION_HIDE; canvas_add_update(canvas, UPDATE_TARGET); return; } static void canvas_time_changed_cb(AmitkStudy * study, gpointer data) { AmitkCanvas * canvas = data; canvas_add_update(canvas, UPDATE_ALL); } static void canvas_volume_changed_cb(AmitkVolume * vol, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_VOLUME(vol)); /* check if we need to remove the roi from the undrawn list */ if (AMITK_IS_ROI(vol)) if (!AMITK_ROI_UNDRAWN(vol)) if (g_list_index(canvas->undrawn_rois, vol) >= 0) { canvas->undrawn_rois = g_list_remove(canvas->undrawn_rois, vol); amitk_object_unref(vol); } canvas_add_object_update(canvas, AMITK_OBJECT(vol)); return; } static void canvas_roi_changed_cb(AmitkRoi * roi, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_ROI(roi)); canvas_add_object_update(canvas, AMITK_OBJECT(roi)); return; } static void canvas_fiducial_mark_changed_cb(AmitkFiducialMark * fm, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_FIDUCIAL_MARK(fm)); canvas_add_object_update(canvas, AMITK_OBJECT(fm)); return; } static void canvas_data_set_invalidate_slice_cache(AmitkDataSet * ds, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_DATA_SET(ds)); canvas->slice_cache = amitk_data_sets_remove_with_slice_parent(canvas->slice_cache, ds); } static void data_set_changed_cb(AmitkDataSet * ds, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_DATA_SET(ds)); canvas_add_object_update(canvas, AMITK_OBJECT(ds)); return; } static void data_set_subject_orientation_changed_cb(AmitkDataSet * ds, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds == AMITK_DATA_SET(canvas->active_object)) canvas_add_update(canvas, UPDATE_SUBJECT_ORIENTATION); return; } static void data_set_thresholding_changed_cb(AmitkDataSet * ds, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_DATA_SET(ds)); canvas_add_update(canvas, UPDATE_DATA_SETS); } static void data_set_color_table_changed_cb(AmitkDataSet * ds, AmitkViewMode view_mode, gpointer data) { AmitkCanvas * canvas = data; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (view_mode == AMITK_CANVAS_VIEW_MODE(canvas)) { canvas_add_update(canvas, UPDATE_DATA_SETS); canvas_add_update(canvas, UPDATE_OBJECTS); } } static void value_spin_cb(GtkWidget * widget, gpointer data) { gdouble * value = data; *value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static amide_real_t canvas_check_z_dimension(AmitkCanvas * canvas, amide_real_t z) { GtkWindow * window; GtkWidget * toplevel; GtkWidget * dialog; GtkWidget * table; GtkWidget * label; GtkWidget * spin_button; GtkWidget * image; g_return_val_if_fail(AMITK_IS_CANVAS(canvas), z); toplevel = gtk_widget_get_toplevel (GTK_WIDGET(canvas)); if (toplevel != NULL) window = GTK_WINDOW(toplevel); else window = NULL; dialog = gtk_dialog_new_with_buttons (_("ROI Depth Selection"), window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); table = gtk_table_new(1,3,FALSE); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); /* pick depth of roi */ image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,GTK_ICON_SIZE_DIALOG); gtk_table_attach(GTK_TABLE(table), image, 0,1, 0,1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("Please pick depth of ROI (mm):")); gtk_table_attach(GTK_TABLE(table), label, 1,2, 0,1, 0, 0, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, MAX(z,EPSILON)); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), z); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_button),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_ALWAYS); gtk_entry_set_activates_default(GTK_ENTRY(spin_button), TRUE); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(value_spin_cb), &z); g_signal_connect(G_OBJECT(spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), spin_button, 2,3, 0,1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show_all(dialog); gtk_dialog_run(GTK_DIALOG(dialog)); /* let the user input */ gtk_widget_destroy(dialog); return z; } static void isocontour_gray_spins(AmitkRoiIsocontourRange isocontour_range, GtkWidget * min_spin_button, GtkWidget * max_spin_button) { switch (isocontour_range) { case AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX: gtk_widget_set_sensitive(min_spin_button, TRUE); gtk_widget_set_sensitive(max_spin_button, TRUE); break; case AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX: gtk_widget_set_sensitive(min_spin_button, FALSE); gtk_widget_set_sensitive(max_spin_button, TRUE); break; case AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN: default: gtk_widget_set_sensitive(min_spin_button, TRUE); gtk_widget_set_sensitive(max_spin_button, FALSE); break; } return; } static void isocontour_range_cb(GtkWidget * widget, gpointer data) { AmitkRoiIsocontourRange *pisocontour_range = data; GtkWidget * min_spin_button; GtkWidget * max_spin_button; /* get the state of the button */ *pisocontour_range = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "isocontour_range")); min_spin_button = g_object_get_data(G_OBJECT(widget), "min_spin_button"); max_spin_button = g_object_get_data(G_OBJECT(widget), "max_spin_button"); /* appropriately gray them out */ isocontour_gray_spins(*pisocontour_range, min_spin_button, max_spin_button); return; } static void canvas_create_isocontour_roi(AmitkCanvas * canvas, AmitkRoi * roi, AmitkPoint position, AmitkDataSet * active_slice) { AmitkPoint temp_point; AmitkVoxel temp_voxel; amide_time_t start_time, end_time; AmitkObject * parent_ds; AmitkDataSet * draw_on_ds=NULL; GtkWindow * window; GtkWidget * toplevel; amide_intpoint_t gate; GtkWidget * hbox; GtkWidget * dialog; GtkWidget * table; GtkWidget * label; GtkWidget * min_spin_button; GtkWidget * max_spin_button; GtkWidget * image; GtkWidget * radio_button[3]; amide_data_t isocontour_min_value; amide_data_t isocontour_max_value; AmitkRoiIsocontourRange isocontour_range; AmitkRoiIsocontourRange i_range; gint table_row; gchar * temp_str; gint return_val; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_ROI(roi)); g_return_if_fail(AMITK_ROI_TYPE_ISOCONTOUR(roi)); /* figure out the data set we're drawing on */ parent_ds = amitk_object_get_parent_of_type(AMITK_OBJECT(roi), AMITK_OBJECT_TYPE_DATA_SET); if (AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_ISOCONTOUR_2D) { if (parent_ds != NULL) { draw_on_ds = amitk_data_sets_find_with_slice_parent(canvas->slices, AMITK_DATA_SET(parent_ds)); if (draw_on_ds == NULL) { g_warning(_("Parent of isocontour not currently displayed, can't draw isocontour")); return; } } else if (active_slice != NULL) { /* if no data set parent, just use the active slice */ draw_on_ds = active_slice; } } else { /* ISOCONTOUR_3D */ if (parent_ds != NULL) draw_on_ds = AMITK_DATA_SET(parent_ds); else if (canvas->active_object != NULL) if (AMITK_IS_DATA_SET(canvas->active_object)) draw_on_ds = AMITK_DATA_SET(canvas->active_object); } if (draw_on_ds == NULL) { g_warning(_("No data set found to draw isocontour on")); return; } start_time = AMITK_STUDY_VIEW_START_TIME(canvas->study); temp_point = amitk_space_b2s(AMITK_SPACE(draw_on_ds), position); if (AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_ISOCONTOUR_3D) gate = AMITK_DATA_SET_VIEW_START_GATE(draw_on_ds); else gate = 0; POINT_TO_VOXEL(temp_point, AMITK_DATA_SET_VOXEL_SIZE(draw_on_ds), amitk_data_set_get_frame(AMITK_DATA_SET(draw_on_ds), start_time), gate, temp_voxel); if (!amitk_raw_data_includes_voxel(AMITK_DATA_SET_RAW_DATA(draw_on_ds),temp_voxel)) { g_warning(_("designated voxel not in data set %s"), AMITK_OBJECT_NAME(draw_on_ds)); return; } /* what we probably want to set the isocontour too */ isocontour_min_value = amitk_data_set_get_value(draw_on_ds, temp_voxel); isocontour_max_value = isocontour_min_value; isocontour_range = AMITK_ROI_ISOCONTOUR_RANGE(roi); toplevel = gtk_widget_get_toplevel (GTK_WIDGET(canvas)); if (toplevel != NULL) window = GTK_WINDOW(toplevel); else window = NULL; /* pop up dialog to let user pick isocontour values, etc. and for any warning messages */ dialog = gtk_dialog_new_with_buttons (_("Isocontour Value Selection"), window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); table = gtk_table_new(4,3,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); /* complain if more then one frame or gate is currently showing for ISOCONTOUR_3D */ if (AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_ISOCONTOUR_3D) { end_time = start_time + AMITK_STUDY_VIEW_DURATION(canvas->study); /* warning for multiple frames */ if (temp_voxel.t != amitk_data_set_get_frame(AMITK_DATA_SET(draw_on_ds), end_time)) { image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING,GTK_ICON_SIZE_DIALOG); gtk_table_attach(GTK_TABLE(table), image, 0,1, table_row,table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); temp_str = g_strdup_printf(_("Multiple data frames are currently being shown from: %s\nThe isocontour will only be drawn over frame %d"),AMITK_OBJECT_NAME(draw_on_ds), temp_voxel.t); label = gtk_label_new(temp_str); g_free(temp_str); gtk_table_attach(GTK_TABLE(table), label, 1,3,table_row,table_row+1, 0, 0, X_PADDING, Y_PADDING); table_row++; } /* warning for multiple gates */ if (AMITK_DATA_SET_VIEW_START_GATE(draw_on_ds) != AMITK_DATA_SET_VIEW_END_GATE(draw_on_ds)) { image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING,GTK_ICON_SIZE_DIALOG); gtk_table_attach(GTK_TABLE(table), image, 0,1, table_row,table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); temp_str = g_strdup_printf(_("Multiple gates are currently being shown from: %s\nThe isocontour will only be drawn over gate %d"),AMITK_OBJECT_NAME(draw_on_ds), temp_voxel.g); label = gtk_label_new(temp_str); g_free(temp_str); gtk_table_attach(GTK_TABLE(table), label, 1,3, table_row,table_row+1, 0, 0, X_PADDING, Y_PADDING); table_row++; } } image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,GTK_ICON_SIZE_DIALOG); gtk_table_attach(GTK_TABLE(table), image, 0,1, table_row,table_row+2, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); /* box where the radio buttons will go */ hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(table), hbox,1,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); table_row++; /* the spin buttons */ label = gtk_label_new(_("Min:")); gtk_table_attach(GTK_TABLE(table), label, 1,2, table_row,table_row+1, 0, 0, X_PADDING, Y_PADDING); min_spin_button = gtk_spin_button_new_with_range(-G_MAXDOUBLE, isocontour_min_value, MAX(EPSILON,fabs(isocontour_min_value)/10)); gtk_spin_button_set_value(GTK_SPIN_BUTTON(min_spin_button), isocontour_min_value); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(min_spin_button),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(min_spin_button), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(min_spin_button), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(min_spin_button), GTK_UPDATE_ALWAYS); gtk_entry_set_activates_default(GTK_ENTRY(min_spin_button), TRUE); g_signal_connect(G_OBJECT(min_spin_button), "value_changed", G_CALLBACK(value_spin_cb), &isocontour_min_value); g_signal_connect(G_OBJECT(min_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), min_spin_button, 2,3, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Max:")); gtk_table_attach(GTK_TABLE(table), label, 1,2, table_row,table_row+1, 0, 0, X_PADDING, Y_PADDING); max_spin_button = gtk_spin_button_new_with_range(isocontour_max_value, G_MAXDOUBLE, MAX(EPSILON,fabs(isocontour_max_value)/10)); gtk_spin_button_set_value(GTK_SPIN_BUTTON(max_spin_button), isocontour_max_value); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(max_spin_button),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(max_spin_button), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(max_spin_button), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(max_spin_button), GTK_UPDATE_ALWAYS); gtk_entry_set_activates_default(GTK_ENTRY(max_spin_button), TRUE); g_signal_connect(G_OBJECT(max_spin_button), "value_changed", G_CALLBACK(value_spin_cb), &isocontour_max_value); g_signal_connect(G_OBJECT(max_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), max_spin_button, 2,3, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* appropriately gray them out */ isocontour_gray_spins(isocontour_range, min_spin_button, max_spin_button); /* radio buttons to choose the isocontour type */ radio_button[0] = gtk_radio_button_new_with_label(NULL, _("Above Min")); radio_button[1] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button[0]), _("Below Max")); radio_button[2] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button[0]), _("Between Min/Max")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[isocontour_range]), TRUE); for (i_range=0; i_range < AMITK_ROI_ISOCONTOUR_RANGE_NUM; i_range++) { gtk_box_pack_start(GTK_BOX(hbox), radio_button[i_range], FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button[i_range]), "isocontour_range", GINT_TO_POINTER(i_range)); g_object_set_data(G_OBJECT(radio_button[i_range]), "min_spin_button", min_spin_button); g_object_set_data(G_OBJECT(radio_button[i_range]), "max_spin_button", max_spin_button); g_signal_connect(G_OBJECT(radio_button[i_range]), "clicked", G_CALLBACK(isocontour_range_cb), &isocontour_range); } /* run the dialog */ gtk_widget_show_all(dialog); return_val = gtk_dialog_run(GTK_DIALOG(dialog)); /* let the user input */ gtk_widget_destroy(dialog); if (return_val != GTK_RESPONSE_OK) return; /* cancel */ ui_common_place_cursor(UI_CURSOR_WAIT, GTK_WIDGET(canvas)); amitk_roi_set_isocontour(roi, AMITK_DATA_SET(draw_on_ds), temp_voxel, isocontour_min_value,isocontour_max_value, isocontour_range); ui_common_remove_wait_cursor(GTK_WIDGET(canvas)); return; } /* returns true if sucessfully completed */ static gboolean canvas_create_freehand_roi(AmitkCanvas * canvas, AmitkRoi * roi, AmitkPoint position, AmitkDataSet * active_slice) { AmitkObject * parent_ds; AmitkDataSet * draw_on_ds=NULL; GtkWindow * window; GtkWidget * toplevel; GtkWidget * dialog; GtkWidget * table; GtkWidget * label; GtkWidget * spin_button[3]; GtkWidget * image; gint table_row; gchar * temp_str; gint return_val; AmitkPoint voxel_size; AmitkPoint temp_point; AmitkVoxel temp_voxel; AmitkAxis i_axis; g_return_val_if_fail(AMITK_IS_CANVAS(canvas), FALSE); g_return_val_if_fail(AMITK_IS_ROI(roi), FALSE); g_return_val_if_fail(AMITK_ROI_TYPE_FREEHAND(roi), FALSE); /* figure out the data set we're drawing on */ parent_ds = amitk_object_get_parent_of_type(AMITK_OBJECT(roi), AMITK_OBJECT_TYPE_DATA_SET); if (AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_FREEHAND_2D) { if (parent_ds != NULL) { draw_on_ds = amitk_data_sets_find_with_slice_parent(canvas->slices, AMITK_DATA_SET(parent_ds)); if (draw_on_ds == NULL) { g_warning(_("Parent of roi not currently displayed, can't draw freehand roi")); return FALSE; } } else if (active_slice != NULL) { /* if no data set parent, just use the active slice */ draw_on_ds = active_slice; } } else { /* FREEHAND_3D */ if (parent_ds != NULL) draw_on_ds = AMITK_DATA_SET(parent_ds); else if (canvas->active_object != NULL) if (AMITK_IS_DATA_SET(canvas->active_object)) draw_on_ds = AMITK_DATA_SET(canvas->active_object); } if (draw_on_ds == NULL) { g_warning(_("No data set found to draw freehand roi on")); return FALSE; } voxel_size = AMITK_DATA_SET_VOXEL_SIZE(draw_on_ds); toplevel = gtk_widget_get_toplevel (GTK_WIDGET(canvas)); if (toplevel != NULL) window = GTK_WINDOW(toplevel); else window = NULL; /* pop up dialog to let user pick isocontour values, etc. and for any warning messages */ dialog = gtk_dialog_new_with_buttons (_("Freehand ROI Parameters"), window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); table = gtk_table_new(4,3,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,GTK_ICON_SIZE_DIALOG); gtk_table_attach(GTK_TABLE(table), image, 0,1, table_row,table_row+2, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); /* the spin buttons */ for (i_axis=0; i_axistype, widget, grab_on, // (GNOME_CANVAS(canvas->canvas)->grabbed_item)); // if ((event->type == GDK_BUTTON_PRESS) || // (event->type == GDK_BUTTON_RELEASE) || // (event->type == GDK_2BUTTON_PRESS)) // g_print("event %d widget %p grab_on %d %p\n", event->type, widget, grab_on, // (GNOME_CANVAS(canvas->canvas)->grabbed_item)); if (canvas->type == AMITK_CANVAS_TYPE_FLY_THROUGH) return FALSE; /* sanity checks */ if (canvas->study == NULL) return FALSE; if (canvas->slices == NULL) return FALSE; g_return_val_if_fail(canvas->active_object != NULL, FALSE); if (ignore_next_event) { ignore_next_event=FALSE; return FALSE; } /* check if we should bail out of drawing mode */ if (in_drawing_mode) { if (drawing_object != NULL) { if (!amitk_object_get_selected(drawing_object, AMITK_SELECTION_ANY)) { in_drawing_mode = FALSE; drawing_object = NULL; ui_common_place_cursor(UI_CURSOR_DEFAULT, GTK_WIDGET(canvas)); } } } if (extended_object != NULL) object = extended_object; if (canvas->undrawn_rois != NULL) /* check if there are any undrawn roi's */ object = canvas->undrawn_rois->data; if (object == NULL) /* no undrawn roi's, see if we're on an object */ object = g_object_get_data(G_OBJECT(widget), "object"); if (object == NULL) object = canvas->active_object; /* try the active object */ g_return_val_if_fail(object != NULL, FALSE); switch(event->type) { case GDK_ENTER_NOTIFY: event_cpoint.x = event->crossing.x; event_cpoint.y = event->crossing.y; if (event->crossing.mode != GDK_CROSSING_NORMAL) canvas_event_type = CANVAS_EVENT_NONE; /* ignore grabs */ else if (enter_drawing_mode) { canvas_event_type = CANVAS_EVENT_PRESS_ENTER_DRAWING_MODE; } else if ((canvas->undrawn_rois == NULL) && (extended_event_type != CANVAS_EVENT_NONE)) canvas_event_type = CANVAS_EVENT_NONE; else canvas_event_type = CANVAS_EVENT_ENTER_OBJECT; break; case GDK_LEAVE_NOTIFY: event_cpoint.x = event->crossing.x; event_cpoint.y = event->crossing.y; if (event->crossing.mode != GDK_CROSSING_NORMAL) canvas_event_type = CANVAS_EVENT_NONE; /* ignore grabs */ else if (extended_event_type != CANVAS_EVENT_NONE) canvas_event_type = CANVAS_EVENT_NONE; else canvas_event_type = CANVAS_EVENT_LEAVE; break; case GDK_BUTTON_PRESS: event_cpoint.x = event->button.x; event_cpoint.y = event->button.y; if (enter_drawing_mode) { canvas_event_type = CANVAS_EVENT_PRESS_ENTER_DRAWING_MODE; } else if (canvas->undrawn_rois != NULL) { canvas_event_type = CANVAS_EVENT_PRESS_NEW_ROI; } else if (in_drawing_mode) { if ((event->button.button == 1) && (event->button.state & GDK_SHIFT_MASK)) canvas_event_type = CANVAS_EVENT_PRESS_DRAW_LARGE_POINT; else if (event->button.button == 1) canvas_event_type = CANVAS_EVENT_PRESS_DRAW_POINT; else if (event->button.button == 2) canvas_event_type = CANVAS_EVENT_PRESS_LEAVE_DRAWING_MODE; else if ((event->button.button == 3) && (event->button.state & GDK_SHIFT_MASK)) canvas_event_type = CANVAS_EVENT_PRESS_ERASE_LARGE_POINT; else if (event->button.button == 3) canvas_event_type = CANVAS_EVENT_PRESS_ERASE_POINT; else canvas_event_type = CANVAS_EVENT_NONE; } else if (extended_event_type != CANVAS_EVENT_NONE) { canvas_event_type = extended_event_type; } else if ((!grab_on) && (!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->button.button == 1)) { if ((event->button.state & GDK_SHIFT_MASK) && (AMITK_IS_DATA_SET(object))) canvas_event_type = CANVAS_EVENT_PRESS_SHIFT_OBJECT; else canvas_event_type = CANVAS_EVENT_PRESS_MOVE_VIEW; } else if ((!grab_on) && (!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->button.button == 2)) { canvas_event_type = CANVAS_EVENT_PRESS_MINIMIZE_VIEW; } else if ((!grab_on) && (!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->button.button == 3)) { if (event->button.state & GDK_CONTROL_MASK) canvas_event_type = CANVAS_EVENT_PRESS_NEW_OBJECT; else if (event->button.state & GDK_SHIFT_MASK) canvas_event_type = CANVAS_EVENT_PRESS_ROTATE_OBJECT; else canvas_event_type = CANVAS_EVENT_PRESS_RESIZE_VIEW; } else if ((!grab_on) && (AMITK_IS_ROI(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_PRESS_SHIFT_OBJECT_IMMEDIATE; } else if ((!grab_on) && (AMITK_IS_ROI(object)) && (event->button.button == 2)) { if (!AMITK_ROI_TYPE_ISOCONTOUR(object) && !AMITK_ROI_TYPE_FREEHAND(object)) canvas_event_type = CANVAS_EVENT_PRESS_RESIZE_ROI; else canvas_event_type = CANVAS_EVENT_PRESS_ENTER_DRAWING_MODE; } else if ((!grab_on) && (AMITK_IS_ROI(object)) && (event->button.button == 3)) { if (event->button.state & GDK_SHIFT_MASK) canvas_event_type = CANVAS_EVENT_PRESS_ERASE_VOLUME_OUTSIDE_ROI; else if (event->button.state & GDK_CONTROL_MASK) canvas_event_type = CANVAS_EVENT_PRESS_ERASE_VOLUME_INSIDE_ROI; else if (!AMITK_ROI_TYPE_ISOCONTOUR(object) && !AMITK_ROI_TYPE_FREEHAND(object)) canvas_event_type = CANVAS_EVENT_PRESS_ROTATE_OBJECT_IMMEDIATE; else canvas_event_type = CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR; } else if ((!grab_on) && (AMITK_IS_FIDUCIAL_MARK(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_PRESS_SHIFT_OBJECT_IMMEDIATE; } else if ((!grab_on) && (AMITK_IS_LINE_PROFILE(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_PRESS_SHIFT_OBJECT_IMMEDIATE; } else if ((!grab_on) && (AMITK_IS_LINE_PROFILE(object)) && (event->button.button == 3)) { canvas_event_type = CANVAS_EVENT_PRESS_ROTATE_OBJECT_IMMEDIATE; } else canvas_event_type = CANVAS_EVENT_NONE; break; case GDK_MOTION_NOTIFY: event_cpoint.x = event->motion.x; event_cpoint.y = event->motion.y; if (grab_on && (canvas->undrawn_rois != NULL)) { canvas_event_type = CANVAS_EVENT_MOTION_NEW_ROI; } else if (enter_drawing_mode) { canvas_event_type = CANVAS_EVENT_PRESS_ENTER_DRAWING_MODE; } else if (in_drawing_mode) { if ((event->motion.state & GDK_BUTTON1_MASK) && (event->motion.state & GDK_SHIFT_MASK)) canvas_event_type = CANVAS_EVENT_MOTION_DRAW_LARGE_POINT; else if (event->motion.state & GDK_BUTTON1_MASK) canvas_event_type = CANVAS_EVENT_MOTION_DRAW_POINT; else if ((event->motion.state & GDK_BUTTON3_MASK) && (event->motion.state & GDK_SHIFT_MASK)) canvas_event_type = CANVAS_EVENT_MOTION_ERASE_LARGE_POINT; else if (event->motion.state & GDK_BUTTON3_MASK) canvas_event_type = CANVAS_EVENT_MOTION_ERASE_POINT; else canvas_event_type = CANVAS_EVENT_MOTION; } else if (extended_event_type != CANVAS_EVENT_NONE) { if (extended_event_type == CANVAS_EVENT_PRESS_ROTATE_OBJECT) canvas_event_type = CANVAS_EVENT_MOTION_ROTATE_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_SHIFT_OBJECT) canvas_event_type = CANVAS_EVENT_MOTION_SHIFT_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR) canvas_event_type = CANVAS_EVENT_MOTION_CHANGE_ISOCONTOUR; else { canvas_event_type = CANVAS_EVENT_NONE; g_warning("unexpected case in %s at line %d", __FILE__, __LINE__); } } else if (grab_on && (!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->motion.state & GDK_BUTTON1_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_MOVE_VIEW; } else if (grab_on && (!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->motion.state & GDK_BUTTON2_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_MINIMIZE_VIEW; } else if (grab_on && (!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->motion.state & GDK_BUTTON3_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_RESIZE_VIEW; } else if (grab_on && (AMITK_IS_ROI(object)) && (event->motion.state & GDK_BUTTON1_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_SHIFT_OBJECT; } else if (grab_on && (AMITK_IS_ROI(object)) && (event->motion.state & GDK_BUTTON2_MASK)) { if (!AMITK_ROI_TYPE_ISOCONTOUR(object) && !AMITK_ROI_TYPE_FREEHAND(object)) canvas_event_type = CANVAS_EVENT_MOTION_RESIZE_ROI; else { canvas_event_type = CANVAS_EVENT_NONE; g_warning("unexpected case in %s at line %d", __FILE__, __LINE__); } } else if (grab_on && (AMITK_IS_ROI(object)) && (event->motion.state & GDK_BUTTON3_MASK)) { if (!AMITK_ROI_TYPE_ISOCONTOUR(object) && !AMITK_ROI_TYPE_FREEHAND(object)) canvas_event_type = CANVAS_EVENT_MOTION_ROTATE_OBJECT; else canvas_event_type = CANVAS_EVENT_MOTION_CHANGE_ISOCONTOUR; } else if (grab_on && (AMITK_IS_FIDUCIAL_MARK(object)) && (event->motion.state & GDK_BUTTON1_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_SHIFT_OBJECT; } else if (grab_on && (AMITK_IS_LINE_PROFILE(object)) && (event->motion.state & GDK_BUTTON1_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_SHIFT_OBJECT; } else if (grab_on && (AMITK_IS_LINE_PROFILE(object)) && (event->motion.state & GDK_BUTTON3_MASK)) { canvas_event_type = CANVAS_EVENT_MOTION_ROTATE_OBJECT; } else canvas_event_type = CANVAS_EVENT_MOTION; break; case GDK_BUTTON_RELEASE: event_cpoint.x = event->button.x; event_cpoint.y = event->button.y; if (canvas->undrawn_rois != NULL) { canvas_event_type = CANVAS_EVENT_RELEASE_NEW_ROI; } else if (in_drawing_mode) { if ((event->button.button == 1) && (event->button.state & GDK_SHIFT_MASK)) canvas_event_type = CANVAS_EVENT_RELEASE_DRAW_LARGE_POINT; else if (event->button.button == 1) canvas_event_type = CANVAS_EVENT_RELEASE_DRAW_POINT; else if ((event->button.button == 3) && (event->button.state & GDK_SHIFT_MASK)) canvas_event_type = CANVAS_EVENT_RELEASE_ERASE_LARGE_POINT; else if (event->button.button == 3) canvas_event_type = CANVAS_EVENT_RELEASE_ERASE_POINT; else canvas_event_type = CANVAS_EVENT_NONE; } else if ((extended_event_type != CANVAS_EVENT_NONE) && (!grab_on) && (event->button.button == 3)) { if (extended_event_type == CANVAS_EVENT_PRESS_ROTATE_OBJECT) canvas_event_type = CANVAS_EVENT_ENACT_ROTATE_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_SHIFT_OBJECT) canvas_event_type = CANVAS_EVENT_ENACT_SHIFT_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR) canvas_event_type = CANVAS_EVENT_ENACT_CHANGE_ISOCONTOUR; else { canvas_event_type = CANVAS_EVENT_NONE; g_warning("unexpected case in %s at line %d", __FILE__, __LINE__); } } else if ((extended_event_type != CANVAS_EVENT_NONE) && (!grab_on)) { if (extended_event_type == CANVAS_EVENT_PRESS_ROTATE_OBJECT) canvas_event_type = CANVAS_EVENT_CANCEL_ROTATE_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_SHIFT_OBJECT) canvas_event_type = CANVAS_EVENT_CANCEL_SHIFT_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR) canvas_event_type = CANVAS_EVENT_CANCEL_CHANGE_ISOCONTOUR; else { canvas_event_type = CANVAS_EVENT_NONE; g_warning("unexpected case in %s at line %d", __FILE__, __LINE__); } } else if ((extended_event_type != CANVAS_EVENT_NONE) && (grab_on)) { if (extended_event_type == CANVAS_EVENT_PRESS_ROTATE_OBJECT) canvas_event_type = CANVAS_EVENT_RELEASE_ROTATE_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_SHIFT_OBJECT) canvas_event_type = CANVAS_EVENT_RELEASE_SHIFT_OBJECT; else if (extended_event_type == CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR) canvas_event_type = CANVAS_EVENT_RELEASE_CHANGE_ISOCONTOUR; else { canvas_event_type = CANVAS_EVENT_NONE; g_warning("unexpected case in %s at line %d", __FILE__, __LINE__); } } else if ((!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_RELEASE_MOVE_VIEW; } else if ((!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->button.button == 2)) { canvas_event_type = CANVAS_EVENT_RELEASE_MINIMIZE_VIEW; } else if ((!in_object) && (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) && (event->button.button == 3)) { canvas_event_type = CANVAS_EVENT_RELEASE_RESIZE_VIEW; } else if ((AMITK_IS_ROI(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_RELEASE_SHIFT_OBJECT_IMMEDIATE; } else if (grab_on && (AMITK_IS_ROI(object)) && (event->button.button == 2)) { if (!AMITK_ROI_TYPE_ISOCONTOUR(object) && !AMITK_ROI_TYPE_FREEHAND(object)) canvas_event_type = CANVAS_EVENT_RELEASE_RESIZE_ROI; else { canvas_event_type = CANVAS_EVENT_NONE; g_warning("unexpected case in %s at line %d", __FILE__, __LINE__); } } else if ((AMITK_IS_ROI(object)) && (event->button.button == 3)) { if (!AMITK_ROI_TYPE_ISOCONTOUR(object) && !AMITK_ROI_TYPE_FREEHAND(object)) canvas_event_type = CANVAS_EVENT_RELEASE_ROTATE_OBJECT_IMMEDIATE; else canvas_event_type = CANVAS_EVENT_RELEASE_CHANGE_ISOCONTOUR; } else if ((AMITK_IS_FIDUCIAL_MARK(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_RELEASE_SHIFT_OBJECT_IMMEDIATE; } else if ((AMITK_IS_LINE_PROFILE(object)) && (event->button.button == 1)) { canvas_event_type = CANVAS_EVENT_RELEASE_SHIFT_OBJECT_IMMEDIATE; } else if ((AMITK_IS_LINE_PROFILE(object)) && (event->button.button == 3)) { canvas_event_type = CANVAS_EVENT_RELEASE_ROTATE_OBJECT_IMMEDIATE; } else canvas_event_type = CANVAS_EVENT_NONE; break; case GDK_SCROLL: /* scroll wheel event */ event_cpoint.x = event_cpoint.y = 0; if (event->scroll.direction == GDK_SCROLL_UP) canvas_event_type = CANVAS_EVENT_SCROLL_UP; else if (event->scroll.direction == GDK_SCROLL_DOWN) canvas_event_type = CANVAS_EVENT_SCROLL_DOWN; else canvas_event_type = CANVAS_EVENT_NONE; break; default: event_cpoint.x = event_cpoint.y = 0; /* an event we don't handle */ canvas_event_type = CANVAS_EVENT_NONE; break; } // if ((canvas_event_type != CANVAS_EVENT_NONE) && // (canvas_event_type != CANVAS_EVENT_MOTION)) // g_print("%s event %d grab %d gdk %d in_object %d\n", AMITK_IS_OBJECT(object) ? AMITK_OBJECT_NAME(object) : "line_profile", // canvas_event_type, grab_on, event->type, in_object); /* get the location of the event, and convert it to the canvas coordinates */ gnome_canvas_window_to_world(GNOME_CANVAS(canvas->canvas), event_cpoint.x, event_cpoint.y, &canvas_cpoint.x, &canvas_cpoint.y); gnome_canvas_w2c_d(GNOME_CANVAS(canvas->canvas), canvas_cpoint.x, canvas_cpoint.y, &canvas_cpoint.x, &canvas_cpoint.y); /* Convert the event location info to real units */ canvas_point = cp_2_p(canvas, canvas_cpoint); base_point = amitk_space_s2b(AMITK_SPACE(canvas->volume), canvas_point); /* get the current location's value */ g_return_val_if_fail(canvas->slices != NULL, FALSE); active_slice = NULL; if (AMITK_IS_DATA_SET(canvas->active_object)) active_slice = amitk_data_sets_find_with_slice_parent(canvas->slices, AMITK_DATA_SET(canvas->active_object)); if (active_slice != NULL) { temp_point[0] = amitk_space_b2s(AMITK_SPACE(active_slice), base_point); POINT_TO_VOXEL(temp_point[0], AMITK_DATA_SET_VOXEL_SIZE(active_slice), 0,0,temp_voxel); voxel_value = amitk_data_set_get_value(active_slice, temp_voxel); } else { voxel_value = NAN; } switch (canvas_event_type) { case CANVAS_EVENT_ENTER_OBJECT: if (in_drawing_mode) { help_info = AMITK_HELP_INFO_CANVAS_DRAWING_MODE; cursor_type = UI_CURSOR_ROI_DRAW; } else if (AMITK_IS_DATA_SET(object)) { help_info = AMITK_HELP_INFO_CANVAS_DATA_SET; cursor_type =UI_CURSOR_DATA_SET_MODE; } else if (AMITK_IS_STUDY(object)) { help_info = AMITK_HELP_INFO_CANVAS_STUDY; cursor_type = UI_CURSOR_DATA_SET_MODE; } else if (AMITK_IS_FIDUCIAL_MARK(object)) { in_object = TRUE; help_info = AMITK_HELP_INFO_CANVAS_FIDUCIAL_MARK; cursor_type =UI_CURSOR_FIDUCIAL_MARK_MODE; } else if (AMITK_IS_ROI(object)) { in_object = TRUE; cursor_type = UI_CURSOR_ROI_MODE; if (AMITK_ROI_TYPE_ISOCONTOUR(object)) { if (AMITK_ROI_UNDRAWN(object)) help_info = AMITK_HELP_INFO_CANVAS_NEW_ISOCONTOUR_ROI; else { help_info = AMITK_HELP_INFO_CANVAS_ISOCONTOUR_ROI; } } else if (AMITK_ROI_TYPE_FREEHAND(object)) { if (AMITK_ROI_UNDRAWN(object)) help_info = AMITK_HELP_INFO_CANVAS_NEW_FREEHAND_ROI; else { help_info = AMITK_HELP_INFO_CANVAS_FREEHAND_ROI; } } else { /* geometric ROI's */ if (AMITK_ROI_UNDRAWN(object)) help_info = AMITK_HELP_INFO_CANVAS_NEW_ROI; else help_info = AMITK_HELP_INFO_CANVAS_ROI; } } else if (AMITK_IS_LINE_PROFILE(object)) { in_object = TRUE; help_info = AMITK_HELP_INFO_CANVAS_LINE_PROFILE; cursor_type = UI_CURSOR_FIDUCIAL_MARK_MODE; } else { g_return_val_if_reached(FALSE); } g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0,help_info, &base_point, 0.0); if (AMITK_IS_ROI(object)) if (!AMITK_ROI_UNDRAWN(object) && (AMITK_ROI_TYPE_ISOCONTOUR(object))) { if (AMITK_ROI_ISOCONTOUR_RANGE(object) == AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN) g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, AMITK_ROI(object)->isocontour_min_value); else if (AMITK_ROI_ISOCONTOUR_RANGE(object) == AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX) g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, AMITK_ROI(object)->isocontour_max_value); else /* AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX */ g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, 0.5*AMITK_ROI(object)->isocontour_min_value+ 0.5*AMITK_ROI(object)->isocontour_max_value); } gtk_widget_grab_focus(GTK_WIDGET(canvas)); /* move the keyboard entry focus into the canvas */ ui_common_place_cursor(cursor_type, GTK_WIDGET(canvas)); break; case CANVAS_EVENT_LEAVE: in_object = FALSE; ui_common_place_cursor(UI_CURSOR_DEFAULT, GTK_WIDGET(canvas)); break; case CANVAS_EVENT_PRESS_MINIMIZE_VIEW: case CANVAS_EVENT_PRESS_RESIZE_VIEW: case CANVAS_EVENT_PRESS_MOVE_VIEW: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point,voxel_value); if (canvas_event_type == CANVAS_EVENT_PRESS_MINIMIZE_VIEW) corner = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(canvas->study)); else corner = AMITK_VOLUME_Z_CORNER(canvas->volume); grab_on = TRUE; initial_base_point = base_point; canvas_update_target(canvas, AMITK_CANVAS_TARGET_ACTION_SHOW, base_point, corner); /* grabbing the target doesn't quite work, double click events aren't handled correctly */ gnome_canvas_item_grab(canvas->image, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK |GDK_BUTTON_PRESS_MASK , ui_common_cursor[UI_CURSOR_DATA_SET_MODE], event->button.time); g_signal_emit(G_OBJECT (canvas), canvas_signals[VIEW_CHANGING], 0, &base_point, corner); break; case CANVAS_EVENT_PRESS_SHIFT_OBJECT: case CANVAS_EVENT_PRESS_ROTATE_OBJECT: if (extended_event_type != CANVAS_EVENT_NONE) { grab_on = FALSE; /* do everything on the BUTTON_RELEASE */ } else { GdkPixbuf * pixbuf; if (AMITK_IS_DATA_SET(object)) { if (active_slice == NULL) { g_warning(_("The active data set is not visible")); return FALSE; } pixbuf = image_from_slice(active_slice, AMITK_CANVAS_VIEW_MODE(canvas)); } else pixbuf = g_object_ref(canvas->pixbuf); grab_on = TRUE; extended_event_type = canvas_event_type; extended_object = object; initial_cpoint = canvas_cpoint; initial_base_point = base_point; initial_canvas_point = canvas_point; previous_cpoint = canvas_cpoint; canvas_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_pixbuf_get_type(), "pixbuf",pixbuf, "x", (double) canvas->border_width, "y", (double) canvas->border_width, NULL); g_signal_connect(G_OBJECT(canvas_item), "event", G_CALLBACK(canvas_event_cb), canvas); g_object_unref(pixbuf); } if (canvas_event_type == CANVAS_EVENT_PRESS_SHIFT_OBJECT) { g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_SHIFT_OBJECT, &base_point, 0.0); } else { /* ROTATE */ g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_ROTATE_OBJECT, &base_point, 0.0); } break; case CANVAS_EVENT_PRESS_NEW_ROI: outline_color = amitk_color_table_outline_color(canvas_get_color_table(canvas), TRUE); initial_canvas_point = canvas_point; initial_cpoint = canvas_cpoint; /* create the new roi */ switch(AMITK_ROI_TYPE(object)) { case AMITK_ROI_TYPE_BOX: case AMITK_ROI_TYPE_ELLIPSOID: case AMITK_ROI_TYPE_CYLINDER: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_NEW_ROI, &base_point, 0.0); canvas_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), (AMITK_ROI_TYPE(object) == AMITK_ROI_TYPE_BOX) ? gnome_canvas_rect_get_type() : gnome_canvas_ellipse_get_type(), "x1",canvas_cpoint.x, "y1", canvas_cpoint.y, "x2", canvas_cpoint.x, "y2", canvas_cpoint.y, "fill_color", NULL, "outline_color_rgba", amitk_color_table_rgba_to_uint32(outline_color), "width_pixels", AMITK_STUDY_CANVAS_ROI_WIDTH(canvas->study), NULL); g_signal_connect(G_OBJECT(canvas_item), "event", G_CALLBACK(canvas_event_cb), canvas); grab_on = TRUE; gnome_canvas_item_grab(canvas_item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ui_common_cursor[UI_CURSOR_ROI_MODE], event->button.time); break; case AMITK_ROI_TYPE_ISOCONTOUR_2D: case AMITK_ROI_TYPE_ISOCONTOUR_3D: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_NEW_ISOCONTOUR_ROI, &base_point, 0.0); grab_on = TRUE; break; case AMITK_ROI_TYPE_FREEHAND_2D: case AMITK_ROI_TYPE_FREEHAND_3D: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_NEW_FREEHAND_ROI, &base_point, 0.0); break; default: grab_on = FALSE; g_error("unexpected case in %s at line %d, roi_type %d", __FILE__, __LINE__, AMITK_ROI_TYPE(object)); break; } break; case CANVAS_EVENT_PRESS_SHIFT_OBJECT_IMMEDIATE: previous_cpoint = canvas_cpoint; case CANVAS_EVENT_PRESS_ROTATE_OBJECT_IMMEDIATE: case CANVAS_EVENT_PRESS_RESIZE_ROI: if (AMITK_IS_LINE_PROFILE(object)) help_info = AMITK_HELP_INFO_CANVAS_LINE_PROFILE; else if (AMITK_IS_FIDUCIAL_MARK(object)) help_info = AMITK_HELP_INFO_CANVAS_FIDUCIAL_MARK; else if (AMITK_ROI_TYPE_ISOCONTOUR(object)) help_info = AMITK_HELP_INFO_CANVAS_ISOCONTOUR_ROI; else if (AMITK_ROI_TYPE_FREEHAND(object)) help_info = AMITK_HELP_INFO_CANVAS_FREEHAND_ROI; else /* normal roi */ help_info = AMITK_HELP_INFO_CANVAS_ROI; if (canvas_event_type == CANVAS_EVENT_PRESS_SHIFT_OBJECT_IMMEDIATE) cursor_type = UI_CURSOR_OBJECT_SHIFT; else if (canvas_event_type == CANVAS_EVENT_PRESS_ROTATE_OBJECT_IMMEDIATE) cursor_type = UI_CURSOR_ROI_ROTATE; else /* CANVAS_EVENT_PRESS_RESIZE_ROI */ cursor_type = UI_CURSOR_ROI_RESIZE; g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, help_info, &base_point, 0.0); g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); grab_on = TRUE; canvas_item = GNOME_CANVAS_ITEM(widget); gnome_canvas_item_grab(canvas_item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ui_common_cursor[cursor_type], event->button.time); initial_base_point = base_point; initial_cpoint = canvas_cpoint; initial_canvas_point = canvas_point; theta = 0.0; zoom.x = zoom.y = zoom.z = 1.0; break; case CANVAS_EVENT_PRESS_ENTER_DRAWING_MODE: in_drawing_mode = TRUE; enter_drawing_mode = FALSE; if (drawing_object == NULL) drawing_object = object; ui_common_place_cursor(UI_CURSOR_ROI_DRAW, GTK_WIDGET(canvas)); g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_DRAWING_MODE, &base_point, voxel_value); break; case CANVAS_EVENT_PRESS_LEAVE_DRAWING_MODE: in_drawing_mode = FALSE; drawing_object = NULL; ui_common_place_cursor(UI_CURSOR_DEFAULT, GTK_WIDGET(canvas)); ignore_next_event=TRUE; g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); break; case CANVAS_EVENT_PRESS_CHANGE_ISOCONTOUR: if (extended_event_type != CANVAS_EVENT_NONE) { grab_on = FALSE; /* do everything on the BUTTON_RELEASE */ } else { g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); grab_on = TRUE; extended_event_type = canvas_event_type; extended_object = object; } g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_CHANGE_ISOCONTOUR, &base_point, 0.0); break; case CANVAS_EVENT_PRESS_ERASE_VOLUME_OUTSIDE_ROI: g_return_val_if_fail(AMITK_IS_ROI(object), FALSE); g_signal_emit(G_OBJECT (canvas), canvas_signals[ERASE_VOLUME], 0, AMITK_ROI(object), TRUE); break; case CANVAS_EVENT_PRESS_ERASE_VOLUME_INSIDE_ROI: g_return_val_if_fail(AMITK_IS_ROI(object), FALSE); g_signal_emit(G_OBJECT (canvas), canvas_signals[ERASE_VOLUME], 0, AMITK_ROI(object), FALSE); break; case CANVAS_EVENT_PRESS_NEW_OBJECT: if (AMITK_IS_DATA_SET(object)) g_signal_emit(G_OBJECT (canvas), canvas_signals[NEW_OBJECT], 0, object, AMITK_OBJECT_TYPE_FIDUCIAL_MARK, &base_point); break; case CANVAS_EVENT_MOTION: if (!in_drawing_mode) if (AMITK_IS_ROI(object)) if (!AMITK_ROI_UNDRAWN(object)) if (AMITK_ROI_TYPE_ISOCONTOUR(object)) { if (AMITK_ROI_ISOCONTOUR_RANGE(object) == AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN) voxel_value = AMITK_ROI(object)->isocontour_min_value; else if (AMITK_ROI_ISOCONTOUR_RANGE(object) == AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX) voxel_value = AMITK_ROI(object)->isocontour_max_value; else /* AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX */ voxel_value = 0.5*(AMITK_ROI(object)->isocontour_min_value+AMITK_ROI(object)->isocontour_max_value); } g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); break; case CANVAS_EVENT_MOTION_MOVE_VIEW: case CANVAS_EVENT_MOTION_MINIMIZE_VIEW: case CANVAS_EVENT_MOTION_RESIZE_VIEW: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); if (canvas_event_type == CANVAS_EVENT_MOTION_RESIZE_VIEW) { corner = point_max_dim(point_diff(base_point, initial_base_point)); center = initial_base_point; } else if (canvas_event_type == CANVAS_EVENT_MOTION_MOVE_VIEW) { corner = AMITK_VOLUME_Z_CORNER(canvas->volume); center = base_point; } else { /* CANVAS_EVENT_MOTION_MINIMIZE_VIEW */ corner = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(canvas->study)); center = base_point; } canvas_update_target(canvas, AMITK_CANVAS_TARGET_ACTION_SHOW, center, corner); g_signal_emit(G_OBJECT (canvas), canvas_signals[VIEW_CHANGING], 0, ¢er, corner); break; case CANVAS_EVENT_PRESS_DRAW_POINT: case CANVAS_EVENT_PRESS_DRAW_LARGE_POINT: case CANVAS_EVENT_PRESS_ERASE_POINT: case CANVAS_EVENT_PRESS_ERASE_LARGE_POINT: grab_on = TRUE; canvas_item = GNOME_CANVAS_ITEM(widget); gnome_canvas_item_grab(canvas_item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ui_common_cursor[UI_CURSOR_ROI_DRAW], event->button.time); /* and fall through */ case CANVAS_EVENT_MOTION_DRAW_POINT: case CANVAS_EVENT_MOTION_DRAW_LARGE_POINT: case CANVAS_EVENT_MOTION_ERASE_POINT: case CANVAS_EVENT_MOTION_ERASE_LARGE_POINT: temp_point[0] = amitk_space_b2s(AMITK_SPACE(drawing_object), base_point); POINT_TO_VOXEL(temp_point[0], AMITK_ROI_VOXEL_SIZE(drawing_object), 0, 0, temp_voxel); amitk_roi_manipulate_area(AMITK_ROI(drawing_object), ((canvas_event_type != CANVAS_EVENT_MOTION_DRAW_POINT) && (canvas_event_type != CANVAS_EVENT_PRESS_DRAW_POINT) && (canvas_event_type != CANVAS_EVENT_MOTION_DRAW_LARGE_POINT) && (canvas_event_type != CANVAS_EVENT_PRESS_DRAW_LARGE_POINT)), temp_voxel, ((canvas_event_type == CANVAS_EVENT_MOTION_DRAW_LARGE_POINT) || (canvas_event_type == CANVAS_EVENT_PRESS_DRAW_LARGE_POINT) || (canvas_event_type == CANVAS_EVENT_MOTION_ERASE_LARGE_POINT) || (canvas_event_type == CANVAS_EVENT_PRESS_ERASE_LARGE_POINT)) ? 2 : 0); g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); break; case CANVAS_EVENT_MOTION_CHANGE_ISOCONTOUR: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); break; case CANVAS_EVENT_MOTION_NEW_ROI: switch(AMITK_ROI_TYPE(object)) { case AMITK_ROI_TYPE_BOX: case AMITK_ROI_TYPE_ELLIPSOID: case AMITK_ROI_TYPE_CYLINDER: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_NEW_ROI, &base_point, 0.0); if (event->motion.state & GDK_BUTTON1_MASK) { /* edge-to-edge button 1 */ temp_cpoint[0] = initial_cpoint; temp_cpoint[1] = canvas_cpoint; } else { /* center-out other buttons*/ diff_cpoint = canvas_point_diff(initial_cpoint, canvas_cpoint); temp_cpoint[0] = canvas_point_sub(initial_cpoint, diff_cpoint); temp_cpoint[1] = canvas_point_add(initial_cpoint, diff_cpoint); } gnome_canvas_item_set(canvas_item, "x1", temp_cpoint[0].x, "y1", temp_cpoint[0].y, "x2", temp_cpoint[1].x, "y2", temp_cpoint[1].y,NULL); break; case AMITK_ROI_TYPE_ISOCONTOUR_2D: case AMITK_ROI_TYPE_ISOCONTOUR_3D: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_NEW_ISOCONTOUR_ROI, &base_point, 0.0); break; case AMITK_ROI_TYPE_FREEHAND_2D: case AMITK_ROI_TYPE_FREEHAND_3D: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_NEW_FREEHAND_ROI, &base_point, 0.0); break; default: g_error("unexpected case in %s at line %d, roi_type %d", __FILE__, __LINE__, AMITK_ROI_TYPE(object)); break; } break; case CANVAS_EVENT_MOTION_SHIFT_OBJECT: if (AMITK_IS_DATA_SET(object)) { diff_point = point_sub(base_point, initial_base_point); g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_SHIFT, &diff_point, theta); } else g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); diff_cpoint = canvas_point_sub(canvas_cpoint, previous_cpoint); gnome_canvas_item_i2w(canvas_item->parent, &diff_cpoint.x, &diff_cpoint.y); gnome_canvas_item_move(canvas_item,diff_cpoint.x,diff_cpoint.y); previous_cpoint = canvas_cpoint; break; case CANVAS_EVENT_MOTION_ROTATE_OBJECT: { /* rotate button Pressed, we're rotating the object */ /* note, I'd like to use the function "gnome_canvas_item_rotate" but this isn't defined in the current version of gnome.... so I'll have to do a whole bunch of shit*/ double affine[6]; AmitkCanvasPoint item_center; AmitkPoint center; if (AMITK_IS_VOLUME(object)) center = amitk_volume_get_center(AMITK_VOLUME(object)); else /* STUDY */ center = canvas->center; center = amitk_space_b2s(AMITK_SPACE(canvas->volume), center); temp_point[0] = point_sub(initial_canvas_point,center); temp_point[1] = point_sub(canvas_point,center); theta = acos(point_dot_product(temp_point[0],temp_point[1])/(point_mag(temp_point[0]) * point_mag(temp_point[1]))); /* correct for the fact that acos is always positive by using the cross product */ if ((temp_point[0].x*temp_point[1].y-temp_point[0].y*temp_point[1].x) < 0.0) theta = -theta; /* figure out what the center of the roi is in canvas_item coords */ /* compensate for x's origin being top left (ours is bottom left) */ item_center = p_2_cp(canvas, center); affine[0] = cos(-theta); /* neg cause GDK has Y axis going down, not up */ affine[1] = sin(-theta); affine[2] = -affine[1]; affine[3] = affine[0]; affine[4] = (1.0-affine[0])*item_center.x+affine[1]*item_center.y; affine[5] = (1.0-affine[3])*item_center.y+affine[2]*item_center.x; gnome_canvas_item_affine_absolute(canvas_item,affine); } g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_THETA, &base_point, theta*180.0/M_PI); break; case CANVAS_EVENT_MOTION_RESIZE_ROI: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); { /* RESIZE button Pressed, we're scaling the object */ /* note, I'd like to use the function "gnome_canvas_item_scale" but this isn't defined in the current version of gnome.... so I'll have to do a whole bunch of shit*/ /* also, this "zoom" strategy doesn't always work if the object is not aligned with the view.... oh well... good enough for now... */ double affine[6]; AmitkCanvasPoint item_center; amide_real_t jump_limit, max, temp, dot; double cos_r, sin_r, rot; AmitkAxis i_axis, axis[AMITK_AXIS_NUM]; AmitkCanvasPoint radius_cpoint; AmitkPoint center, radius, canvas_zoom; /* calculating the radius and center wrt the canvas */ radius_point = point_cmult(0.5,AMITK_VOLUME_CORNER(object)); radius = amitk_space_s2s_dim(AMITK_SPACE(object), AMITK_SPACE(canvas->volume), radius_point); center = amitk_space_b2s(AMITK_SPACE(canvas->volume),amitk_volume_get_center(AMITK_VOLUME(object))); temp_point[0] = point_diff(initial_canvas_point, center); temp_point[1] = point_diff(canvas_point,center); radius_cpoint.x = radius_point.x; radius_cpoint.y = radius_point.y; jump_limit = canvas_point_mag(radius_cpoint)/3.0; /* figure out the zoom we're specifying via the canvas */ if (temp_point[0].x < jump_limit) /* prevent jumping */ canvas_zoom.x = (radius.x+temp_point[1].x)/(radius.x+temp_point[0].x); else canvas_zoom.x = temp_point[1].x/temp_point[0].x; if (temp_point[0].y < jump_limit) /* prevent jumping */ canvas_zoom.y = (radius.x+temp_point[1].y)/(radius.x+temp_point[0].y); else canvas_zoom.y = temp_point[1].y/temp_point[0].y; canvas_zoom.z = 1.0; /* translate the canvas zoom into the ROI's coordinate frame */ temp_point[0].x = temp_point[0].y = temp_point[0].z = 1.0; temp_point[0] = amitk_space_s2s_dim(AMITK_SPACE(canvas->volume), AMITK_SPACE(object), temp_point[0]); zoom = amitk_space_s2s_dim(AMITK_SPACE(canvas->volume), AMITK_SPACE(object), canvas_zoom); zoom = point_div(zoom, temp_point[0]); /* first, figure out how much the roi is rotated in the plane of the canvas */ /* figure out which axis in the ROI is closest to the view's x axis */ max = 0.0; axis[AMITK_AXIS_X]=AMITK_AXIS_X; temp_point[0] = amitk_axes_get_orthogonal_axis(AMITK_SPACE_AXES(canvas->volume), canvas->view, AMITK_STUDY_CANVAS_LAYOUT(canvas->study), AMITK_AXIS_X); for (i_axis=0;i_axis max) { max=temp; axis[AMITK_AXIS_X]=i_axis; } } /* and y axis */ max = 0.0; axis[AMITK_AXIS_Y]= (axis[AMITK_AXIS_X]+1 < AMITK_AXIS_NUM) ? axis[AMITK_AXIS_X]+1 : AMITK_AXIS_X; temp_point[0] = amitk_axes_get_orthogonal_axis(AMITK_SPACE_AXES(canvas->volume), canvas->view, AMITK_STUDY_CANVAS_LAYOUT(canvas->study), AMITK_AXIS_Y); for (i_axis=0;i_axis max) { if (i_axis != axis[AMITK_AXIS_X]) { max=temp; axis[AMITK_AXIS_Y]=i_axis; } } } i_axis = AMITK_AXIS_Z; for (i_axis=0;i_axisvolume), temp_point[0]); temp_point[0].z = 0.0; temp_point[1] = amitk_axes_get_orthogonal_axis(AMITK_SPACE_AXES(canvas->volume), canvas->view, AMITK_STUDY_CANVAS_LAYOUT(canvas->study), i_axis); temp_point[1] = amitk_space_b2s(AMITK_SPACE(canvas->volume), temp_point[1]); temp_point[1].z = 0.0; /* and get the angle the projection makes to the x axis */ dot = point_dot_product(temp_point[0],temp_point[1])/(point_mag(temp_point[0]) * point_mag(temp_point[1])); /* correct for the fact that acos is always positive by using the cross product */ if ((temp_point[0].x*temp_point[1].y-temp_point[0].y*temp_point[1].x) > 0.0) temp = acos(dot); else temp = -acos(dot); if (isnan(temp)) temp=0; rot += temp; } cos_r = cos(rot); /* precompute cos and sin of rot */ sin_r = sin(rot); /* figure out what the center of the roi is in gnome_canvas_item coords */ /* compensate for X's origin being top left (not bottom left) */ item_center = p_2_cp(canvas, center); /* do a wild ass affine matrix so that we can scale while preserving angles */ affine[0] = canvas_zoom.x * cos_r * cos_r + canvas_zoom.y * sin_r * sin_r; affine[1] = (canvas_zoom.x-canvas_zoom.y)* cos_r * sin_r; affine[2] = affine[1]; affine[3] = canvas_zoom.x * sin_r * sin_r + canvas_zoom.y * cos_r * cos_r; affine[4] = item_center.x - item_center.x*canvas_zoom.x*cos_r*cos_r - item_center.x*canvas_zoom.y*sin_r*sin_r + (canvas_zoom.y-canvas_zoom.x)*item_center.y*cos_r*sin_r; affine[5] = item_center.y - item_center.y*canvas_zoom.y*cos_r*cos_r - item_center.y*canvas_zoom.x*sin_r*sin_r + (canvas_zoom.y-canvas_zoom.x)*item_center.x*cos_r*sin_r; gnome_canvas_item_affine_absolute(canvas_item,affine); } break; case CANVAS_EVENT_RELEASE_MOVE_VIEW: case CANVAS_EVENT_RELEASE_MINIMIZE_VIEW: case CANVAS_EVENT_RELEASE_RESIZE_VIEW: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_UPDATE_LOCATION, &base_point, voxel_value); grab_on = FALSE; gnome_canvas_item_ungrab(canvas->image, event->button.time); /* queue target cross redraw */ amitk_canvas_update_target(canvas, AMITK_CANVAS_TARGET_ACTION_HIDE, base_point, 0.0); if (canvas_event_type == CANVAS_EVENT_RELEASE_RESIZE_VIEW) center = initial_base_point; else center = base_point; if (canvas_event_type == CANVAS_EVENT_RELEASE_MINIMIZE_VIEW) corner = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(canvas->study)); else if (canvas_event_type == CANVAS_EVENT_RELEASE_RESIZE_VIEW) corner = point_max_dim(point_diff(base_point, initial_base_point)); else corner = AMITK_VOLUME_Z_CORNER(canvas->volume); g_signal_emit(G_OBJECT (canvas), canvas_signals[VIEW_CHANGED], 0, ¢er, corner); break; case CANVAS_EVENT_RELEASE_SHIFT_OBJECT: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_SHIFT_OBJECT, &base_point, 0.0); break; case CANVAS_EVENT_RELEASE_ROTATE_OBJECT: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_ROTATE_OBJECT, &base_point, 0.0); break; case CANVAS_EVENT_CANCEL_SHIFT_OBJECT: case CANVAS_EVENT_CANCEL_ROTATE_OBJECT: if (AMITK_IS_STUDY(object)) help_info = AMITK_HELP_INFO_CANVAS_STUDY; else /* DATA_SET */ help_info = AMITK_HELP_INFO_CANVAS_DATA_SET; g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0,help_info, &base_point, 0.0); extended_event_type = CANVAS_EVENT_NONE; extended_object = NULL; gtk_object_destroy(GTK_OBJECT(canvas_item)); break; case CANVAS_EVENT_CANCEL_CHANGE_ISOCONTOUR: help_info = AMITK_HELP_INFO_CANVAS_ISOCONTOUR_ROI; g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0,help_info, &base_point, 0.0); extended_event_type = CANVAS_EVENT_NONE; extended_object = NULL; break; case CANVAS_EVENT_ENACT_SHIFT_OBJECT: case CANVAS_EVENT_ENACT_ROTATE_OBJECT: if (AMITK_IS_STUDY(object)) help_info = AMITK_HELP_INFO_CANVAS_STUDY; else /* DATA_SET */ help_info = AMITK_HELP_INFO_CANVAS_DATA_SET; g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0,help_info, &base_point, 0.0); gtk_object_destroy(GTK_OBJECT(canvas_item)); extended_event_type = CANVAS_EVENT_NONE; extended_object = NULL; if (canvas_event_type == CANVAS_EVENT_ENACT_SHIFT_OBJECT) { /* shift active data set */ amitk_space_shift_offset(AMITK_SPACE(canvas->active_object), point_sub(base_point, initial_base_point)); } else {/* rotate active data set*/ if (canvas->view == AMITK_VIEW_SAGITTAL) theta = -theta; /* sagittal is left-handed */ if (AMITK_IS_VOLUME(object)) center = amitk_volume_get_center(AMITK_VOLUME(canvas->active_object)); else center = canvas->center; amitk_space_rotate_on_vector(AMITK_SPACE(canvas->active_object), amitk_space_get_axis(AMITK_SPACE(canvas->volume), AMITK_AXIS_Z), theta, center); } break; case CANVAS_EVENT_ENACT_CHANGE_ISOCONTOUR: help_info = AMITK_HELP_INFO_CANVAS_ISOCONTOUR_ROI; g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0,help_info, &base_point, 0.0); extended_event_type = CANVAS_EVENT_NONE; extended_object = NULL; if (active_slice == NULL) { g_warning(_("The active data set is not visible")); return FALSE; } canvas_create_isocontour_roi(canvas, AMITK_ROI(object), base_point, active_slice); break; case CANVAS_EVENT_RELEASE_NEW_ROI: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_DATA_SET, &base_point, 0.0); grab_on = FALSE; switch(AMITK_ROI_TYPE(object)) { case AMITK_ROI_TYPE_CYLINDER: case AMITK_ROI_TYPE_BOX: case AMITK_ROI_TYPE_ELLIPSOID: gnome_canvas_item_ungrab(canvas_item, event->button.time); diff_point = point_diff(initial_canvas_point, canvas_point); diff_point.z = canvas_check_z_dimension(canvas, AMITK_VOLUME_Z_CORNER(canvas->volume)); diff_point.z /= 2; gtk_object_destroy(GTK_OBJECT(canvas_item)); /* get rid of the roi drawn on the canvas */ if (event->button.button == 1) { /* edge to edge */ temp_point[0].x = MIN(initial_canvas_point.x, canvas_point.x); temp_point[0].y = MIN(initial_canvas_point.y, canvas_point.y); temp_point[0].z = canvas_point.z - diff_point.z; temp_point[1].x = MAX(initial_canvas_point.x, canvas_point.x); temp_point[1].y = MAX(initial_canvas_point.y, canvas_point.y); temp_point[1].z = canvas_point.z + diff_point.z; } else { /* center to center */ temp_point[0] = point_sub(initial_canvas_point, diff_point); temp_point[1] = point_add(initial_canvas_point, diff_point); } /* we'll save the coord frame and offset of the roi */ amitk_space_copy_in_place(AMITK_SPACE(object), AMITK_SPACE(canvas->volume)); amitk_space_set_offset(AMITK_SPACE(object), amitk_space_s2b(AMITK_SPACE(canvas->volume), temp_point[0])); /* and set the far corner of the roi */ amitk_volume_set_corner(AMITK_VOLUME(object), point_abs(amitk_space_s2s(AMITK_SPACE(canvas->volume), AMITK_SPACE(object), temp_point[1]))); break; case AMITK_ROI_TYPE_ISOCONTOUR_2D: case AMITK_ROI_TYPE_ISOCONTOUR_3D: if (active_slice == NULL) { g_warning(_("The active data set is not visible")); return FALSE; } canvas_create_isocontour_roi(canvas, AMITK_ROI(object), base_point, active_slice); break; case AMITK_ROI_TYPE_FREEHAND_2D: case AMITK_ROI_TYPE_FREEHAND_3D: if (active_slice == NULL) { g_warning(_("The active data set is not visible")); return FALSE; } if (canvas_create_freehand_roi(canvas, AMITK_ROI(object), base_point, active_slice)) { enter_drawing_mode = TRUE; drawing_object = object; } break; default: g_error("unexpected case in %s at line %d, roi_type %d", __FILE__, __LINE__, AMITK_ROI_TYPE(object)); break; } canvas_add_object_update(canvas, AMITK_OBJECT(object)); /* add this object for updating */ break; case CANVAS_EVENT_RELEASE_SHIFT_OBJECT_IMMEDIATE: gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(widget), event->button.time); grab_on = FALSE; shift = point_sub(base_point, initial_base_point); /* ------------- apply any shift done -------------- */ if (!POINT_EQUAL(shift, zero_point)) { if (AMITK_IS_FIDUCIAL_MARK(object)) { amitk_fiducial_mark_set(AMITK_FIDUCIAL_MARK(object), point_add(shift, AMITK_FIDUCIAL_MARK_GET(object))); center = AMITK_FIDUCIAL_MARK_GET(object); } else if (AMITK_IS_ROI(object)) { amitk_space_shift_offset(AMITK_SPACE(object), shift); center = amitk_volume_get_center(AMITK_VOLUME(object)); } else if (AMITK_IS_LINE_PROFILE(object)) { center = point_add(shift, canvas->center); /* make sure it stays in bounds */ center = amitk_volume_place_in_bounds(canvas->volume, center); } else g_return_val_if_reached(FALSE); g_signal_emit(G_OBJECT (canvas), canvas_signals[VIEW_CHANGED], 0, ¢er, AMITK_VOLUME_Z_CORNER(canvas->volume)); } break; case CANVAS_EVENT_RELEASE_ROTATE_OBJECT_IMMEDIATE: gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(widget), event->button.time); grab_on = FALSE; if (canvas->view == AMITK_VIEW_SAGITTAL) theta = -theta; /* sagittal is a left-handed coord frame */ /* now rotate the roi coordinate space axis */ if (AMITK_IS_ROI(object)) { amitk_space_rotate_on_vector(AMITK_SPACE(object), amitk_space_get_axis(AMITK_SPACE(canvas->volume), AMITK_AXIS_Z), theta, amitk_volume_get_center(AMITK_VOLUME(object))); } else if (AMITK_IS_LINE_PROFILE(object)) { amitk_line_profile_set_angle(AMITK_LINE_PROFILE(object), theta+AMITK_LINE_PROFILE_ANGLE(object)); } else g_return_val_if_reached(FALSE); /* shouldn't get here */ break; case CANVAS_EVENT_RELEASE_RESIZE_ROI: gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(widget), event->button.time); grab_on = FALSE; radius_point = point_cmult(0.5,AMITK_VOLUME_CORNER(object)); temp_point[0] = point_mult(zoom, radius_point); /* new radius */ temp_point[1] = amitk_space_b2s(AMITK_SPACE(object), amitk_volume_get_center(AMITK_VOLUME(object))); temp_point[1] = amitk_space_s2b(AMITK_SPACE(object), point_sub(temp_point[1], temp_point[0])); amitk_space_set_offset(AMITK_SPACE(object), temp_point[1]); /* and the new upper right corner is simply twice the radius */ amitk_volume_set_corner(AMITK_VOLUME(object), point_cmult(2.0, temp_point[0])); break; case CANVAS_EVENT_RELEASE_DRAW_POINT: case CANVAS_EVENT_RELEASE_DRAW_LARGE_POINT: case CANVAS_EVENT_RELEASE_ERASE_POINT: case CANVAS_EVENT_RELEASE_ERASE_LARGE_POINT: gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(widget), event->button.time); grab_on = FALSE; break; case CANVAS_EVENT_RELEASE_CHANGE_ISOCONTOUR: g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_CANVAS_CHANGE_ISOCONTOUR, &base_point, 0.0); break; case CANVAS_EVENT_SCROLL_UP: case CANVAS_EVENT_SCROLL_DOWN: /* just pretend this event is like the user pressed the scrollbar */ if (canvas_event_type == CANVAS_EVENT_SCROLL_UP) g_signal_emit_by_name(G_OBJECT(canvas->scrollbar), "move_slider", GTK_SCROLL_PAGE_BACKWARD, canvas); else /* scroll down */ g_signal_emit_by_name(G_OBJECT(canvas->scrollbar), "move_slider", GTK_SCROLL_PAGE_FORWARD, canvas); break; case CANVAS_EVENT_NONE: break; default: g_warning("unexpected case in %s at line %d, event %d", __FILE__, __LINE__, canvas_event_type); break; } return FALSE; } /* function called indicating the plane adjustment has changed */ static void canvas_scrollbar_adjustment_cb(GtkObject * adjustment, gpointer data) { AmitkCanvas * canvas = data; AmitkPoint canvas_center; g_return_if_fail(AMITK_IS_CANVAS(canvas)); canvas_center = amitk_space_b2s(AMITK_SPACE(canvas->volume), canvas->center); canvas_center.z = GTK_ADJUSTMENT(adjustment)->value; canvas->center = amitk_space_s2b(AMITK_SPACE(canvas->volume), canvas_center); canvas_add_update(canvas, UPDATE_ALL); g_signal_emit(G_OBJECT (canvas), canvas_signals[VIEW_CHANGED], 0, &(canvas->center), AMITK_VOLUME_Z_CORNER(canvas->volume)); g_signal_emit(G_OBJECT (canvas), canvas_signals[HELP_EVENT], 0, AMITK_HELP_INFO_BLANK, &(canvas->center), 0.0); return; } static gboolean canvas_recalc_corners(AmitkCanvas * canvas) { GList * volumes; gboolean changed; /* sanity checks */ if (canvas->study == NULL) return FALSE; /* what volumes are we looking at - ignore ROI's */ if (AMITK_STUDY_CANVAS_MAINTAIN_SIZE(canvas->study)) { volumes = amitk_object_get_children_of_type(AMITK_OBJECT(canvas->study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); } else { volumes = amitk_object_get_selected_children_of_type(AMITK_OBJECT(canvas->study), AMITK_OBJECT_TYPE_DATA_SET, canvas->view_mode, TRUE); } changed = amitk_volumes_calc_display_volume(volumes, AMITK_SPACE(canvas->volume), canvas->center, AMITK_VOLUME_Z_CORNER(canvas->volume), AMITK_STUDY_FOV(canvas->study), canvas->volume); amitk_objects_unref(volumes); return changed; } /* function to update the adjustment settings for the scrollbar */ static void canvas_update_scrollbar(AmitkCanvas * canvas, AmitkPoint center, amide_real_t thickness) { AmitkCorners view_corner; amide_real_t upper, lower; amide_real_t min_voxel_size; AmitkPoint zp_start; GList * volumes; GList * data_sets; /* sanity checks */ if (canvas->study == NULL) return; /* make valgrind happy */ view_corner[0]=zero_point; view_corner[1]=zero_point; volumes = amitk_object_get_selected_children_of_type(AMITK_OBJECT(canvas->study), AMITK_OBJECT_TYPE_VOLUME, canvas->view_mode, TRUE); amitk_volumes_get_enclosing_corners(volumes, AMITK_SPACE(canvas->volume), view_corner); amitk_objects_unref(volumes); data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(canvas->study), AMITK_OBJECT_TYPE_DATA_SET, canvas->view_mode, TRUE); min_voxel_size = amitk_data_sets_get_min_voxel_size(data_sets); amitk_objects_unref(data_sets); upper = view_corner[1].z; lower = view_corner[0].z; /* translate the view center point so that the z coordinate corresponds to depth in this view */ zp_start = amitk_space_b2s(AMITK_SPACE(canvas->volume), center); /* make sure our view center makes sense */ if (zp_start.z < lower) { if (zp_start.z < lower-thickness) zp_start.z = (upper-lower)/2.0+lower; else zp_start.z = lower; } else if (zp_start.z > upper) { if (zp_start.z > lower+thickness) zp_start.z = (upper-lower)/2.0+lower; else zp_start.z = upper; } GTK_ADJUSTMENT(canvas->scrollbar_adjustment)->upper = upper; GTK_ADJUSTMENT(canvas->scrollbar_adjustment)->lower = lower; GTK_ADJUSTMENT(canvas->scrollbar_adjustment)->step_increment = min_voxel_size; GTK_ADJUSTMENT(canvas->scrollbar_adjustment)->page_increment = (thickness/2.0 < min_voxel_size) ? min_voxel_size : thickness/2.0; GTK_ADJUSTMENT(canvas->scrollbar_adjustment)->page_size = 0; GTK_ADJUSTMENT(canvas->scrollbar_adjustment)->value = zp_start.z; /* allright, we need to update widgets connected to the adjustment without triggering our callback */ g_signal_handlers_block_by_func(G_OBJECT(canvas->scrollbar_adjustment), G_CALLBACK(canvas_scrollbar_adjustment_cb), canvas); gtk_adjustment_changed(GTK_ADJUSTMENT(canvas->scrollbar_adjustment)); g_signal_handlers_unblock_by_func(G_OBJECT(canvas->scrollbar_adjustment), G_CALLBACK(canvas_scrollbar_adjustment_cb), canvas); return; } /* function to update the target cross on the canvas */ static void canvas_update_target(AmitkCanvas * canvas, AmitkCanvasTargetAction action, AmitkPoint center, amide_real_t thickness) { GnomeCanvasPoints * points[8]; AmitkCanvasPoint point0, point1; AmitkPoint start, end; gint i; gdouble separation; rgba_t color; if (canvas->type == AMITK_CANVAS_TYPE_FLY_THROUGH) return; if ((canvas->slices == NULL) || ((action == AMITK_CANVAS_TARGET_ACTION_HIDE) && (!AMITK_STUDY_CANVAS_TARGET(canvas->study)))) { for (i=0; i < 8 ; i++) if (canvas->target[i] != NULL) gnome_canvas_item_hide(canvas->target[i]); return; } if (((action == AMITK_CANVAS_TARGET_ACTION_HIDE) && AMITK_STUDY_CANVAS_TARGET(canvas->study)) || (action == AMITK_CANVAS_TARGET_ACTION_LEAVE)) { thickness = AMITK_VOLUME_Z_CORNER(canvas->volume); center = canvas->center; } color = amitk_color_table_outline_color(canvas_get_color_table(canvas), FALSE); start = end = amitk_space_b2s(AMITK_SPACE(canvas->volume), center); start.x -= thickness/2.0; start.y -= thickness/2.0; end.x += thickness/2.0; end.y += thickness/2.0; /* get the canvas locations corresponding to the start and end coordinates */ point0 = p_2_cp(canvas, start); point1 = p_2_cp(canvas, end); separation = (point1.x - point0.x)/2.0; if (separation < AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(canvas->study)) separation = AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(canvas->study)-separation; else separation = 0.0; points[0] = gnome_canvas_points_new(2); points[0]->coords[0] = (gdouble) canvas->border_width; points[0]->coords[1] = point1.y; points[0]->coords[2] = ((point0.x-separation) > canvas->border_width) ? (point0.x-separation) : canvas->border_width; points[0]->coords[3] = point1.y; points[1] = gnome_canvas_points_new(2); points[1]->coords[0] = point0.x; points[1]->coords[1] = ((point1.y-separation) > canvas->border_width) ? (point1.y-separation) : canvas->border_width; points[1]->coords[2] = point0.x; points[1]->coords[3] = (gdouble) canvas->border_width; points[2] = gnome_canvas_points_new(2); points[2]->coords[0] = point1.x; points[2]->coords[1] = (gdouble) canvas->border_width; points[2]->coords[2] = point1.x; points[2]->coords[3] = ((point1.y-separation) > canvas->border_width) ? (point1.y-separation) : canvas->border_width; points[3] = gnome_canvas_points_new(2); points[3]->coords[0] = ((point1.x+separation) < canvas->pixbuf_width+canvas->border_width) ? (point1.x+separation) : canvas->pixbuf_width+canvas->border_width; points[3]->coords[1] = point1.y; points[3]->coords[2] = (gdouble) (canvas->pixbuf_width+canvas->border_width); points[3]->coords[3] = point1.y; points[4] = gnome_canvas_points_new(2); points[4]->coords[0] = (gdouble) canvas->border_width; points[4]->coords[1] = point0.y; points[4]->coords[2] = ((point0.x-separation) > canvas->border_width) ? (point0.x-separation) : canvas->border_width; points[4]->coords[3] = point0.y; points[5] = gnome_canvas_points_new(2); points[5]->coords[0] = point0.x; points[5]->coords[1] = ((point0.y+separation) < canvas->pixbuf_height+canvas->border_width) ? (point0.y+separation) : canvas->pixbuf_height+canvas->border_width; points[5]->coords[2] = point0.x; points[5]->coords[3] = (gdouble) (canvas->pixbuf_height+canvas->border_width); points[6] = gnome_canvas_points_new(2); points[6]->coords[0] = point1.x; points[6]->coords[1] = (gdouble) (canvas->pixbuf_height+canvas->border_width); points[6]->coords[2] = point1.x; points[6]->coords[3] = ((point0.y+separation) < canvas->pixbuf_height+canvas->border_width) ? (point0.y+separation) : canvas->pixbuf_height+canvas->border_width; points[7] = gnome_canvas_points_new(2); points[7]->coords[0] = ((point1.x+separation) < canvas->pixbuf_width+canvas->border_width) ? (point1.x+separation) : canvas->pixbuf_width+canvas->border_width; points[7]->coords[1] = point0.y; points[7]->coords[2] = (gdouble) (canvas->pixbuf_width+canvas->border_width); points[7]->coords[3] = point0.y; for (i=0; i<8; i++) { if (canvas->target[i]==NULL) { canvas->target[i] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_line_get_type(), "points", points[i], "fill_color_rgba", amitk_color_table_rgba_to_uint32(color), "width_pixels", 1, NULL); g_signal_connect(G_OBJECT(canvas->target[i]), "event", G_CALLBACK(canvas_event_cb), canvas); } else if (action == AMITK_CANVAS_TARGET_ACTION_SHOW) gnome_canvas_item_set(canvas->target[i],"points",points[i], "fill_color_rgba", amitk_color_table_rgba_to_uint32(color), "width_pixels", 1, NULL); else gnome_canvas_item_set(canvas->target[i],"points",points[i], "fill_color_rgba", amitk_color_table_rgba_to_uint32(color), NULL); gnome_canvas_item_show(canvas->target[i]); gnome_canvas_points_unref(points[i]); } return; } /* function to update the arrows on the canvas */ static void canvas_update_arrows(AmitkCanvas * canvas) { GnomeCanvasPoints * points[4]; AmitkCanvasPoint point0, point1; AmitkPoint start, end; gint i; amide_real_t thickness; if (canvas->type == AMITK_CANVAS_TYPE_FLY_THROUGH) return; if (canvas->slices == NULL) { for (i=0; i<4; i++) if (canvas->arrows[i] != NULL) gnome_canvas_item_hide(canvas->arrows[i]); return; } /* figure out the dimensions of the view "box" */ thickness= AMITK_VOLUME_Z_CORNER(canvas->volume); start = amitk_space_b2s(AMITK_SPACE(canvas->volume), canvas->center); start.x -= thickness/2.0; start.y -= thickness/2.0; end = amitk_space_b2s(AMITK_SPACE(canvas->volume), canvas->center); end.x += thickness/2.0; end.y += thickness/2.0; /* get the canvas locations corresponding to the start and end coordinates */ point0 = p_2_cp(canvas, start); point1 = p_2_cp(canvas, end); /* notes: 1) even coords are the x coordinate, odd coords are the y 2) drawing coordinate frame starts from the top left 3) X's origin is top left, ours is bottom left */ /* left arrow */ points[0] = gnome_canvas_points_new(4); points[0]->coords[0] = DEFAULT_CANVAS_BORDER_WIDTH-DEFAULT_CANVAS_TRIANGLE_SEPARATION; points[0]->coords[1] = point1.y; points[0]->coords[2] = points[0]->coords[0]; points[0]->coords[3] = point0.y; points[0]->coords[4] = DEFAULT_CANVAS_TRIANGLE_BORDER; points[0]->coords[5] = point0.y + DEFAULT_CANVAS_TRIANGLE_WIDTH/2.0; points[0]->coords[6] = DEFAULT_CANVAS_TRIANGLE_BORDER; points[0]->coords[7] = point1.y - DEFAULT_CANVAS_TRIANGLE_WIDTH/2.0; /* top arrow */ points[1] = gnome_canvas_points_new(4); points[1]->coords[0] = point0.x; points[1]->coords[1] = DEFAULT_CANVAS_BORDER_WIDTH-DEFAULT_CANVAS_TRIANGLE_SEPARATION; points[1]->coords[2] = point1.x; points[1]->coords[3] = points[1]->coords[1]; points[1]->coords[4] = point1.x + DEFAULT_CANVAS_TRIANGLE_WIDTH/2.0; points[1]->coords[5] = DEFAULT_CANVAS_TRIANGLE_BORDER; points[1]->coords[6] = point0.x - DEFAULT_CANVAS_TRIANGLE_WIDTH/2.0; points[1]->coords[7] = DEFAULT_CANVAS_TRIANGLE_BORDER; /* right arrow */ points[2] = gnome_canvas_points_new(4); points[2]->coords[0] = DEFAULT_CANVAS_BORDER_WIDTH + DEFAULT_CANVAS_TRIANGLE_SEPARATION + canvas->pixbuf_width; points[2]->coords[1] = point1.y; points[2]->coords[2] = points[2]->coords[0]; points[2]->coords[3] = point0.y; points[2]->coords[4] = DEFAULT_CANVAS_BORDER_WIDTH + DEFAULT_CANVAS_TRIANGLE_HEIGHT + DEFAULT_CANVAS_TRIANGLE_SEPARATION + canvas->pixbuf_width; points[2]->coords[5] = point0.y + DEFAULT_CANVAS_TRIANGLE_WIDTH/2; points[2]->coords[6] = points[2]->coords[4]; points[2]->coords[7] = point1.y - DEFAULT_CANVAS_TRIANGLE_WIDTH/2; /* bottom arrow */ points[3] = gnome_canvas_points_new(4); points[3]->coords[0] = point0.x; points[3]->coords[1] = DEFAULT_CANVAS_BORDER_WIDTH + DEFAULT_CANVAS_TRIANGLE_SEPARATION + canvas->pixbuf_height; points[3]->coords[2] = point1.x; points[3]->coords[3] = points[3]->coords[1]; points[3]->coords[4] = point1.x + DEFAULT_CANVAS_TRIANGLE_WIDTH/2; points[3]->coords[5] = DEFAULT_CANVAS_BORDER_WIDTH+DEFAULT_CANVAS_TRIANGLE_HEIGHT + DEFAULT_CANVAS_TRIANGLE_SEPARATION + canvas->pixbuf_height; points[3]->coords[6] = point0.x - DEFAULT_CANVAS_TRIANGLE_WIDTH/2; points[3]->coords[7] = points[3]->coords[5]; for (i=0; i<4; i++) { if (canvas->arrows[i] != NULL ) gnome_canvas_item_set(canvas->arrows[i],"points",points[i], NULL); else canvas->arrows[i] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_polygon_get_type(), "points", points[i],"fill_color", "white", "outline_color", "black", "width_pixels", 2, NULL); gnome_canvas_item_show(canvas->arrows[i]); gnome_canvas_points_unref(points[i]); } return; } /* function to update the line profile on the canvas */ static void canvas_update_line_profile(AmitkCanvas * canvas) { GnomeCanvasPoints * points; AmitkCanvasPoint point0, point1; AmitkPoint start, end; amide_real_t temp; amide_real_t profile_angle; gint roi_width; #ifndef AMIDE_LIBGNOMECANVAS_AA GdkLineStyle line_style; #endif guint32 fill_color_rgba; rgba_t outline_color; AmitkLineProfile * line_profile; gdouble affine[6]; AmitkPoint initial; if (canvas->type == AMITK_CANVAS_TYPE_FLY_THROUGH) return; line_profile = AMITK_STUDY_LINE_PROFILE(canvas->study); /* figure out if we need to hide it */ if ((canvas->view != AMITK_LINE_PROFILE_VIEW(line_profile)) || (!AMITK_LINE_PROFILE_VISIBLE(line_profile)) || !amitk_volume_point_in_bounds(canvas->volume, canvas->center)) { /* the !amitk_volume_point_in_bounds gets hit when there's no data set on the given canvas.. only happens if multiple views are up at the same time */ if (canvas->line_profile_item != NULL) gnome_canvas_item_hide(canvas->line_profile_item); return; } initial = amitk_space_b2s(AMITK_SPACE(canvas->volume), canvas->center); profile_angle = AMITK_LINE_PROFILE_ANGLE(line_profile); if (canvas->view == AMITK_VIEW_SAGITTAL) profile_angle = -profile_angle; /* sagittal is a left-handed coord frame */ /* z location's easy */ start.z = end.z = initial.z; /* x locations */ if (REAL_EQUAL(profile_angle, M_PI/2.0)) { /* 90 degrees */ start.x = end.x = initial.x; } else if (REAL_EQUAL(profile_angle, 0) || REAL_EQUAL(profile_angle, M_PI)) { /* 0, 180 degrees */ start.x = 0; end.x = AMITK_VOLUME_X_CORNER(canvas->volume); } else { /* everything else */ start.x = initial.x - initial.y/tan(profile_angle); end.x = initial.x + (AMITK_VOLUME_Y_CORNER(canvas->volume)-initial.y)/tan(profile_angle); } if (start.x < 0.0) start.x = 0.0; else if (start.x > AMITK_VOLUME_X_CORNER(canvas->volume)) start.x = AMITK_VOLUME_X_CORNER(canvas->volume); if (end.x < 0.0) end.x = 0.0; else if (end.x > AMITK_VOLUME_X_CORNER(canvas->volume)) end.x = AMITK_VOLUME_X_CORNER(canvas->volume); if (profile_angle < 0.0) { temp = start.x; start.x = end.x; end.x = temp; } /* y locations */ if (REAL_EQUAL(profile_angle, M_PI/2.0)) { /* 90 degrees */ start.y = 0; end.y = AMITK_VOLUME_Y_CORNER(canvas->volume); } else if (REAL_EQUAL(profile_angle, 0) || REAL_EQUAL(profile_angle, M_PI)) { /* 0, 180 degrees */ start.y = end.y = initial.y; } else { /* everything else */ start.y = initial.y - initial.x*tan(profile_angle); end.y = initial.y + (AMITK_VOLUME_X_CORNER(canvas->volume)-initial.x)*tan(profile_angle); } if (start.y < 0.0) start.y = 0.0; else if (start.y > AMITK_VOLUME_Y_CORNER(canvas->volume)) start.y = AMITK_VOLUME_Y_CORNER(canvas->volume); if (end.y < 0.0) end.y = 0.0; else if (end.y > AMITK_VOLUME_Y_CORNER(canvas->volume)) end.y = AMITK_VOLUME_Y_CORNER(canvas->volume); if (fabs(profile_angle) > M_PI/2) { temp = start.y; start.y = end.y; end.y = temp; } /* get the canvas locations corresponding to the start and end coordinates */ point0 = p_2_cp(canvas, start); point1 = p_2_cp(canvas, end); /* record our start and end */ start = amitk_space_s2b(AMITK_SPACE(canvas->volume), start); amitk_line_profile_set_start_point(AMITK_STUDY_LINE_PROFILE(canvas->study), start); end = amitk_space_s2b(AMITK_SPACE(canvas->volume), end); amitk_line_profile_set_end_point(AMITK_STUDY_LINE_PROFILE(canvas->study), end); /* calculate the line */ points = gnome_canvas_points_new(2); points->coords[0] = point0.x; points->coords[1] = point0.y; points->coords[2] = point1.x; points->coords[3] = point1.y; roi_width = AMITK_STUDY_CANVAS_ROI_WIDTH(canvas->study); #ifndef AMIDE_LIBGNOMECANVAS_AA line_style = AMITK_STUDY_CANVAS_LINE_STYLE(canvas->study); #endif outline_color = amitk_color_table_outline_color(canvas_get_color_table(canvas), TRUE); fill_color_rgba = amitk_color_table_rgba_to_uint32(outline_color); if (canvas->line_profile_item != NULL ) { /* make sure to reset any affine translations we've done */ gnome_canvas_item_i2w_affine(canvas->line_profile_item,affine); affine[0] = affine[3] = 1.0; affine[1] = affine[2] = affine[4] = affine[5] = 0.0; gnome_canvas_item_affine_absolute(canvas->line_profile_item,affine); gnome_canvas_item_set(canvas->line_profile_item, "points",points, "fill_color_rgba", fill_color_rgba, "width_pixels", roi_width, #ifndef AMIDE_LIBGNOMECANVAS_AA "line_style", line_style, #endif NULL); } else { canvas->line_profile_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", fill_color_rgba, "width_pixels", roi_width, "last_arrowhead", TRUE, "arrow_shape_a", (gdouble) 6.0, "arrow_shape_b", (gdouble) 5.0, "arrow_shape_c", (gdouble) 4.0, #ifndef AMIDE_LIBGNOMECANVAS_AA "line_style", line_style, #endif NULL); g_object_set_data(G_OBJECT(canvas->line_profile_item), "object", line_profile); g_signal_connect(G_OBJECT(canvas->line_profile_item), "event", G_CALLBACK(canvas_event_cb), canvas); } gnome_canvas_item_show(canvas->line_profile_item); gnome_canvas_points_unref(points); return; } /* function to update the line profile on the canvas */ static void canvas_update_time_on_image(AmitkCanvas * canvas) { amide_time_t midpt_time; gint hours, minutes, seconds; gchar * time_str; rgba_t color; /* put up the timer */ if (canvas->time_on_image) { midpt_time = AMITK_STUDY_VIEW_START_TIME(canvas->study)+ AMITK_STUDY_VIEW_DURATION(canvas->study)/2.0; hours = floor(midpt_time/3600); midpt_time -= hours*3600; minutes = floor(midpt_time/60); midpt_time -= minutes*60; seconds = midpt_time; time_str = g_strdup_printf("%d:%.2d:%.2d",hours,minutes,seconds); color = amitk_color_table_outline_color(canvas_get_color_table(canvas), FALSE); if (canvas->time_label != NULL) gnome_canvas_item_set(canvas->time_label, "text", time_str, "fill_color_rgba", color, NULL); else canvas->time_label = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_SOUTH_WEST, "text", time_str, "x", 4.0, "y", canvas->pixbuf_height-2.0, "fill_color_rgba", color, "font_desc", amitk_fixed_font_desc, NULL); g_free(time_str); } else { if (canvas->time_label != NULL) { gtk_object_destroy(GTK_OBJECT(canvas->time_label)); canvas->time_label = NULL; } } return; } static void canvas_update_subject_orientation(AmitkCanvas * canvas) { gboolean remove = FALSE; int i; float x[4]; float y[4]; gint anchor[4]; gint which_orientation[4]; if (canvas->active_object == NULL) remove = TRUE; else if (!AMITK_IS_DATA_SET(canvas->active_object)) remove = TRUE; else if (AMITK_DATA_SET_SUBJECT_ORIENTATION(canvas->active_object) == AMITK_SUBJECT_ORIENTATION_UNKNOWN) remove = TRUE; if (remove) { for (i=0; i<4; i++) if (canvas->orientation_label[i] != NULL) gnome_canvas_item_hide(canvas->orientation_label[i]); } else { switch(canvas->view) { case AMITK_VIEW_TRANSVERSE: switch(AMITK_DATA_SET_SUBJECT_ORIENTATION(canvas->active_object)) { case AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST: which_orientation[0] = ANTERIOR; which_orientation[1] = POSTERIOR; which_orientation[2] = RIGHT; which_orientation[3] = LEFT; break; case AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST: which_orientation[0] = ANTERIOR; which_orientation[1] = POSTERIOR; which_orientation[2] = LEFT; which_orientation[3] = RIGHT; break; case AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST: which_orientation[0] = POSTERIOR; which_orientation[1] = ANTERIOR; which_orientation[2] = LEFT; which_orientation[3] = RIGHT; break; case AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST: which_orientation[0] = POSTERIOR; which_orientation[1] = ANTERIOR; which_orientation[2] = RIGHT; which_orientation[3] = LEFT; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST: which_orientation[0] = LEFT; which_orientation[1] = RIGHT; which_orientation[2] = ANTERIOR; which_orientation[3] = POSTERIOR; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST: which_orientation[0] = LEFT; which_orientation[1] = RIGHT; which_orientation[2] = POSTERIOR; which_orientation[3] = ANTERIOR; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST: which_orientation[0] = RIGHT; which_orientation[1] = LEFT; which_orientation[2] = POSTERIOR; which_orientation[3] = ANTERIOR; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST: which_orientation[0] = RIGHT; which_orientation[1] = LEFT; which_orientation[2] = ANTERIOR; which_orientation[3] = POSTERIOR; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } break; case AMITK_VIEW_CORONAL: switch(AMITK_DATA_SET_SUBJECT_ORIENTATION(canvas->active_object)) { case AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = RIGHT; which_orientation[3] = LEFT; break; case AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = LEFT; which_orientation[3] = RIGHT; break; case AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = LEFT; which_orientation[3] = RIGHT; break; case AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = RIGHT; which_orientation[3] = LEFT; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = ANTERIOR; which_orientation[3] = POSTERIOR; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = POSTERIOR; which_orientation[3] = ANTERIOR; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = POSTERIOR; which_orientation[3] = ANTERIOR; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = ANTERIOR; which_orientation[3] = POSTERIOR; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } break; case AMITK_VIEW_SAGITTAL: switch(AMITK_DATA_SET_SUBJECT_ORIENTATION(canvas->active_object)) { case AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = POSTERIOR; which_orientation[3] = ANTERIOR; break; case AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = POSTERIOR; which_orientation[3] = ANTERIOR; break; case AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = ANTERIOR; which_orientation[3] = POSTERIOR; break; case AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = ANTERIOR; which_orientation[3] = POSTERIOR; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = RIGHT; which_orientation[3] = LEFT; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = RIGHT; which_orientation[3] = LEFT; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST: which_orientation[0] = SUPERIOR; which_orientation[1] = INFERIOR; which_orientation[2] = LEFT; which_orientation[3] = RIGHT; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST: which_orientation[0] = INFERIOR; which_orientation[1] = SUPERIOR; which_orientation[2] = LEFT; which_orientation[3] = RIGHT; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } /* text locations */ x[0] = 0; y[0] = canvas->border_width; anchor[0] = GTK_ANCHOR_NORTH_WEST; x[1] = 0; y[1] = canvas->border_width + canvas->pixbuf_height; anchor[1] = GTK_ANCHOR_SOUTH_WEST; x[2] = canvas->border_width; y[2] = 2*canvas->border_width + canvas->pixbuf_height; anchor[2] = GTK_ANCHOR_SOUTH_WEST; x[3] = canvas->border_width+canvas->pixbuf_width; y[3] = 2*canvas->border_width + canvas->pixbuf_height; anchor[3] = GTK_ANCHOR_SOUTH_EAST; for (i=0; i<4; i++) { if (canvas->orientation_label[i] != NULL ) gnome_canvas_item_set(canvas->orientation_label[i],"text", _(orientation_label[which_orientation[i]]), "x", x[i], "y", y[i], NULL); else canvas->orientation_label[i] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_text_get_type(), "anchor", anchor[i], "text", _(orientation_label[which_orientation[i]]), "x", x[i], "y", y[i], "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); gnome_canvas_item_show(canvas->orientation_label[i]); } } return; } static void canvas_update_pixbuf(AmitkCanvas * canvas) { gint old_width, old_height; rgba_t blank_rgba; GtkStyle * widget_style; amide_real_t pixel_dim; AmitkPoint corner; gint width,height; GList * data_sets; AmitkDataSet * active_ds; /* sanity checks */ g_return_if_fail(canvas->study != NULL); old_width = canvas->pixbuf_width; old_height = canvas->pixbuf_height; /* free the previous pixbuf if possible */ if (canvas->pixbuf != NULL) { g_object_unref(canvas->pixbuf); canvas->pixbuf = NULL; } /* compensate for zoom */ pixel_dim = (1/AMITK_STUDY_ZOOM(canvas->study))*AMITK_STUDY_VOXEL_DIM(canvas->study); data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(canvas->study), AMITK_OBJECT_TYPE_DATA_SET, canvas->view_mode, TRUE); if (data_sets == NULL) { /* just use a blank image */ /* figure out what color to use */ widget_style = gtk_widget_get_style(GTK_WIDGET(canvas)); if (widget_style == NULL) { g_warning(_("Canvas has no style?\n")); widget_style = gtk_style_new(); } blank_rgba.r = widget_style->bg[GTK_STATE_NORMAL].red >> 8; blank_rgba.g = widget_style->bg[GTK_STATE_NORMAL].green >> 8; blank_rgba.b = widget_style->bg[GTK_STATE_NORMAL].blue >> 8; blank_rgba.a = 0xFF; corner = AMITK_VOLUME_CORNER(canvas->volume); width = ceil(corner.x/pixel_dim); if (width < 1) width = 1; height = ceil(corner.y/pixel_dim); if (height < 1) height = 1; canvas->pixbuf = image_blank(width, height,blank_rgba); amitk_objects_unref(canvas->slices); canvas->slices = NULL; } else { if (AMITK_IS_DATA_SET(canvas->active_object)) active_ds = AMITK_DATA_SET(canvas->active_object); else active_ds = NULL; canvas->pixbuf = image_from_data_sets(&(canvas->slices), &(canvas->slice_cache), canvas->max_slice_cache_size, data_sets, active_ds, AMITK_STUDY_VIEW_START_TIME(canvas->study), AMITK_STUDY_VIEW_DURATION(canvas->study), -1, pixel_dim, canvas->volume, AMITK_STUDY_FUSE_TYPE(canvas->study), AMITK_CANVAS_VIEW_MODE(canvas)); amitk_objects_unref(data_sets); } if (canvas->pixbuf != NULL) { /* record the width and height for future use*/ canvas->pixbuf_width = gdk_pixbuf_get_width(canvas->pixbuf); canvas->pixbuf_height = gdk_pixbuf_get_height(canvas->pixbuf); /* reset the min size of the widget and set the scroll region */ if ((old_width != canvas->pixbuf_width) || (old_height != canvas->pixbuf_height) || (canvas->image == NULL)) { gtk_widget_set_size_request(canvas->canvas, canvas->pixbuf_width + 2 * canvas->border_width, canvas->pixbuf_height + 2 * canvas->border_width); gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas->canvas), 0.0, 0.0, canvas->pixbuf_width + 2 * canvas->border_width, canvas->pixbuf_height + 2 * canvas->border_width); } /* put the canvas rgb image on the canvas_image */ if (canvas->image == NULL) {/* time to make a new image */ canvas->image = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(canvas->canvas)), gnome_canvas_pixbuf_get_type(), "pixbuf", canvas->pixbuf, "x", (double) canvas->border_width, "y", (double) canvas->border_width, NULL); g_signal_connect(G_OBJECT(canvas->image), "event", G_CALLBACK(canvas_event_cb), canvas); } else { gnome_canvas_item_set(canvas->image, "pixbuf", canvas->pixbuf, NULL); } } return; } static void canvas_update_object(AmitkCanvas * canvas, AmitkObject * object) { rgba_t outline_color; GnomeCanvasItem * item; GnomeCanvasItem * new_item; amide_real_t pixel_dim; g_return_if_fail(object != NULL); g_return_if_fail(canvas->study != NULL); item = canvas_find_item(canvas, object); if (item != NULL) { g_return_if_fail(object == g_object_get_data(G_OBJECT(item), "object")); } outline_color = amitk_color_table_outline_color(canvas_get_color_table(canvas), TRUE); /* compensate for zoom */ pixel_dim = (1/AMITK_STUDY_ZOOM(canvas->study))*AMITK_STUDY_VOXEL_DIM(canvas->study); new_item = amitk_canvas_object_draw(GNOME_CANVAS(canvas->canvas), canvas->volume, object, AMITK_CANVAS_VIEW_MODE(canvas), item, pixel_dim, canvas->pixbuf_width, canvas->pixbuf_height, canvas->border_width,canvas->border_width, outline_color, AMITK_STUDY_CANVAS_ROI_WIDTH(canvas->study), #ifdef AMIDE_LIBGNOMECANVAS_AA AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(canvas->study) #else AMITK_STUDY_CANVAS_LINE_STYLE(canvas->study), AMITK_STUDY_CANVAS_FILL_ROI(canvas->study) #endif ); if ((item == NULL) && (new_item != NULL)) { g_object_set_data(G_OBJECT(new_item), "object", object); g_signal_connect(G_OBJECT(new_item), "event", G_CALLBACK(canvas_event_cb), canvas); canvas->object_items = g_list_append(canvas->object_items, new_item); } return; } static void canvas_update_objects(AmitkCanvas * canvas, gboolean all) { GList * objects; AmitkObject * object; if (all) { objects = canvas_add_current_objects(canvas, canvas->next_update_objects); } else { objects = canvas->next_update_objects; } canvas->next_update_objects = NULL; while (objects != NULL) { object = AMITK_OBJECT(objects->data); canvas_update_object(canvas, object); objects = g_list_remove(objects, object); amitk_object_unref(object); } } static void canvas_update_setup(AmitkCanvas * canvas) { gboolean first_time = FALSE; gchar * temp_str; if (canvas->canvas != NULL) { /* add a ref so they aren't destroyed when removed from the container */ g_object_ref(G_OBJECT(canvas->label)); g_object_ref(G_OBJECT(canvas->canvas)); g_object_ref(G_OBJECT(canvas->scrollbar)); gtk_container_remove(GTK_CONTAINER(canvas), canvas->label); gtk_container_remove(GTK_CONTAINER(canvas), canvas->canvas); gtk_container_remove(GTK_CONTAINER(canvas), canvas->scrollbar); } else { first_time = TRUE; temp_str = g_strdup_printf("%s %d\n", amitk_view_get_name(canvas->view), canvas->view_mode+1); canvas->label = gtk_label_new(temp_str); g_free(temp_str); #ifdef AMIDE_LIBGNOMECANVAS_AA canvas->canvas = gnome_canvas_new_aa(); #else canvas->canvas = gnome_canvas_new(); #endif canvas->scrollbar_adjustment = gtk_adjustment_new(0.5, 0, 1, 1, 1, 1); /* junk values */ g_signal_connect(canvas->scrollbar_adjustment, "value_changed", G_CALLBACK(canvas_scrollbar_adjustment_cb), canvas); canvas->scrollbar = gtk_hscrollbar_new(GTK_ADJUSTMENT(canvas->scrollbar_adjustment)); gtk_range_set_update_policy(GTK_RANGE(canvas->scrollbar), GTK_UPDATE_CONTINUOUS); } /* pack it in based on what the layout is */ switch(AMITK_STUDY_CANVAS_LAYOUT(canvas->study)) { case AMITK_LAYOUT_ORTHOGONAL: switch(canvas->view) { case AMITK_VIEW_CORONAL: gtk_box_pack_start(GTK_BOX(canvas), canvas->canvas, TRUE, TRUE, BOX_SPACING); gtk_box_pack_start(GTK_BOX(canvas), canvas->scrollbar, FALSE, FALSE, BOX_SPACING); gtk_box_pack_start(GTK_BOX(canvas), canvas->label, FALSE, FALSE, BOX_SPACING); break; case AMITK_VIEW_TRANSVERSE: case AMITK_VIEW_SAGITTAL: default: gtk_box_pack_start(GTK_BOX(canvas), canvas->label, FALSE, FALSE, BOX_SPACING); gtk_box_pack_start(GTK_BOX(canvas), canvas->scrollbar, FALSE, FALSE, BOX_SPACING); gtk_box_pack_start(GTK_BOX(canvas), canvas->canvas, TRUE,TRUE,BOX_SPACING); break; } break; case AMITK_LAYOUT_LINEAR: default: gtk_box_pack_start(GTK_BOX(canvas), canvas->label, FALSE, FALSE, BOX_SPACING); gtk_box_pack_start(GTK_BOX(canvas), canvas->canvas, TRUE,TRUE,BOX_SPACING); gtk_box_pack_start(GTK_BOX(canvas), canvas->scrollbar, FALSE, FALSE,BOX_SPACING); break; } if (first_time) { canvas_add_update(canvas, UPDATE_ALL); } else { if (canvas->view == AMITK_VIEW_SAGITTAL) canvas_add_update(canvas, UPDATE_ALL); g_object_unref(G_OBJECT(canvas->label)); g_object_unref(G_OBJECT(canvas->canvas)); g_object_unref(G_OBJECT(canvas->scrollbar)); } } static void canvas_add_object_update(AmitkCanvas * canvas, AmitkObject * object) { if (AMITK_IS_STUDY(object)) { canvas_add_update(canvas, UPDATE_ALL); } else if (amitk_object_get_selected(object, canvas->view_mode)) { if (AMITK_IS_DATA_SET(object)) { canvas_add_update(canvas, UPDATE_ALL); } else if (g_list_index(canvas->next_update_objects, object) < 0) {/* not yet in list */ canvas->next_update_objects=g_list_append(canvas->next_update_objects, amitk_object_ref(object)); canvas_add_update(canvas, UPDATE_OBJECT); } } return; } static void canvas_add_update(AmitkCanvas * canvas, guint update_type) { /* reslicing is slow, put up a wait cursor */ /* don't use ui_common_place_cursor, as this has a gtk_main_iteration call... */ if ((update_type & UPDATE_DATA_SETS) && !(canvas->next_update & UPDATE_DATA_SETS)) ui_common_place_cursor_no_wait(UI_CURSOR_WAIT,GTK_WIDGET(canvas)); canvas->next_update = canvas->next_update | update_type; /* DEFAULT_IDLE is needed, as this is the first default lower then redraw */ if (canvas->idle_handler_id == 0) canvas->idle_handler_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,canvas_update_while_idle, canvas, NULL); return; } static gboolean canvas_update_while_idle(gpointer data) { AmitkCanvas * canvas = data; /* update the corners */ if (canvas_recalc_corners(canvas)) /* if corners changed */ canvas->next_update = canvas->next_update | UPDATE_ALL; if (canvas->next_update & UPDATE_DATA_SETS) { canvas_update_pixbuf(canvas); } if (canvas->next_update & UPDATE_ARROWS) { canvas_update_arrows(canvas); } if (canvas->next_update & UPDATE_SCROLLBAR) { canvas_update_scrollbar(canvas, canvas->center, AMITK_VOLUME_Z_CORNER(canvas->volume)); } if (canvas->next_update & (UPDATE_OBJECTS | UPDATE_OBJECT)) { canvas_update_objects(canvas, (canvas->next_update & UPDATE_OBJECTS)); } if (canvas->next_update & UPDATE_LINE_PROFILE) { canvas_update_line_profile(canvas); } if (canvas->next_update & UPDATE_TIME) { canvas_update_time_on_image(canvas); } if (canvas->next_update & UPDATE_SUBJECT_ORIENTATION) { canvas_update_subject_orientation(canvas); } if (canvas->next_update & UPDATE_TARGET) { canvas_update_target(canvas, canvas->next_target_action, canvas->next_target_center, canvas->next_target_thickness); } canvas->idle_handler_id=0; if (canvas->next_update & UPDATE_DATA_SETS) /* remove the cursor on slow updates */ ui_common_remove_wait_cursor(GTK_WIDGET(canvas)); canvas->next_update = UPDATE_NONE; return FALSE; } static void canvas_add_object(AmitkCanvas * canvas, AmitkObject * object) { GList * children; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(object)); amitk_object_ref(object); if (AMITK_IS_STUDY(object)) { if (canvas->study != NULL) { canvas_remove_object(canvas, AMITK_OBJECT(canvas->study)); } canvas->study = AMITK_STUDY(object); canvas->center = AMITK_STUDY_VIEW_CENTER(object); amitk_volume_set_z_corner(canvas->volume, AMITK_STUDY_VIEW_THICKNESS(object)); } canvas_add_object_update(canvas, object); g_signal_connect(G_OBJECT(object), "space_changed", G_CALLBACK(canvas_space_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "object_selection_changed", G_CALLBACK(canvas_object_selection_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "object_add_child", G_CALLBACK(canvas_object_add_child_cb), canvas); g_signal_connect(G_OBJECT(object), "object_remove_child", G_CALLBACK(canvas_object_remove_child_cb), canvas); if (AMITK_IS_STUDY(object)) { g_signal_connect(G_OBJECT(object), "thickness_changed", G_CALLBACK(canvas_view_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "time_changed", G_CALLBACK(canvas_time_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "canvas_target_changed", G_CALLBACK(canvas_target_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "voxel_dim_or_zoom_changed", G_CALLBACK(canvas_study_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "fov_changed", G_CALLBACK(canvas_study_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "fuse_type_changed", G_CALLBACK(canvas_study_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "view_center_changed", G_CALLBACK(canvas_view_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "canvas_roi_preference_changed", G_CALLBACK(canvas_roi_preference_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "canvas_general_preference_changed", G_CALLBACK(canvas_general_preference_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "canvas_target_preference_changed", G_CALLBACK(canvas_target_preference_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "canvas_layout_preference_changed", G_CALLBACK(canvas_layout_preference_changed_cb), canvas); g_signal_connect(G_OBJECT(AMITK_STUDY_LINE_PROFILE(object)), "line_profile_changed", G_CALLBACK(canvas_line_profile_changed_cb), canvas); } if (AMITK_IS_VOLUME(object)) { g_signal_connect(G_OBJECT(object), "volume_changed", G_CALLBACK(canvas_volume_changed_cb), canvas); } if (AMITK_IS_ROI(object)) { g_signal_connect(G_OBJECT(object), "roi_changed", G_CALLBACK(canvas_roi_changed_cb), canvas); } if (AMITK_IS_FIDUCIAL_MARK(object)) { g_signal_connect(G_OBJECT(object), "fiducial_mark_changed", G_CALLBACK(canvas_fiducial_mark_changed_cb), canvas); } if (AMITK_IS_DATA_SET(object)) { g_signal_connect(G_OBJECT(object), "data_set_changed", G_CALLBACK(data_set_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "invalidate_slice_cache", G_CALLBACK(canvas_data_set_invalidate_slice_cache), canvas); g_signal_connect(G_OBJECT(object), "interpolation_changed", G_CALLBACK(data_set_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "rendering_changed", G_CALLBACK(data_set_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "thresholding_changed", G_CALLBACK(data_set_thresholding_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "thresholds_changed", G_CALLBACK(data_set_thresholding_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "color_table_changed", G_CALLBACK(data_set_color_table_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "subject_orientation_changed", G_CALLBACK(data_set_subject_orientation_changed_cb), canvas); g_signal_connect(G_OBJECT(object), "view_gates_changed", G_CALLBACK(data_set_changed_cb), canvas); } /* keep track of undrawn rois */ if (AMITK_IS_ROI(object)) if (AMITK_ROI_UNDRAWN(object)) if (amitk_object_get_selected(object, canvas->view_mode)) { if (g_list_index(canvas->undrawn_rois, object) < 0) /* not yet in list */ canvas->undrawn_rois = g_list_prepend(canvas->undrawn_rois, amitk_object_ref(object)); amitk_object_ref(object); } /* recurse */ children= AMITK_OBJECT_CHILDREN(object); while (children != NULL) { canvas_add_object(canvas, children->data); children = children->next; } return; } static void canvas_remove_object(AmitkCanvas * canvas, AmitkObject * object) { GnomeCanvasItem * found_item; GList * children; g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_OBJECT(object)); /* remove children */ children= AMITK_OBJECT_CHILDREN(object); while (children != NULL) { canvas_remove_object(canvas, children->data); children = children->next; } /* keep track of undrawn rois */ if (AMITK_IS_ROI(object)) { if (g_list_index(canvas->undrawn_rois, object) >= 0) { canvas->undrawn_rois = g_list_remove(canvas->undrawn_rois, object); amitk_object_unref(object); } } g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_space_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_object_selection_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_object_add_child_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_object_remove_child_cb, canvas); if (AMITK_IS_STUDY(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_study_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_view_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_target_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_time_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_roi_preference_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_general_preference_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_target_preference_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_layout_preference_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(AMITK_STUDY_LINE_PROFILE(object)), canvas_line_profile_changed_cb, canvas); } if (AMITK_IS_VOLUME(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_volume_changed_cb, canvas); } if (AMITK_IS_ROI(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_roi_changed_cb, canvas); } if (AMITK_IS_FIDUCIAL_MARK(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_fiducial_mark_changed_cb, canvas); } if (AMITK_IS_DATA_SET(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), data_set_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), canvas_data_set_invalidate_slice_cache, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), data_set_thresholding_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), data_set_color_table_changed_cb, canvas); g_signal_handlers_disconnect_by_func(G_OBJECT(object), data_set_subject_orientation_changed_cb, canvas); canvas->slice_cache = amitk_data_sets_remove_with_slice_parent(canvas->slice_cache, AMITK_DATA_SET(object)); } /* find corresponding CanvasItem and destroy */ found_item = canvas_find_item(canvas, object); if (found_item) { canvas->object_items = g_list_remove(canvas->object_items, found_item); gtk_object_destroy(GTK_OBJECT(found_item)); canvas_add_update(canvas, UPDATE_VIEW); /* needed to check if we need to reset the view slice */ } else if (AMITK_IS_DATA_SET(object)) { canvas_add_update(canvas, UPDATE_ALL); } amitk_object_unref(object); return; } GtkWidget * amitk_canvas_new(AmitkStudy * study, AmitkView view, AmitkViewMode view_mode, AmitkCanvasType type) { AmitkCanvas * canvas; g_return_val_if_fail(AMITK_IS_STUDY(study), NULL); canvas = g_object_new(amitk_canvas_get_type(), NULL); canvas->view = view; canvas->view_mode = view_mode; canvas->type = type; switch(type) { case AMITK_CANVAS_TYPE_FLY_THROUGH: canvas->border_width = 0.0; break; case AMITK_CANVAS_TYPE_NORMAL: default: canvas->border_width = DEFAULT_CANVAS_BORDER_WIDTH; break; } amitk_space_set_view_space(AMITK_SPACE(canvas->volume), canvas->view, AMITK_STUDY_CANVAS_LAYOUT(study)); amitk_canvas_set_study(canvas, study); canvas_update_setup(canvas); return GTK_WIDGET (canvas); } void amitk_canvas_set_study(AmitkCanvas * canvas, AmitkStudy * study) { g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(AMITK_IS_STUDY(study)); canvas_add_object(canvas, AMITK_OBJECT(study)); return; } void amitk_canvas_set_active_object(AmitkCanvas * canvas, AmitkObject * active_object) { g_return_if_fail(AMITK_IS_CANVAS(canvas)); g_return_if_fail(active_object != NULL); if (canvas->active_object != active_object) { canvas->active_object = active_object; if (AMITK_STUDY_FUSE_TYPE(canvas->study) == AMITK_FUSE_TYPE_BLEND) { canvas_add_update(canvas, UPDATE_OBJECTS); } else /* AMITK_FUSE_TYPE_OVERLAY */ canvas_add_update(canvas, UPDATE_DATA_SETS); canvas_add_update(canvas, UPDATE_TARGET); canvas_add_update(canvas, UPDATE_LINE_PROFILE); canvas_add_update(canvas, UPDATE_SUBJECT_ORIENTATION); } return; } void amitk_canvas_update_target(AmitkCanvas * canvas, AmitkCanvasTargetAction action, AmitkPoint center, amide_real_t thickness) { g_return_if_fail(AMITK_IS_CANVAS(canvas)); canvas->next_target_action = action; canvas->next_target_center = center; canvas->next_target_thickness = thickness; canvas_add_update(canvas, UPDATE_TARGET); return; } void amitk_canvas_set_time_on_image(AmitkCanvas * canvas, gboolean time_on_image) { g_return_if_fail(AMITK_IS_CANVAS(canvas)); if (time_on_image != canvas->time_on_image) { canvas->time_on_image = time_on_image; canvas_add_update(canvas, UPDATE_TIME); } return; } gint amitk_canvas_get_width(AmitkCanvas * canvas) { g_return_val_if_fail(AMITK_IS_CANVAS(canvas), 0); return canvas->pixbuf_width + 2*canvas->border_width; } gint amitk_canvas_get_height(AmitkCanvas * canvas) { GtkRequisition size; gint height; g_return_val_if_fail(AMITK_IS_CANVAS(canvas), 0); height = canvas->pixbuf_height + 2*canvas->border_width; gtk_widget_size_request(canvas->label, &size); height+=size.height; gtk_widget_size_request(canvas->scrollbar, &size); height+=size.height; return height; } GdkPixbuf * amitk_canvas_get_pixbuf(AmitkCanvas * canvas) { GdkPixbuf * pixbuf; pixbuf = amitk_get_pixbuf_from_canvas(GNOME_CANVAS(canvas->canvas), canvas->border_width,canvas->border_width, canvas->pixbuf_width, canvas->pixbuf_height); return pixbuf; } amide-1.0.6/amide-current/src/amitk_canvas.h000066400000000000000000000114001423227705100207330ustar00rootroot00000000000000/* amitk_canvas.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_CANVAS_H__ #define __AMITK_CANVAS_H__ /* includes we always need with this widget */ //#include //#include //#include #include "amitk_study.h" G_BEGIN_DECLS #define AMITK_TYPE_CANVAS (amitk_canvas_get_type ()) #define AMITK_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_CANVAS, AmitkCanvas)) #define AMITK_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_CANVAS, AmitkCanvasClass)) #define AMITK_IS_CANVAS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_CANVAS)) #define AMITK_IS_CANVAS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_CANVAS)) #define AMITK_CANVAS_VIEW(obj) (AMITK_CANVAS(obj)->view) #define AMITK_CANVAS_VIEW_MODE(obj) (AMITK_CANVAS(obj)->view_mode) typedef enum { AMITK_CANVAS_TYPE_NORMAL, AMITK_CANVAS_TYPE_FLY_THROUGH } AmitkCanvasType; typedef enum { AMITK_CANVAS_TARGET_ACTION_HIDE, AMITK_CANVAS_TARGET_ACTION_SHOW, AMITK_CANVAS_TARGET_ACTION_LEAVE } AmitkCanvasTargetAction; typedef struct _AmitkCanvas AmitkCanvas; typedef struct _AmitkCanvasClass AmitkCanvasClass; struct _AmitkCanvas { GtkVBox vbox; GtkWidget * canvas; GtkWidget * label; GtkWidget * scrollbar; GtkObject * scrollbar_adjustment; GnomeCanvasItem * arrows[4]; GnomeCanvasItem * orientation_label[4]; AmitkCanvasType type; AmitkVolume * volume; /* the volume that this canvas slice displays */ AmitkPoint center; /* in base coordinate space */ AmitkView view; AmitkViewMode view_mode; gint roi_width; AmitkObject * active_object; GList * slices; GList * slice_cache; gint max_slice_cache_size; gint pixbuf_width, pixbuf_height; gdouble border_width; GnomeCanvasItem * image; GdkPixbuf * pixbuf; gboolean time_on_image; GnomeCanvasItem * time_label; AmitkStudy * study; GList * undrawn_rois; GList * object_items; guint next_update; guint idle_handler_id; GList * next_update_objects; /* profile stuff */ GnomeCanvasItem * line_profile_item; /* target stuff */ GnomeCanvasItem * target[8]; AmitkCanvasTargetAction next_target_action; AmitkPoint next_target_center; amide_real_t next_target_thickness; }; struct _AmitkCanvasClass { GtkVBoxClass parent_class; void (* help_event) (AmitkCanvas *Canvas, AmitkHelpInfo which_help, AmitkPoint *position, amide_data_t value); void (* view_changing) (AmitkCanvas *Canvas, AmitkPoint *position, amide_real_t thickness); void (* view_changed) (AmitkCanvas *Canvas, AmitkPoint *position, amide_real_t thickness); void (* erase_volume) (AmitkCanvas *Canvas, AmitkRoi *roi, gboolean outside); void (* new_object) (AmitkCanvas *Canvas, AmitkObject * parent, AmitkObjectType type, AmitkPoint *position); }; GType amitk_canvas_get_type (void); GtkWidget * amitk_canvas_new (AmitkStudy * study, AmitkView view, AmitkViewMode view_mode, AmitkCanvasType type); void amitk_canvas_set_study (AmitkCanvas * canvas, AmitkStudy * study); void amitk_canvas_set_active_object (AmitkCanvas * canvas, AmitkObject * active_object); void amitk_canvas_update_target (AmitkCanvas * canvas, AmitkCanvasTargetAction action, AmitkPoint center, amide_real_t thickness); void amitk_canvas_set_time_on_image (AmitkCanvas * canvas, gboolean time_on_image); gint amitk_canvas_get_width (AmitkCanvas * canvas); gint amitk_canvas_get_height (AmitkCanvas * canvas); GdkPixbuf * amitk_canvas_get_pixbuf (AmitkCanvas * canvas); G_END_DECLS #endif /* __AMITK_CANVAS_H__ */ amide-1.0.6/amide-current/src/amitk_canvas_object.c000066400000000000000000000225431423227705100222660ustar00rootroot00000000000000/* amitk_canvas_object.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_marshal.h" #include "amitk_canvas_object.h" #include "amitk_type_builtins.h" #include "amitk_canvas.h" #include "image.h" #define FIDUCIAL_MARK_WIDTH 4.0 #define FIDUCIAL_MARK_WIDTH_PIXELS 2 #ifndef AMIDE_LIBGNOMECANVAS_AA #define FIDUCIAL_MARK_LINE_STYLE GDK_LINE_SOLID #endif /* draws the given object on the given canvas. */ /* if item is NULL, a new canvas item will be created */ /* pixel dim is the current dimensions of the pixels in the canvas */ GnomeCanvasItem * amitk_canvas_object_draw(GnomeCanvas * canvas, AmitkVolume * canvas_volume, AmitkObject * object, AmitkViewMode view_mode, GnomeCanvasItem * item, amide_real_t pixel_dim, gint width, gint height, gdouble x_offset, gdouble y_offset, rgba_t roi_color, gint roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA gdouble transparency #else GdkLineStyle line_style, gboolean fill_roi #endif ) { guint32 fill_color_rgba; guint32 outline_color_rgba; gdouble affine[6]; gboolean hide_object = FALSE; GnomeCanvasPoints * points; g_return_val_if_fail(GNOME_IS_CANVAS(canvas), item); g_return_val_if_fail(AMITK_IS_VOLUME(canvas_volume), item); g_return_val_if_fail(object != NULL, item); if (item != NULL) { /* make sure to reset any affine translations we've done */ gnome_canvas_item_i2w_affine(item,affine); affine[0] = affine[3] = 1.0; affine[1] = affine[2] = affine[4] = affine[5] = 0.0; gnome_canvas_item_affine_absolute(item,affine); } if (AMITK_IS_FIDUCIAL_MARK(object)) { /* --------------------- redraw alignment point ----------------------------- */ AmitkPoint center_point; AmitkCanvasPoint center_cpoint; rgba_t outline_color; if (AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(object)) outline_color = AMITK_FIDUCIAL_MARK_COLOR(object); else if (AMITK_IS_DATA_SET(AMITK_OBJECT_PARENT(object))) outline_color = amitk_color_table_outline_color(amitk_data_set_get_color_table_to_use(AMITK_DATA_SET(AMITK_OBJECT_PARENT(object)), view_mode), TRUE); else outline_color = amitk_color_table_outline_color(AMITK_COLOR_TABLE_BW_LINEAR, TRUE); outline_color_rgba = amitk_color_table_rgba_to_uint32(outline_color); center_point = amitk_space_b2s(AMITK_SPACE(canvas_volume), AMITK_FIDUCIAL_MARK_GET(object)); center_cpoint= point_2_canvas_point(AMITK_VOLUME_CORNER(canvas_volume), width, height, x_offset, y_offset, center_point); points = gnome_canvas_points_new(7); points->coords[0] = center_cpoint.x-FIDUCIAL_MARK_WIDTH; points->coords[1] = center_cpoint.y; points->coords[2] = center_cpoint.x; points->coords[3] = center_cpoint.y; points->coords[4] = center_cpoint.x; points->coords[5] = center_cpoint.y+FIDUCIAL_MARK_WIDTH; points->coords[6] = center_cpoint.x; points->coords[7] = center_cpoint.y; points->coords[8] = center_cpoint.x+FIDUCIAL_MARK_WIDTH; points->coords[9] = center_cpoint.y; points->coords[10] = center_cpoint.x; points->coords[11] = center_cpoint.y; points->coords[12] = center_cpoint.x; points->coords[13] = center_cpoint.y-FIDUCIAL_MARK_WIDTH; if (item == NULL) item = gnome_canvas_item_new(gnome_canvas_root(canvas), gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", outline_color_rgba, "width_pixels", FIDUCIAL_MARK_WIDTH_PIXELS, #ifndef AMIDE_LIBGNOMECANVAS_AA "line_style", FIDUCIAL_MARK_LINE_STYLE, #endif NULL); else gnome_canvas_item_set(item, "points", points,"fill_color_rgba", outline_color_rgba, NULL); gnome_canvas_points_unref(points); /* make sure the point is on this slice */ hide_object = ((center_point.x < 0.0) || (center_point.x > AMITK_VOLUME_X_CORNER(canvas_volume)) || (center_point.y < 0.0) || (center_point.y > AMITK_VOLUME_Y_CORNER(canvas_volume)) || (center_point.z < 0.0) || (center_point.z > AMITK_VOLUME_Z_CORNER(canvas_volume))); } else if (AMITK_IS_ROI(object)) { /* --------------------- redraw roi ----------------------------- */ GSList * roi_points, * temp; guint num_points, j; AmitkCanvasPoint roi_cpoint; GdkPixbuf * pixbuf; AmitkCanvasPoint offset_cpoint; AmitkCanvasPoint corner_cpoint; AmitkRoi * roi = AMITK_ROI(object); AmitkPoint offset, corner; AmitkPoint * ptemp_rp; if (AMITK_ROI_UNDRAWN(object)) return item; /* overwrite the passed in color if desired */ if (AMITK_ROI_SPECIFY_COLOR(object)) roi_color = AMITK_ROI_COLOR(object); switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ISOCONTOUR_2D: case AMITK_ROI_TYPE_ISOCONTOUR_3D: case AMITK_ROI_TYPE_FREEHAND_2D: case AMITK_ROI_TYPE_FREEHAND_3D: offset = zero_point; corner = one_point; pixbuf = image_slice_intersection(roi, canvas_volume, pixel_dim, #ifdef AMIDE_LIBGNOMECANVAS_AA transparency, #else fill_roi, #endif roi_color,&offset, &corner); offset_cpoint= point_2_canvas_point(AMITK_VOLUME_CORNER(canvas_volume), width, height, x_offset, y_offset, amitk_space_b2s(AMITK_SPACE(canvas_volume), offset)); corner_cpoint= point_2_canvas_point(AMITK_VOLUME_CORNER(canvas_volume), width, height, x_offset, y_offset, amitk_space_b2s(AMITK_SPACE(canvas_volume), corner)); /* find the north west corner (in terms of the X reference frame) */ if (corner_cpoint.y < offset_cpoint.y) offset_cpoint.y = corner_cpoint.y; if (corner_cpoint.x < offset_cpoint.x) offset_cpoint.x = corner_cpoint.x; /* create the item */ if (item == NULL) { item = gnome_canvas_item_new(gnome_canvas_root(canvas), gnome_canvas_pixbuf_get_type(), "pixbuf", pixbuf, "x", (double) offset_cpoint.x, "y", (double) offset_cpoint.y, NULL); } else { gnome_canvas_item_set(item, "pixbuf", pixbuf, "x", (double) offset_cpoint.x, "y", (double) offset_cpoint.y, NULL); } if (pixbuf != NULL) g_object_unref(pixbuf); break; case AMITK_ROI_TYPE_ELLIPSOID: case AMITK_ROI_TYPE_CYLINDER: case AMITK_ROI_TYPE_BOX: roi_points = amitk_roi_get_intersection_line(roi, canvas_volume, pixel_dim); /* count the points */ num_points=0; temp=roi_points; while(temp!=NULL) { temp=temp->next; num_points++; } /* transfer the points list to what we'll be using to construction the figure */ if (num_points > 1) { points = gnome_canvas_points_new(num_points); temp=roi_points; j=0; while(temp!=NULL) { ptemp_rp = temp->data; roi_cpoint= point_2_canvas_point(AMITK_VOLUME_CORNER(canvas_volume), width, height, x_offset, y_offset, *ptemp_rp); points->coords[j] = roi_cpoint.x; points->coords[j+1] = roi_cpoint.y; temp=temp->next; j += 2; } } else { /* throw in junk we'll hide*/ hide_object = TRUE; points = gnome_canvas_points_new(3); points->coords[0] = points->coords[1] = 0; points->coords[2] = points->coords[3] = 1; points->coords[4] = 0; points->coords[5] = 1; } roi_points = amitk_roi_free_points_list(roi_points); #ifdef AMIDE_LIBGNOMECANVAS_AA outline_color_rgba = amitk_color_table_rgba_to_uint32(roi_color); roi_color.a = transparency * 0xFF; #endif fill_color_rgba = amitk_color_table_rgba_to_uint32(roi_color); if ((item == NULL)) { /* create the item */ item = gnome_canvas_item_new(gnome_canvas_root(canvas), #ifdef AMIDE_LIBGNOMECANVAS_AA gnome_canvas_polygon_get_type(), #else gnome_canvas_line_get_type(), #endif "points", points, "fill_color_rgba",fill_color_rgba, "width_pixels", roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA "outline_color_rgba", outline_color_rgba, #else "line_style", line_style, #endif NULL); } else { /* and reset the line points */ gnome_canvas_item_set(item, "points", points, "fill_color_rgba", fill_color_rgba, "width_pixels", roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA "outline_color_rgba", outline_color_rgba, #else "line_style", line_style, #endif NULL); } gnome_canvas_points_unref(points); break; default: g_error("unexpected case in %s at %d\n", __FILE__, __LINE__); break; } } /* make sure the point is on this canvas */ if (hide_object) gnome_canvas_item_hide(item); else if (item) gnome_canvas_item_show(item); return item; } amide-1.0.6/amide-current/src/amitk_canvas_object.h000066400000000000000000000033141423227705100222660ustar00rootroot00000000000000/* amitk_canvas_object.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2004-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_CANVAS_OBJECT_H__ #define __AMITK_CANVAS_OBJECT_H__ /* includes we always need with this widget */ #include #include #include #include "amitk_volume.h" #include "amitk_color_table.h" G_BEGIN_DECLS GnomeCanvasItem * amitk_canvas_object_draw(GnomeCanvas * canvas, AmitkVolume * canvas_volume, AmitkObject * object, AmitkViewMode view_mode, GnomeCanvasItem * item, amide_real_t pixel_dim, gint width, gint height, gdouble x_offset, gdouble y_offset, rgba_t roi_color, gint roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA gdouble transparency #else GdkLineStyle line_style, gboolean fill_roi #endif ); G_END_DECLS #endif /* __AMITK_CANVAS_OBJECT_H__ */ amide-1.0.6/amide-current/src/amitk_color_table.c000066400000000000000000000602531423227705100217520ustar00rootroot00000000000000/* amitk_color_table.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include "amitk_common.h" #include "amitk_color_table.h" #include "amitk_type_builtins.h" /* external variables */ /* don't change these, as legacy.c needs them for reading in files */ gchar * color_table_menu_names[] = { N_("black/white linear"), N_("white/black linear"), N_("black/white/black"), N_("white/black/white"), N_("red temperature"), N_("inverse red temp."), N_("blue temperature"), N_("inv. blue temp."), N_("green temperature"), N_("inv. green temp."), N_("hot metal"), N_("inv. hot metal"), N_("hot metal contour"), N_("inv. hot metal c."), N_("hot blue"), N_("inverse hot blue"), N_("hot green"), N_("inverse hot green"), N_("spectrum"), N_("inverse spectrum"), N_("NIH + white"), N_("inv. NIH + white"), N_("NIH"), N_("inverse NIH"), N_("viridis"), N_("inverse viridis") }; static const amide_data_t kViridis[256*3] = { // from https://github.com/RhoInc/sas-viridis/blob/master/src/viridis.sas 0.267004, 0.004874, 0.329415, 0.268510, 0.009605, 0.335427, 0.269944, 0.014625, 0.341379, 0.271305, 0.019942, 0.347269, 0.272594, 0.025563, 0.353093, 0.273809, 0.031497, 0.358853, 0.274952, 0.037752, 0.364543, 0.276022, 0.044167, 0.370164, 0.277018, 0.050344, 0.375715, 0.277941, 0.056324, 0.381191, 0.278791, 0.062145, 0.386592, 0.279566, 0.067836, 0.391917, 0.280267, 0.073417, 0.397163, 0.280894, 0.078907, 0.402329, 0.281446, 0.084320, 0.407414, 0.281924, 0.089666, 0.412415, 0.282327, 0.094955, 0.417331, 0.282656, 0.100196, 0.422160, 0.282910, 0.105393, 0.426902, 0.283091, 0.110553, 0.431554, 0.283197, 0.115680, 0.436115, 0.283229, 0.120777, 0.440584, 0.283187, 0.125848, 0.444960, 0.283072, 0.130895, 0.449241, 0.282884, 0.135920, 0.453427, 0.282623, 0.140926, 0.457517, 0.282290, 0.145912, 0.461510, 0.281887, 0.150881, 0.465405, 0.281412, 0.155834, 0.469201, 0.280868, 0.160771, 0.472899, 0.280255, 0.165693, 0.476498, 0.279574, 0.170599, 0.479997, 0.278826, 0.175490, 0.483397, 0.278012, 0.180367, 0.486697, 0.277134, 0.185228, 0.489898, 0.276194, 0.190074, 0.493001, 0.275191, 0.194905, 0.496005, 0.274128, 0.199721, 0.498911, 0.273006, 0.204520, 0.501721, 0.271828, 0.209303, 0.504434, 0.270595, 0.214069, 0.507052, 0.269308, 0.218818, 0.509577, 0.267968, 0.223549, 0.512008, 0.266580, 0.228262, 0.514349, 0.265145, 0.232956, 0.516599, 0.263663, 0.237631, 0.518762, 0.262138, 0.242286, 0.520837, 0.260571, 0.246922, 0.522828, 0.258965, 0.251537, 0.524736, 0.257322, 0.256130, 0.526563, 0.255645, 0.260703, 0.528312, 0.253935, 0.265254, 0.529983, 0.252194, 0.269783, 0.531579, 0.250425, 0.274290, 0.533103, 0.248629, 0.278775, 0.534556, 0.246811, 0.283237, 0.535941, 0.244972, 0.287675, 0.537260, 0.243113, 0.292092, 0.538516, 0.241237, 0.296485, 0.539709, 0.239346, 0.300855, 0.540844, 0.237441, 0.305202, 0.541921, 0.235526, 0.309527, 0.542944, 0.233603, 0.313828, 0.543914, 0.231674, 0.318106, 0.544834, 0.229739, 0.322361, 0.545706, 0.227802, 0.326594, 0.546532, 0.225863, 0.330805, 0.547314, 0.223925, 0.334994, 0.548053, 0.221989, 0.339161, 0.548752, 0.220057, 0.343307, 0.549413, 0.218130, 0.347432, 0.550038, 0.216210, 0.351535, 0.550627, 0.214298, 0.355619, 0.551184, 0.212395, 0.359683, 0.551710, 0.210503, 0.363727, 0.552206, 0.208623, 0.367752, 0.552675, 0.206756, 0.371758, 0.553117, 0.204903, 0.375746, 0.553533, 0.203063, 0.379716, 0.553925, 0.201239, 0.383670, 0.554294, 0.199430, 0.387607, 0.554642, 0.197636, 0.391528, 0.554969, 0.195860, 0.395433, 0.555276, 0.194100, 0.399323, 0.555565, 0.192357, 0.403199, 0.555836, 0.190631, 0.407061, 0.556089, 0.188923, 0.410910, 0.556326, 0.187231, 0.414746, 0.556547, 0.185556, 0.418570, 0.556753, 0.183898, 0.422383, 0.556944, 0.182256, 0.426184, 0.557120, 0.180629, 0.429975, 0.557282, 0.179019, 0.433756, 0.557430, 0.177423, 0.437527, 0.557565, 0.175841, 0.441290, 0.557685, 0.174274, 0.445044, 0.557792, 0.172719, 0.448791, 0.557885, 0.171176, 0.452530, 0.557965, 0.169646, 0.456262, 0.558030, 0.168126, 0.459988, 0.558082, 0.166617, 0.463708, 0.558119, 0.165117, 0.467423, 0.558141, 0.163625, 0.471133, 0.558148, 0.162142, 0.474838, 0.558140, 0.160665, 0.478540, 0.558115, 0.159194, 0.482237, 0.558073, 0.157729, 0.485932, 0.558013, 0.156270, 0.489624, 0.557936, 0.154815, 0.493313, 0.557840, 0.153364, 0.497000, 0.557724, 0.151918, 0.500685, 0.557587, 0.150476, 0.504369, 0.557430, 0.149039, 0.508051, 0.557250, 0.147607, 0.511733, 0.557049, 0.146180, 0.515413, 0.556823, 0.144759, 0.519093, 0.556572, 0.143343, 0.522773, 0.556295, 0.141935, 0.526453, 0.555991, 0.140536, 0.530132, 0.555659, 0.139147, 0.533812, 0.555298, 0.137770, 0.537492, 0.554906, 0.136408, 0.541173, 0.554483, 0.135066, 0.544853, 0.554029, 0.133743, 0.548535, 0.553541, 0.132444, 0.552216, 0.553018, 0.131172, 0.555899, 0.552459, 0.129933, 0.559582, 0.551864, 0.128729, 0.563265, 0.551229, 0.127568, 0.566949, 0.550556, 0.126453, 0.570633, 0.549841, 0.125394, 0.574318, 0.549086, 0.124395, 0.578002, 0.548287, 0.123463, 0.581687, 0.547445, 0.122606, 0.585371, 0.546557, 0.121831, 0.589055, 0.545623, 0.121148, 0.592739, 0.544641, 0.120565, 0.596422, 0.543611, 0.120092, 0.600104, 0.542530, 0.119738, 0.603785, 0.541400, 0.119512, 0.607464, 0.540218, 0.119423, 0.611141, 0.538982, 0.119483, 0.614817, 0.537692, 0.119699, 0.618490, 0.536347, 0.120081, 0.622161, 0.534946, 0.120638, 0.625828, 0.533488, 0.121380, 0.629492, 0.531973, 0.122312, 0.633153, 0.530398, 0.123444, 0.636809, 0.528763, 0.124780, 0.640461, 0.527068, 0.126326, 0.644107, 0.525311, 0.128087, 0.647749, 0.523491, 0.130067, 0.651384, 0.521608, 0.132268, 0.655014, 0.519661, 0.134692, 0.658636, 0.517649, 0.137339, 0.662252, 0.515571, 0.140210, 0.665859, 0.513427, 0.143303, 0.669459, 0.511215, 0.146616, 0.673050, 0.508936, 0.150148, 0.676631, 0.506589, 0.153894, 0.680203, 0.504172, 0.157851, 0.683765, 0.501686, 0.162016, 0.687316, 0.499129, 0.166383, 0.690856, 0.496502, 0.170948, 0.694384, 0.493803, 0.175707, 0.697900, 0.491033, 0.180653, 0.701402, 0.488189, 0.185783, 0.704891, 0.485273, 0.191090, 0.708366, 0.482284, 0.196571, 0.711827, 0.479221, 0.202219, 0.715272, 0.476084, 0.208030, 0.718701, 0.472873, 0.214000, 0.722114, 0.469588, 0.220124, 0.725509, 0.466226, 0.226397, 0.728888, 0.462789, 0.232815, 0.732247, 0.459277, 0.239374, 0.735588, 0.455688, 0.246070, 0.738910, 0.452024, 0.252899, 0.742211, 0.448284, 0.259857, 0.745492, 0.444467, 0.266941, 0.748751, 0.440573, 0.274149, 0.751988, 0.436601, 0.281477, 0.755203, 0.432552, 0.288921, 0.758394, 0.428426, 0.296479, 0.761561, 0.424223, 0.304148, 0.764704, 0.419943, 0.311925, 0.767822, 0.415586, 0.319809, 0.770914, 0.411152, 0.327796, 0.773980, 0.406640, 0.335885, 0.777018, 0.402049, 0.344074, 0.780029, 0.397381, 0.352360, 0.783011, 0.392636, 0.360741, 0.785964, 0.387814, 0.369214, 0.788888, 0.382914, 0.377779, 0.791781, 0.377939, 0.386433, 0.794644, 0.372886, 0.395174, 0.797475, 0.367757, 0.404001, 0.800275, 0.362552, 0.412913, 0.803041, 0.357269, 0.421908, 0.805774, 0.351910, 0.430983, 0.808473, 0.346476, 0.440137, 0.811138, 0.340967, 0.449368, 0.813768, 0.335384, 0.458674, 0.816363, 0.329727, 0.468053, 0.818921, 0.323998, 0.477504, 0.821444, 0.318195, 0.487026, 0.823929, 0.312321, 0.496615, 0.826376, 0.306377, 0.506271, 0.828786, 0.300362, 0.515992, 0.831158, 0.294279, 0.525776, 0.833491, 0.288127, 0.535621, 0.835785, 0.281908, 0.545524, 0.838039, 0.275626, 0.555484, 0.840254, 0.269281, 0.565498, 0.842430, 0.262877, 0.575563, 0.844566, 0.256415, 0.585678, 0.846661, 0.249897, 0.595839, 0.848717, 0.243329, 0.606045, 0.850733, 0.236712, 0.616293, 0.852709, 0.230052, 0.626579, 0.854645, 0.223353, 0.636902, 0.856542, 0.216620, 0.647257, 0.858400, 0.209861, 0.657642, 0.860219, 0.203082, 0.668054, 0.861999, 0.196293, 0.678489, 0.863742, 0.189503, 0.688944, 0.865448, 0.182725, 0.699415, 0.867117, 0.175971, 0.709898, 0.868751, 0.169257, 0.720391, 0.870350, 0.162603, 0.730889, 0.871916, 0.156029, 0.741388, 0.873449, 0.149561, 0.751884, 0.874951, 0.143228, 0.762373, 0.876424, 0.137064, 0.772852, 0.877868, 0.131109, 0.783315, 0.879285, 0.125405, 0.793760, 0.880678, 0.120005, 0.804182, 0.882046, 0.114965, 0.814576, 0.883393, 0.110347, 0.824940, 0.884720, 0.106217, 0.835270, 0.886029, 0.102646, 0.845561, 0.887322, 0.099702, 0.855810, 0.888601, 0.097452, 0.866013, 0.889868, 0.095953, 0.876168, 0.891125, 0.095250, 0.886271, 0.892374, 0.095374, 0.896320, 0.893616, 0.096335, 0.906311, 0.894855, 0.098125, 0.916242, 0.896091, 0.100717, 0.926106, 0.897330, 0.104071, 0.935904, 0.898570, 0.108131, 0.945636, 0.899815, 0.112838, 0.955300, 0.901065, 0.118128, 0.964894, 0.902323, 0.123941, 0.974417, 0.903590, 0.130215, 0.983868, 0.904867, 0.136897, 0.993248, 0.906157, 0.143936 }; /* internal functions */ static rgb_t hsv_to_rgb(hsv_t * hsv); /* this algorithm is derived from "Computer Graphics: principles and practice" */ /* hue = [0 360], s and v are in [0,1] */ static rgb_t hsv_to_rgb(hsv_t * hsv) { rgb_t rgb; hsv_data_t fraction, p,q,t; gint whole; if (hsv->s == 0.0) /* saturation is zero (on black white line)n */ rgb.r = rgb.g = rgb.b = UCHAR_MAX * hsv->v; /* achromatic case */ else { if (hsv->h == 360.0) hsv->h = 0.0; /* from [0 360] to [0 360) */ whole = floor(hsv->h/60.0); fraction = (hsv->h/60.0) - whole; p = hsv->v*(1.0-hsv->s); q = hsv->v*(1.0-(hsv->s*fraction)); t = hsv->v*(1.0-(hsv->s*(1.0-fraction))); switch(whole) { case 0: rgb.r = UCHAR_MAX * hsv->v; rgb.g = UCHAR_MAX * t; rgb.b = UCHAR_MAX * p; break; case 1: rgb.r = UCHAR_MAX * q; rgb.g = UCHAR_MAX * hsv->v; rgb.b = UCHAR_MAX * p; break; case 2: rgb.r = UCHAR_MAX * p; rgb.g = UCHAR_MAX * hsv->v; rgb.b = UCHAR_MAX * t; break; case 3: rgb.r = UCHAR_MAX * p; rgb.g = UCHAR_MAX * q; rgb.b = UCHAR_MAX * hsv->v; break; case 4: rgb.r = UCHAR_MAX * t; rgb.g = UCHAR_MAX * p; rgb.b = UCHAR_MAX * hsv->v; break; case 5: rgb.r = UCHAR_MAX * hsv->v; rgb.g = UCHAR_MAX * p; rgb.b = UCHAR_MAX * q; break; default: /* should never get here */ rgb.r = rgb.g = rgb.b = 0; break; } } return rgb; } rgba_t amitk_color_table_lookup(amide_data_t datum, AmitkColorTable which, amide_data_t min, amide_data_t max) { rgba_t temp_rgba; rgba_t rgba; rgb_t rgb; hsv_t hsv; amide_data_t scale; amide_data_t temp; gboolean not_a_number=FALSE; unsigned short index = 0; /* if not a number, computer as min value, and then set to transparent */ if (isnan(datum)) { datum = min; not_a_number = TRUE; } switch(which) { case AMITK_COLOR_TABLE_BWB_LINEAR: temp = 2*(datum-min) * 0xFF/(max-min); if (temp > 255) temp = 511-temp; if (temp < 0) temp = 0; rgba.r = temp; rgba.g = temp; rgba.b = temp; rgba.a = temp; break; case AMITK_COLOR_TABLE_WBW_LINEAR: rgba = amitk_color_table_lookup(datum, AMITK_COLOR_TABLE_BWB_LINEAR, min, max); rgba.r = 0xFF-rgba.r; rgba.g = 0xFF-rgba.g; rgba.b = 0xFF-rgba.b; break; case AMITK_COLOR_TABLE_RED_TEMP: /* this may not be exactly right.... */ scale = 0xFF/(max-min); temp = (datum-min)/(max-min); if (temp > 1.0) rgba.r = rgba.g = rgba.b = rgba.a = 0xFF; else if (temp < 0.0) rgba.r = rgba.g = rgba.b = rgba.a = 0; else { rgba.r = temp >= 0.70 ? 0xFF : scale*(datum-min)/0.70; rgba.g = temp >= 0.50 ? 2*scale*(datum-min/2.0-max/2.0) : 0; rgba.b = temp >= 0.50 ? 2*scale*(datum-min/2.0-max/2.0) : 0; rgba.a = 0xFF*temp; } break; case AMITK_COLOR_TABLE_INV_RED_TEMP: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_RED_TEMP, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_BLUE_TEMP: temp_rgba = amitk_color_table_lookup(datum, AMITK_COLOR_TABLE_RED_TEMP, min, max); rgba.r = temp_rgba.b; rgba.g = temp_rgba.g; rgba.b = temp_rgba.r; rgba.a = temp_rgba.a; break; case AMITK_COLOR_TABLE_INV_BLUE_TEMP: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_BLUE_TEMP, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_GREEN_TEMP: temp_rgba = amitk_color_table_lookup(datum, AMITK_COLOR_TABLE_RED_TEMP, min, max); rgba.r = temp_rgba.g; rgba.g = temp_rgba.r; rgba.b = temp_rgba.b; rgba.a = temp_rgba.a; break; case AMITK_COLOR_TABLE_INV_GREEN_TEMP: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_GREEN_TEMP, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_HOT_METAL: /* derived from code in xmedcon (by Erik Nolf) */ temp = ((datum-min)/(max-min)); /* between 0.0 and 1.0 */ if (temp > 1.0) rgba.r = rgba.g = rgba.b = rgba.a = 0xFF; else if (temp < 0.0) rgba.r = rgba.g = rgba.b = rgba.a = 0; else { /* several "magic" numbers are used, i.e. I have no idea how they're derived, but they work..... red: distributed between 0-181 (out of 255) green: distributed between 128-218 (out of 255) blue: distributed between 192-255 (out of 255) */ rgba.r = (temp >= (182.0/255.0)) ? 0xFF : 0xFF*temp*(255.0/182); rgba.g = (temp < (128.0/255.0)) ? 0x00 : ((temp >= (219.0/255.0)) ? 0xFF : 0xFF*(temp-128.0/255.0)*(255.0/91.0)); rgba.b = (temp >= (192.0/255.0)) ? 0xFF*(temp-192.0/255)*(255.0/63.0) : 0x00 ; rgba.a = 0xFF*temp; } break; case AMITK_COLOR_TABLE_INV_HOT_METAL: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_HOT_METAL, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_HOT_METAL_CONTOUR: temp = 2*(datum-min) * 0xFF/(max-min); if (temp > 255) temp = 511-temp; if (temp < 0) temp = 0; rgba = amitk_color_table_lookup(temp, AMITK_COLOR_TABLE_HOT_METAL, 0, 255); break; case AMITK_COLOR_TABLE_INV_HOT_METAL_CONTOUR: temp = 2*(datum-min) * 0xFF/(max-min); if (temp > 255) temp = 511-temp; if (temp < 0) temp = 0; rgba = amitk_color_table_lookup(temp, AMITK_COLOR_TABLE_INV_HOT_METAL, 0, 255); break; case AMITK_COLOR_TABLE_HOT_BLUE: temp_rgba = amitk_color_table_lookup(datum, AMITK_COLOR_TABLE_HOT_METAL, min, max); rgba.r = temp_rgba.b; rgba.g = temp_rgba.g; rgba.b = temp_rgba.r; rgba.a = temp_rgba.a; break; case AMITK_COLOR_TABLE_INV_HOT_BLUE: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_HOT_BLUE, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_HOT_GREEN: temp_rgba = amitk_color_table_lookup(datum, AMITK_COLOR_TABLE_HOT_METAL, min, max); rgba.r = temp_rgba.g; rgba.g = temp_rgba.r; rgba.b = temp_rgba.b; rgba.a = temp_rgba.a; break; case AMITK_COLOR_TABLE_INV_HOT_GREEN: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_HOT_GREEN, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_SPECTRUM: temp = ((datum-min)/(max-min)); hsv.s = 1.0; hsv.v = 1.0; if (temp > 1.0) { hsv.h = 360.0; rgba.a = 0xFF; } else if (temp < 0.0) { hsv.h = 0.0; rgba.a = 0; } else { hsv.h = 360.0*temp; rgba.a = 0xFF*temp; } rgb = hsv_to_rgb(&hsv); rgba.r = rgb.r; rgba.g = rgb.g; rgba.b = rgb.b; break; case AMITK_COLOR_TABLE_INV_SPECTRUM: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_SPECTRUM, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_NIH: /* this algorithm is a complete guess, don't trust it */ temp = ((datum-min)/(max-min)); hsv.s = 1.0; if (temp < 0.0) hsv.v = 0.0; else if (temp > 0.2) hsv.v = 1.0; else hsv.v = 5*temp; if (temp > 1.0) { hsv.h = 0.0; rgba.a = 0xFF; } else if (temp < 0.0) { hsv.h = 300.0; rgba.a = 0; } else { hsv.h = 300.0*(1.0-temp); rgba.a = 0xFF*temp; } rgb = hsv_to_rgb(&hsv); rgba.r = rgb.r; rgba.g = rgb.g; rgba.b = rgb.b; break; case AMITK_COLOR_TABLE_INV_NIH: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_NIH, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_NIH_WHITE: /* this algorithm is a complete guess, don't trust it */ temp = ((datum-min)/(max-min)); hsv.s = 1.0; if (temp < 0.0) hsv.v = 0.0; else if (temp > 0.2) hsv.v = 1.0; else hsv.v = 5*temp; if (temp > 1.0) { hsv.s = hsv.h = 0.0; rgba.a = 0xFF; } else if (temp < 0.0) { hsv.h = 300.0; rgba.a = 0; } else { hsv.h = 300.0*(1.0-temp); rgba.a = 0xFF * temp; } rgb = hsv_to_rgb(&hsv); rgba.r = rgb.r; rgba.g = rgb.g; rgba.b = rgb.b; break; case AMITK_COLOR_TABLE_INV_NIH_WHITE: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_NIH_WHITE, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_VIRIDIS: temp = ((datum-min)/(max-min)); /* between 0.0 and 1.0 */ if (temp >= 1.0) index = 255; else if (temp < 0.0) index = 0; else index = temp * 256; rgba.r = 0xFF * kViridis[index*3]; rgba.g = 0xFF * kViridis[index*3+1]; rgba.b = 0xFF * kViridis[index*3+2]; rgba.a = index; break; case AMITK_COLOR_TABLE_INV_VIRIDIS: temp = ((datum-min)/(max-min)); /* between 0.0 and 1.0 */ unsigned short index = 0; if (temp >= 1.0) index = 255; else if (temp < 0.0) index = 0; else index = temp * 256; index = 255 - index; rgba.r = 0xFF * kViridis[index*3]; rgba.g = 0xFF * kViridis[index*3+1]; rgba.b = 0xFF * kViridis[index*3+2]; rgba.a = index; break; case AMITK_COLOR_TABLE_WB_LINEAR: rgba = amitk_color_table_lookup((max-datum)+min, AMITK_COLOR_TABLE_BW_LINEAR, min, max); rgba.a = 0xFF-rgba.a; break; case AMITK_COLOR_TABLE_BW_LINEAR: default: temp = (datum-min) * 0xFF/(max-min); if (temp > 255) temp = 255; else if (temp < 0) temp = 0; rgba.r = temp; rgba.g = temp; rgba.b = temp; rgba.a = temp; break; } if (not_a_number) rgba.a = 0; return rgba; } rgba_t amitk_color_table_uint32_to_rgba(guint32 color_uint32) { rgba_t rgba; rgba.r = (color_uint32 >> 24) & 0x000000FF; rgba.g = (color_uint32 >> 16) & 0x000000FF; rgba.b = (color_uint32 >> 8) & 0x000000FF; rgba.a = (color_uint32 >> 0) & 0x000000FF; return rgba; } rgba_t amitk_color_table_outline_color(AmitkColorTable which, gboolean highlight) { rgba_t rgba, normal_rgba, highlight_rgba; switch(which) { case AMITK_COLOR_TABLE_RED_TEMP: case AMITK_COLOR_TABLE_INV_RED_TEMP: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0x00; normal_rgba.g = 0xFF; normal_rgba.b = 0x80; highlight_rgba.r = 0x00; highlight_rgba.g = 0xFF; highlight_rgba.b = 0xFF; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_BLUE_TEMP: case AMITK_COLOR_TABLE_INV_BLUE_TEMP: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0xFF; normal_rgba.g = 0x80; normal_rgba.b = 0x00; highlight_rgba.r = 0xFF; highlight_rgba.g = 0xFF; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_GREEN_TEMP: case AMITK_COLOR_TABLE_INV_GREEN_TEMP: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0x00; normal_rgba.g = 0x80; normal_rgba.b = 0xFF; highlight_rgba.r = 0xFF; highlight_rgba.g = 0x00; highlight_rgba.b = 0xFF; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_HOT_METAL: case AMITK_COLOR_TABLE_INV_HOT_METAL: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0x00; normal_rgba.g = 0xFF; normal_rgba.b = 0x80; highlight_rgba.r = 0x00; highlight_rgba.g = 0xFF; highlight_rgba.b = 0xFF; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_HOT_METAL_CONTOUR: case AMITK_COLOR_TABLE_INV_HOT_METAL_CONTOUR: normal_rgba = amitk_color_table_lookup(0.5, which, 0.0,1.0); normal_rgba.r = 0x00; normal_rgba.g = 0xFF; normal_rgba.b = 0x80; highlight_rgba.r = 0x00; highlight_rgba.g = 0xFF; highlight_rgba.b = 0xFF; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_HOT_BLUE: case AMITK_COLOR_TABLE_INV_HOT_BLUE: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0xFF; normal_rgba.g = 0x80; normal_rgba.b = 0x00; highlight_rgba.r = 0xFF; highlight_rgba.g = 0xFF; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_HOT_GREEN: case AMITK_COLOR_TABLE_INV_HOT_GREEN: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0x80; normal_rgba.g = 0x00; normal_rgba.b = 0xFF; highlight_rgba.r = 0xFF; highlight_rgba.g = 0x00; highlight_rgba.b = 0xFF; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_SPECTRUM: case AMITK_COLOR_TABLE_INV_SPECTRUM: normal_rgba.r = normal_rgba.g = normal_rgba.b = normal_rgba.a = 0xFF; highlight_rgba.r = highlight_rgba.g = highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_NIH: case AMITK_COLOR_TABLE_INV_NIH: normal_rgba.r = normal_rgba.g = normal_rgba.b = normal_rgba.a = 0xFF; highlight_rgba.r = 0xFF; highlight_rgba.g = 0x80; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_NIH_WHITE: case AMITK_COLOR_TABLE_INV_NIH_WHITE: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); highlight_rgba.r = 0xFF; highlight_rgba.g = 0x80; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_WBW_LINEAR: normal_rgba = amitk_color_table_lookup(0.5, which, 0.0,1.0); normal_rgba.r = 0xFF; normal_rgba.g = 0x00; normal_rgba.b = 0x00; highlight_rgba.r = 0xF0; highlight_rgba.g = 0xF0; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_WB_LINEAR: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0xFF; normal_rgba.g = 0x00; normal_rgba.b = 0x00; highlight_rgba.r = 0xF0; highlight_rgba.g = 0xF0; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_BWB_LINEAR: normal_rgba = amitk_color_table_lookup(0.5, which, 0.0,1.0); normal_rgba.r = 0xFF; normal_rgba.g = 0x00; normal_rgba.b = 0x00; highlight_rgba.r = 0xFF; highlight_rgba.g = 0xFF; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; case AMITK_COLOR_TABLE_BW_LINEAR: default: normal_rgba = amitk_color_table_lookup(1.0, which, 0.0,1.0); normal_rgba.r = 0xFF; normal_rgba.g = 0x00; normal_rgba.b = 0x00; highlight_rgba.r = 0xFF; highlight_rgba.g = 0xFF; highlight_rgba.b = 0x00; highlight_rgba.a = normal_rgba.a; break; } if (highlight) rgba = highlight_rgba; else rgba = normal_rgba; return rgba; } const gchar * amitk_color_table_get_name(const AmitkColorTable which) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_COLOR_TABLE); enum_value = g_enum_get_value(enum_class, which); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_color_table.h000066400000000000000000000060511423227705100217530ustar00rootroot00000000000000/* amitk_color_table.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __COLOR_TABLE_H__ #define __COLOR_TABLE_H__ /* header files that are always associated with this header file */ #include "amitk_type.h" G_BEGIN_DECLS /* typedef's */ typedef enum { AMITK_COLOR_TABLE_BW_LINEAR, AMITK_COLOR_TABLE_WB_LINEAR, AMITK_COLOR_TABLE_BWB_LINEAR, AMITK_COLOR_TABLE_WBW_LINEAR, AMITK_COLOR_TABLE_RED_TEMP, AMITK_COLOR_TABLE_INV_RED_TEMP, AMITK_COLOR_TABLE_BLUE_TEMP, AMITK_COLOR_TABLE_INV_BLUE_TEMP, AMITK_COLOR_TABLE_GREEN_TEMP, AMITK_COLOR_TABLE_INV_GREEN_TEMP, AMITK_COLOR_TABLE_HOT_METAL, AMITK_COLOR_TABLE_INV_HOT_METAL, AMITK_COLOR_TABLE_HOT_METAL_CONTOUR, AMITK_COLOR_TABLE_INV_HOT_METAL_CONTOUR, AMITK_COLOR_TABLE_HOT_BLUE, AMITK_COLOR_TABLE_INV_HOT_BLUE, AMITK_COLOR_TABLE_HOT_GREEN, AMITK_COLOR_TABLE_INV_HOT_GREEN, AMITK_COLOR_TABLE_SPECTRUM, AMITK_COLOR_TABLE_INV_SPECTRUM, AMITK_COLOR_TABLE_NIH_WHITE, AMITK_COLOR_TABLE_INV_NIH_WHITE, AMITK_COLOR_TABLE_NIH, AMITK_COLOR_TABLE_INV_NIH, AMITK_COLOR_TABLE_VIRIDIS, AMITK_COLOR_TABLE_INV_VIRIDIS, AMITK_COLOR_TABLE_NUM } AmitkColorTable; #define AMITK_OBJECT_DEFAULT_COLOR 0x808000FF typedef guint8 color_data_t; typedef guint16 color_data16_t; typedef gdouble hsv_data_t; typedef struct rgba_t { color_data_t r; color_data_t g; color_data_t b; color_data_t a; } rgba_t; typedef struct rgba16_t { color_data16_t r; color_data16_t g; color_data16_t b; color_data16_t a; } rgba16_t; typedef struct rgb_t { color_data_t r; color_data_t g; color_data_t b; } rgb_t; typedef struct hsv_t { hsv_data_t h; hsv_data_t s; hsv_data_t v; } hsv_t; /* defines */ #define amitk_color_table_rgba_to_uint32(rgba) (((rgba).r<<24) | ((rgba).g<<16) | ((rgba).b<<8) | ((rgba).a<<0)) /* external functions */ rgba_t amitk_color_table_uint32_to_rgba(guint32 color_uint32); rgba_t amitk_color_table_outline_color(AmitkColorTable which, gboolean highlight); rgba_t amitk_color_table_lookup(amide_data_t datum, AmitkColorTable which, amide_data_t min, amide_data_t max); const gchar * amitk_color_table_get_name(const AmitkColorTable which); /* external variables */ extern gchar * color_table_menu_names[]; G_END_DECLS #endif /* __COLOR_TABLE_H__ */ amide-1.0.6/amide-current/src/amitk_color_table_menu.c000066400000000000000000000072131423227705100227730ustar00rootroot00000000000000/* amitk_color_table_menu.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "amitk_color_table_menu.h" #include "image.h" #define MENU_COLOR_SCALE_HEIGHT 8 #define MENU_COLOR_SCALE_WIDTH 30 static void color_table_menu_class_init (AmitkColorTableMenuClass *klass); static void color_table_menu_init (AmitkColorTableMenu *menu); //static GtkComboBoxClass *parent_class; static GtkComboBoxClass *parent_class; GType amitk_color_table_menu_get_type (void) { static GType color_table_menu_type = 0; if (!color_table_menu_type) { static const GTypeInfo color_table_menu_info = { sizeof (AmitkColorTableMenuClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) color_table_menu_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkColorTableMenu), 0, /* # preallocs */ (GInstanceInitFunc) color_table_menu_init, NULL /* value table */ }; color_table_menu_type = g_type_register_static(GTK_TYPE_COMBO_BOX, "AmitkColorTableMenu", &color_table_menu_info, 0); } return color_table_menu_type; } static void color_table_menu_class_init (AmitkColorTableMenuClass *klass) { parent_class = g_type_class_peek_parent(klass); } static void color_table_menu_init (AmitkColorTableMenu * ct_menu) { GtkCellRenderer *renderer; GdkPixbuf *pixbuf; GtkTreeIter iter; GtkListStore *store; AmitkColorTable i_color_table; /* create the store of data */ store = gtk_list_store_new(2, /* NUM_COLUMNS */ GDK_TYPE_PIXBUF, G_TYPE_STRING); for(i_color_table=0; i_color_table */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_COLOR_TABLE_MENU__ #define __AMITK_COLOR_TABLE_MENU_H__ /* includes we always need with this widget */ #include #include "amitk_color_table.h" G_BEGIN_DECLS #define AMITK_TYPE_COLOR_TABLE_MENU (amitk_color_table_menu_get_type ()) #define AMITK_COLOR_TABLE_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_COLOR_TABLE_MENU, AmitkColorTableMenu)) #define AMITK_COLOR_TABLE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_COLOR_TABLE_MENU, AmitkColorTableMenuClass)) #define AMITK_IS_COLOR_TABLE_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_COLOR_TABLE_MENU)) #define AMITK_IS_COLOR_TABLE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_COLOR_TABLE_MENU)) #define AMITK_COLOR_TABLE_MENU_COLOR_TABLE(obj) (AMITK_COLOR_TABLE_MENU(obj)->color_table) typedef struct _AmitkColorTableMenu AmitkColorTableMenu; typedef struct _AmitkColorTableMenuClass AmitkColorTableMenuClass; struct _AmitkColorTableMenu { GtkComboBox combo_box; }; struct _AmitkColorTableMenuClass { GtkComboBoxClass parent_class; }; GType amitk_color_table_menu_get_type (void); GtkWidget* amitk_color_table_menu_new (); G_END_DECLS #endif /* __AMITK_COLOR_TABLE_MENU_H__ */ amide-1.0.6/amide-current/src/amitk_common.c000066400000000000000000000254251423227705100207570ustar00rootroot00000000000000/* amitk_common.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2004-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" //#include //#include //#include #include #include #include #include "amitk_type_builtins.h" #include "amitk_common.h" /* external variables */ gchar * amitk_limit_names[AMITK_THRESHOLD_STYLE_NUM][AMITK_LIMIT_NUM] = { { N_("Min"), N_("Max") }, { N_("Center"), N_("Width") } }; gchar * amitk_window_names[] = { // N_("Bone"), // N_("Soft Tissue") N_("Abdomen"), N_("Brain"), N_("Extremities"), N_("Liver"), N_("Lung"), N_("Pelvis, soft tissue"), N_("Skull Base"), N_("Spine A"), N_("Spine B"), N_("Thorax, soft tissue") }; /* external variables */ PangoFontDescription * amitk_fixed_font_desc; void amitk_common_font_init(void) { #if defined (G_PLATFORM_WIN32) amitk_fixed_font_desc = pango_font_description_from_string("Tahoma 10"); #else amitk_fixed_font_desc = pango_font_description_from_string("Monospace 9"); #endif /* actually, these fonts aren't fixed width... but it's what I've been using */ // amitk_fixed_font_desc = pango_font_description_from_string("Sans 9"); // amitk_fixed_font_desc = pango_font_description_from_string("-*-helvetica-medium-r-normal-*-*-120-*-*-*-*-*-*"); return; } /* little utility function, appends str to pstr, handles case of pstr pointing to NULL */ void amitk_append_str_with_newline(gchar ** pstr, const gchar * format, ...) { va_list args; gchar * temp_str; gchar * error_str; if (pstr == NULL) return; va_start (args, format); error_str = g_strdup_vprintf(format, args); va_end (args); if (*pstr != NULL) { temp_str = g_strdup_printf("%s\n%s", *pstr, error_str); g_free(*pstr); *pstr = temp_str; } else { *pstr = g_strdup(error_str); } g_free(error_str); } void amitk_append_str(gchar ** pstr, const gchar * format, ...) { va_list args; gchar * temp_str; gchar * error_str; if (pstr == NULL) return; va_start (args, format); error_str = g_strdup_vprintf(format, args); va_end (args); if (*pstr != NULL) { temp_str = g_strdup_printf("%s%s", *pstr, error_str); g_free(*pstr); *pstr = temp_str; } else { *pstr = g_strdup(error_str); } g_free(error_str); } /* this function's use is a bit of a cludge GTK typically uses %f for changing a float to text to display in a table Here we overwrite the typical conversion with a %g conversion */ void amitk_real_cell_data_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { gdouble value; gchar *text; gint column = GPOINTER_TO_INT(data); /* Get the double value from the model. */ gtk_tree_model_get (tree_model, iter, column, &value, -1); /* Now we can format the value ourselves. */ text = g_strdup_printf ("%g", value); g_object_set (cell, "text", text, NULL); g_free (text); return; } gint amitk_spin_button_scientific_output (GtkSpinButton *spin_button, gpointer data) { gchar *buf = g_strdup_printf ("%g", spin_button->adjustment->value); if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button)))) gtk_entry_set_text (GTK_ENTRY (spin_button), buf); g_free (buf); return TRUE; /* non-zero forces the default output function not to run */ } /* this function exists, because double or triple clicking on the arrows in a spin button goes into an endless loop if that spin button is in a toolbar, at least in gtk as of version 2.24.22. */ gint amitk_spin_button_discard_double_or_triple_click(GtkWidget *widget, GdkEventButton *event, gpointer func_data) { if ((event->type==GDK_2BUTTON_PRESS || event->type==GDK_3BUTTON_PRESS)) return TRUE; else return FALSE; } /* The following function should return a pixbuf representing the currently shown data on the canvas (within the specified height/width at the given offset). -The code is based on gnome_canvas_paint_rect in gnome-canvas.c */ GdkPixbuf * amitk_get_pixbuf_from_canvas(GnomeCanvas * canvas, gint xoffset, gint yoffset, gint width, gint height) { GdkPixbuf * pixbuf; if (canvas->aa) { GnomeCanvasBuf buf; GdkColor *color; guchar * px; px = g_new (guchar, width*height * 3); buf.buf = px; buf.buf_rowstride = width * 3; buf.rect.x0 = xoffset; buf.rect.y0 = yoffset; buf.rect.x1 = xoffset+width; buf.rect.y1 = yoffset+height; color = >K_WIDGET(canvas)->style->bg[GTK_STATE_NORMAL]; buf.bg_color = (((color->red & 0xff00) << 8) | (color->green & 0xff00) | (color->blue >> 8)); buf.is_bg = 1; buf.is_buf = 0; /* render the background */ if ((* GNOME_CANVAS_GET_CLASS(canvas)->render_background) != NULL) (* GNOME_CANVAS_GET_CLASS(canvas)->render_background) (canvas, &buf); /* render the rest */ if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE) (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->render) (canvas->root, &buf); if (buf.is_bg) { g_warning("No code written to implement case buf.is_bg: %s at %d\n", __FILE__, __LINE__); pixbuf = NULL; } else { pixbuf = gdk_pixbuf_new_from_data(buf.buf, GDK_COLORSPACE_RGB, FALSE, 8, width, height,width*3, NULL, NULL); } } else { GdkPixmap * pixmap; pixmap = gdk_pixmap_new (canvas->layout.bin_window, width, height, gtk_widget_get_visual (GTK_WIDGET(canvas))->depth); /* draw the background */ (* GNOME_CANVAS_GET_CLASS(canvas)->draw_background) (canvas, pixmap, xoffset, yoffset, width, height); /* force a draw onto the pixmap */ (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->draw) (canvas->root, pixmap,xoffset, yoffset, width, height); /* transfer to a pixbuf */ pixbuf = gdk_pixbuf_get_from_drawable (NULL,GDK_DRAWABLE(pixmap),NULL,0,0,0,0,-1,-1); g_object_unref(pixmap); } return pixbuf; } gboolean amitk_is_xif_directory(const gchar * filename, gboolean * plegacy1, gchar ** pxml_filename) { struct stat file_info; gchar * temp_str; DIR * directory; struct dirent * directory_entry; gchar *xifname; gint length; /* remove any trailing directory characters */ length = strlen(filename); if ((length >= 1) && (strcmp(filename+length-1, G_DIR_SEPARATOR_S) == 0)) length--; xifname = g_strndup(filename, length); if (stat(xifname, &file_info) != 0) return FALSE; /* file doesn't exist */ if (!S_ISDIR(file_info.st_mode)) return FALSE; /* check for legacy .xif file (< 2.0 version) */ temp_str = g_strdup_printf("%s%sStudy.xml", xifname, G_DIR_SEPARATOR_S); if (stat(temp_str, &file_info) == 0) { if (plegacy1 != NULL) *plegacy1 = TRUE; if (pxml_filename != NULL) *pxml_filename = temp_str; else g_free(temp_str); return TRUE; } g_free(temp_str); /* figure out the name of the study file */ directory = opendir(xifname); /* currently, only looks at the first study_*.xml file... there should be only one anyway */ if (directory != NULL) { while (((directory_entry = readdir(directory)) != NULL)) if (g_pattern_match_simple("study_*.xml", directory_entry->d_name)) { if (plegacy1 != NULL) *plegacy1 = FALSE; if (pxml_filename != NULL) *pxml_filename = g_strdup(directory_entry->d_name); closedir(directory); return TRUE; } } closedir(directory); return FALSE; } gboolean amitk_is_xif_flat_file(const gchar * filename, guint64 * plocation_le, guint64 *psize_le) { struct stat file_info; FILE * study_file; guint64 location_le, size_le; gchar magic[64]; if (stat(filename, &file_info) != 0) return FALSE; /* file doesn't exist */ if (S_ISDIR(file_info.st_mode)) return FALSE; /* Note, "rb" is same as "r" on Unix, but not in Windows */ if ((study_file = fopen(filename, "rb")) == NULL) return FALSE; /* check magic string */ size_t nRead; nRead = fread(magic, sizeof(gchar), 64, study_file); if (strncmp(magic, AMITK_FLAT_FILE_MAGIC_STRING, strlen(AMITK_FLAT_FILE_MAGIC_STRING)) != 0 || nRead != 64) { fclose(study_file); return FALSE; } /* get area of file to read for initial XML data */ nRead = fread(&location_le, sizeof(guint64), 1, study_file); if (nRead != 1) { fclose(study_file); return FALSE; } nRead = fread(&size_le, sizeof(guint64), 1, study_file); if (nRead != 1) { fclose(study_file); return FALSE; } if (plocation_le != NULL) *plocation_le = location_le; if (psize_le != NULL) *psize_le = size_le; fclose(study_file); return TRUE; } const gchar * amitk_layout_get_name(const AmitkLayout layout) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_LAYOUT); enum_value = g_enum_get_value(enum_class, layout); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_panel_layout_get_name(const AmitkPanelLayout panel_layout) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_PANEL_LAYOUT); enum_value = g_enum_get_value(enum_class, panel_layout); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_limit_get_name(const AmitkLimit limit) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_LIMIT); enum_value = g_enum_get_value(enum_class, limit); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_window_get_name (const AmitkWindow window) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_WINDOW); enum_value = g_enum_get_value(enum_class, window); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_modality_get_name(const AmitkModality modality) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_MODALITY); enum_value = g_enum_get_value(enum_class, modality); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_common.h000066400000000000000000000122511423227705100207550ustar00rootroot00000000000000/* amitk_common.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2004-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_COMMON_H__ #define __AMITK_COMMON_H__ /* header files that are always needed with this file */ #include #include #include "amide_intl.h" G_BEGIN_DECLS #define AMITK_RESPONSE_EXECUTE 1 #define AMITK_RESPONSE_COPY 2 #define AMITK_RESPONSE_SAVE_AS 3 #define AMITK_RESPONSE_SAVE_RAW_AS 4 /* defines how many times we want the progress bar to be updated over the course of an action */ #define AMITK_UPDATE_DIVIDER 40.0 /* must be float point */ /* file info. magic string needs to be < 64 bytes */ #define AMITK_FILE_VERSION (xmlChar *) "2.0" #define AMITK_FLAT_FILE_MAGIC_STRING "AMIDE XML Image Format Flat File" /* typedef's */ /* layout of the three views in a canvas */ typedef enum { AMITK_LAYOUT_LINEAR, AMITK_LAYOUT_ORTHOGONAL, AMITK_LAYOUT_NUM } AmitkLayout; /* layout of multiple canvases */ typedef enum { AMITK_PANEL_LAYOUT_MIXED, AMITK_PANEL_LAYOUT_LINEAR_X, AMITK_PANEL_LAYOUT_LINEAR_Y, AMITK_PANEL_LAYOUT_NUM } AmitkPanelLayout; typedef enum { AMITK_VIEW_MODE_SINGLE, AMITK_VIEW_MODE_LINKED_2WAY, AMITK_VIEW_MODE_LINKED_3WAY, AMITK_VIEW_MODE_NUM } AmitkViewMode; typedef enum { AMITK_MODALITY_PET, AMITK_MODALITY_SPECT, AMITK_MODALITY_CT, AMITK_MODALITY_MRI, AMITK_MODALITY_OTHER, AMITK_MODALITY_NUM } AmitkModality; typedef enum { AMITK_LIMIT_MIN, AMITK_LIMIT_MAX, AMITK_LIMIT_NUM } AmitkLimit; // AMITK_WINDOW_BONE, // AMITK_WINDOW_SOFT_TISSUE, typedef enum { AMITK_WINDOW_ABDOMEN, AMITK_WINDOW_BRAIN, AMITK_WINDOW_EXTREMITIES, AMITK_WINDOW_LIVER, AMITK_WINDOW_LUNG, AMITK_WINDOW_PELVIS_SOFT_TISSUE, AMITK_WINDOW_SKULL_BASE, AMITK_WINDOW_SPINE_A, AMITK_WINDOW_SPINE_B, AMITK_WINDOW_THORAX_SOFT_TISSUE, AMITK_WINDOW_NUM } AmitkWindow; typedef enum { AMITK_THRESHOLD_STYLE_MIN_MAX, AMITK_THRESHOLD_STYLE_CENTER_WIDTH, AMITK_THRESHOLD_STYLE_NUM } AmitkThresholdStyle; typedef enum { AMITK_HELP_INFO_BLANK, AMITK_HELP_INFO_CANVAS_DATA_SET, AMITK_HELP_INFO_CANVAS_ROI, AMITK_HELP_INFO_CANVAS_FIDUCIAL_MARK, AMITK_HELP_INFO_CANVAS_STUDY, AMITK_HELP_INFO_CANVAS_ISOCONTOUR_ROI, AMITK_HELP_INFO_CANVAS_FREEHAND_ROI, AMITK_HELP_INFO_CANVAS_DRAWING_MODE, AMITK_HELP_INFO_CANVAS_LINE_PROFILE, AMITK_HELP_INFO_CANVAS_NEW_ROI, AMITK_HELP_INFO_CANVAS_NEW_ISOCONTOUR_ROI, AMITK_HELP_INFO_CANVAS_NEW_FREEHAND_ROI, AMITK_HELP_INFO_CANVAS_CHANGE_ISOCONTOUR, AMITK_HELP_INFO_CANVAS_SHIFT_OBJECT, AMITK_HELP_INFO_CANVAS_ROTATE_OBJECT, AMITK_HELP_INFO_TREE_VIEW_DATA_SET, AMITK_HELP_INFO_TREE_VIEW_ROI, AMITK_HELP_INFO_TREE_VIEW_FIDUCIAL_MARK, AMITK_HELP_INFO_TREE_VIEW_STUDY, AMITK_HELP_INFO_TREE_VIEW_NONE, AMITK_HELP_INFO_UPDATE_LOCATION, AMITK_HELP_INFO_UPDATE_THETA, AMITK_HELP_INFO_UPDATE_SHIFT, AMITK_HELP_INFO_NUM } AmitkHelpInfo; /* external variables */ extern gchar * amitk_limit_names[AMITK_THRESHOLD_STYLE_NUM][AMITK_LIMIT_NUM]; extern gchar * amitk_window_names[AMITK_WINDOW_NUM]; extern PangoFontDescription * amitk_fixed_font_desc; /* external functions */ void amitk_common_font_init(void); void amitk_append_str_with_newline(gchar ** pstr, const gchar * format, ...); void amitk_append_str(gchar ** pstr, const gchar * format, ...); void amitk_real_cell_data_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); gint amitk_spin_button_scientific_output (GtkSpinButton *spin_button, gpointer data); gint amitk_spin_button_discard_double_or_triple_click(GtkWidget *widget, GdkEventButton *event, gpointer func_data); GdkPixbuf * amitk_get_pixbuf_from_canvas(GnomeCanvas * canvas, gint xoffset, gint yoffset, gint width, gint height); gboolean amitk_is_xif_directory(const gchar * filename, gboolean * plegacy, gchar ** pxml_filename); gboolean amitk_is_xif_flat_file(const gchar * filename, guint64 * plocation_le, guint64 *psize_le); /* built in type functions */ const gchar * amitk_layout_get_name (const AmitkLayout layout); const gchar * amitk_panel_layout_get_name (const AmitkPanelLayout panel_layout); const gchar * amitk_limit_get_name (const AmitkLimit limit); const gchar * amitk_window_get_name (const AmitkWindow window); const gchar * amitk_modality_get_name (const AmitkModality modality); G_END_DECLS #endif /* __AMITK_COMMON_H__ */ amide-1.0.6/amide-current/src/amitk_data_set.c000066400000000000000000007111671423227705100212600ustar00rootroot00000000000000/* amitk_data_set.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_data_set.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "amitk_line_profile.h" /* variable type function declarations */ #include "amitk_data_set_UBYTE_0D_SCALING.h" #include "amitk_data_set_UBYTE_1D_SCALING.h" #include "amitk_data_set_UBYTE_2D_SCALING.h" #include "amitk_data_set_SBYTE_0D_SCALING.h" #include "amitk_data_set_SBYTE_1D_SCALING.h" #include "amitk_data_set_SBYTE_2D_SCALING.h" #include "amitk_data_set_USHORT_0D_SCALING.h" #include "amitk_data_set_USHORT_1D_SCALING.h" #include "amitk_data_set_USHORT_2D_SCALING.h" #include "amitk_data_set_SSHORT_0D_SCALING.h" #include "amitk_data_set_SSHORT_1D_SCALING.h" #include "amitk_data_set_SSHORT_2D_SCALING.h" #include "amitk_data_set_UINT_0D_SCALING.h" #include "amitk_data_set_UINT_1D_SCALING.h" #include "amitk_data_set_UINT_2D_SCALING.h" #include "amitk_data_set_SINT_0D_SCALING.h" #include "amitk_data_set_SINT_1D_SCALING.h" #include "amitk_data_set_SINT_2D_SCALING.h" #include "amitk_data_set_FLOAT_0D_SCALING.h" #include "amitk_data_set_FLOAT_1D_SCALING.h" #include "amitk_data_set_FLOAT_2D_SCALING.h" #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include "amitk_data_set_DOUBLE_1D_SCALING.h" #include "amitk_data_set_DOUBLE_2D_SCALING.h" #include #include #include #include #ifdef AMIDE_DEBUG #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include "raw_data_import.h" #include "dcmtk_interface.h" #include "libecat_interface.h" #include "libmdc_interface.h" #include "vistaio_interface.h" //#define SLICE_TIMING #undef SLICE_TIMING /* external variables */ AmitkColorTable amitk_modality_default_color_table[AMITK_MODALITY_NUM] = { AMITK_COLOR_TABLE_NIH, /* PET */ AMITK_COLOR_TABLE_HOT_METAL, /* SPECT */ AMITK_COLOR_TABLE_BW_LINEAR, /* CT */ AMITK_COLOR_TABLE_BW_LINEAR, /* MRI */ AMITK_COLOR_TABLE_BW_LINEAR /* OTHER */ }; const gchar * amitk_interpolation_explanations[AMITK_INTERPOLATION_NUM] = { N_("interpolate using nearest neighbor (fast)"), N_("interpolate using trilinear interpolation (slow)"), }; const gchar * amitk_rendering_explanation = N_("How data is aggregated, most important for thick slices. MPR (multiplanar reformation) combines by averaging. MIP (maximum intensity projection) combines by taking the maximum. MINIP (minimum intensity projection) combines by taking the minimum"); const gchar * amitk_import_menu_names[] = { "", /* place holder for AMITK_IMPORT_METHOD_GUESS */ N_("_Raw Data"), #ifdef AMIDE_LIBDCMDATA_SUPPORT N_("_DICOM via dcmtk"), #endif #ifdef AMIDE_LIBECAT_SUPPORT N_("_ECAT 6/7 via libecat"), #endif #ifdef AMIDE_VISTAIO_SUPPORT N_("_Vista image"), #endif #ifdef AMIDE_LIBMDC_SUPPORT "" /* place holder for AMITK_IMPORT_METHOD_LIBMDC */ #endif }; const gchar * amitk_import_menu_explanations[] = { "", N_("Import file as raw data"), #ifdef AMIDE_LIBDCMDATA_SUPPORT N_("Import a DICOM file or directory file using the DCMTK library"), #endif #ifdef AMIDE_LIBECAT_SUPPORT N_("Import a CTI 6.4 or 7.0 file using the libecat library"), #endif #ifdef AMIDE_VISTAIO_SUPPORT N_("Import images from a vista file"), #endif #ifdef AMIDE_LIBMDC_SUPPORT N_("Import via the (X)medcon library (libmdc)"), #endif }; const gchar * amitk_export_menu_names[] = { N_("Raw Data"), #ifdef AMIDE_LIBDCMDATA_SUPPORT N_("DICOM via dcmtk"), #endif #ifdef AMIDE_LIBMDC_SUPPORT "" /* place holder for AMITK_EXPORT_METHOD_LIBMDC */ #endif }; const gchar * amitk_export_menu_explanations[] = { N_("Export file as raw data"), #ifdef AMIDE_LIBDCMDATA_SUPPORT N_("Export a DICOM file or directory file using the DCMTK library"), #endif #ifdef AMIDE_LIBMDC_SUPPORT N_("Export via the (X)medcon library (libmdc)"), #endif }; const gchar * amitk_conversion_names[] = { N_("Direct"), N_("%ID/cc"), N_("SUV") }; const gchar * amitk_dose_unit_names[] = { N_("MBq"), N_("mCi"), N_("uCi"), N_("nCi") }; const gchar * amitk_weight_unit_names[] = { N_("Kg"), N_("g"), N_("lbs"), N_("ounces"), }; const gchar * amitk_cylinder_unit_names[] = { N_("MBq/cc/Image Units"), N_("mCi/cc/Image Units"), N_("uCi/cc/Image Units"), N_("nCi/cc/Image Units"), N_("Image Units/(MBq/cc)"), N_("Image Units/(mCi/cc)"), N_("Image Units/(uCi/cc)"), N_("Image Units/(nCi/cc)"), }; const gchar * amitk_scaling_menu_names[] = { N_("Single Scale Factor"), N_("Per Frame Scale Factor"), N_("Per Plane Scale Factor"), N_("Single Scale Factor with Intercept"), N_("Per Frame Scale Factor with Intercept"), N_("Per Plane Scale Factor with Intercept") }; amide_data_t amitk_window_default[AMITK_WINDOW_NUM][AMITK_LIMIT_NUM] = { // {-800.0, 1200.0}, /* bone */ // {-200.0, 200.0} /* tissue */ {-85.0, 165.0}, /* abdomen */ {-0.0, 80.0}, /* brain */ {-400.0, 1000.0}, /* extremities */ {-40.0, 160.0}, /* liver */ {-1350.0, 150.0}, /* lung */ {-140.0, 210.0}, /* pelvis, soft tissue */ {-60.0, 140.0}, /* skull base */ {-35.0, 215.0}, /* spine a */ {-300.0, 1200.0}, /* spine b */ {-125.0, 225.0} /* thorax, soft tissue */ }; enum { THRESHOLDING_CHANGED, THRESHOLD_STYLE_CHANGED, THRESHOLDS_CHANGED, WINDOWS_CHANGED, COLOR_TABLE_CHANGED, COLOR_TABLE_INDEPENDENT_CHANGED, INTERPOLATION_CHANGED, RENDERING_CHANGED, SUBJECT_ORIENTATION_CHANGED, SUBJECT_SEX_CHANGED, CONVERSION_CHANGED, SCALE_FACTOR_CHANGED, MODALITY_CHANGED, TIME_CHANGED, VOXEL_SIZE_CHANGED, DATA_SET_CHANGED, INVALIDATE_SLICE_CACHE, VIEW_GATES_CHANGED, LAST_SIGNAL }; static void data_set_class_init (AmitkDataSetClass *klass); static void data_set_init (AmitkDataSet *data_set); static void data_set_finalize (GObject *object); static void data_set_scale (AmitkSpace *space, AmitkPoint *ref_point, AmitkPoint *scaling); static void data_set_space_changed (AmitkSpace *space); static void data_set_selection_changed (AmitkObject *object); static AmitkObject * data_set_copy (const AmitkObject *object); static void data_set_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); static void data_set_write_xml (const AmitkObject *object, xmlNodePtr nodes, FILE *study_file); static gchar * data_set_read_xml (AmitkObject *object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf); static void data_set_invalidate_slice_cache (AmitkDataSet * ds); static void data_set_set_voxel_size (AmitkDataSet * ds, const AmitkPoint voxel_size); static void data_set_drop_intercept (AmitkDataSet * ds); static void data_set_reduce_scaling_dimension (AmitkDataSet * ds); static AmitkVolumeClass * parent_class; static guint data_set_signals[LAST_SIGNAL]; static amide_data_t calculate_scale_factor(AmitkDataSet * ds); GList * slice_cache_trim(GList * slice_cache, gint max_size); #define MIN_LOCAL_CACHE_SIZE 3 GType amitk_data_set_get_type(void) { static GType data_set_type = 0; if (!data_set_type) { static const GTypeInfo data_set_info = { sizeof (AmitkDataSetClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) data_set_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkDataSet), 0, /* n_preallocs */ (GInstanceInitFunc) data_set_init, NULL /* value table */ }; data_set_type = g_type_register_static (AMITK_TYPE_VOLUME, "AmitkDataSet", &data_set_info, 0); } return data_set_type; } static void data_set_class_init (AmitkDataSetClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); AmitkObjectClass * object_class = AMITK_OBJECT_CLASS(class); AmitkSpaceClass * space_class = AMITK_SPACE_CLASS(class); parent_class = g_type_class_peek_parent(class); space_class->space_scale = data_set_scale; space_class->space_changed = data_set_space_changed; object_class->object_selection_changed = data_set_selection_changed; object_class->object_copy = data_set_copy; object_class->object_copy_in_place = data_set_copy_in_place; object_class->object_write_xml = data_set_write_xml; object_class->object_read_xml = data_set_read_xml; class->invalidate_slice_cache = data_set_invalidate_slice_cache; gobject_class->finalize = data_set_finalize; data_set_signals[THRESHOLDING_CHANGED] = g_signal_new ("thresholding_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, thresholding_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[THRESHOLD_STYLE_CHANGED] = g_signal_new ("threshold_style_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, threshold_style_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[THRESHOLDS_CHANGED] = g_signal_new ("thresholds_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, thresholds_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[WINDOWS_CHANGED] = g_signal_new ("windows_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, windows_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[COLOR_TABLE_CHANGED] = g_signal_new ("color_table_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, color_table_changed), NULL, NULL, amitk_marshal_VOID__ENUM, G_TYPE_NONE, 1, AMITK_TYPE_VIEW_MODE); data_set_signals[COLOR_TABLE_INDEPENDENT_CHANGED] = g_signal_new ("color_table_independent_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, color_table_independent_changed), NULL, NULL, amitk_marshal_VOID__ENUM, G_TYPE_NONE, 1, AMITK_TYPE_VIEW_MODE); data_set_signals[INTERPOLATION_CHANGED] = g_signal_new ("interpolation_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, interpolation_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[RENDERING_CHANGED] = g_signal_new ("rendering_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, rendering_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[SUBJECT_ORIENTATION_CHANGED] = g_signal_new ("subject_orientation_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, subject_orientation_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[SUBJECT_SEX_CHANGED] = g_signal_new ("subject_sex_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, subject_sex_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[CONVERSION_CHANGED] = g_signal_new ("conversion_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, conversion_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[SCALE_FACTOR_CHANGED] = g_signal_new ("scale_factor_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, scale_factor_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[MODALITY_CHANGED] = g_signal_new ("modality_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, modality_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[TIME_CHANGED] = g_signal_new ("time_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, time_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[VOXEL_SIZE_CHANGED] = g_signal_new ("voxel_size_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, voxel_size_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[DATA_SET_CHANGED] = g_signal_new ("data_set_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, data_set_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[INVALIDATE_SLICE_CACHE] = g_signal_new ("invalidate_slice_cache", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, invalidate_slice_cache), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); data_set_signals[VIEW_GATES_CHANGED] = g_signal_new ("view_gates_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkDataSetClass, view_gates_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void data_set_init (AmitkDataSet * data_set) { gint i; AmitkWindow i_window; AmitkLimit i_limit; AmitkViewMode i_view_mode; /* put in some sensable values */ data_set->raw_data = NULL; data_set->current_scaling_factor = NULL; data_set->gate_time = NULL; data_set->frame_duration = NULL; data_set->min_max_calculated = FALSE; data_set->frame_max = NULL; data_set->frame_min = NULL; data_set->global_max = 0.0; data_set->global_min = 0.0; amitk_data_set_set_thresholding(data_set, AMITK_THRESHOLDING_GLOBAL); amitk_data_set_set_threshold_style(data_set, AMITK_THRESHOLD_STYLE_MIN_MAX); for (i=0; i<2; i++) data_set->threshold_ref_frame[i]=0; data_set->distribution = NULL; data_set->modality = AMITK_MODALITY_PET; data_set->voxel_size = one_point; data_set->scaling_type = AMITK_SCALING_TYPE_0D; data_set->internal_scaling_factor = amitk_raw_data_DOUBLE_0D_SCALING_init(1.0); g_assert(data_set->internal_scaling_factor!=NULL); data_set->internal_scaling_intercept = NULL; amitk_data_set_set_scale_factor(data_set, 1.0); data_set->conversion = AMITK_CONVERSION_STRAIGHT; data_set->injected_dose = NAN; /* unknown */ data_set->displayed_dose_unit = AMITK_DOSE_UNIT_MEGABECQUEREL; data_set->subject_weight = NAN; /* unknown */ data_set->displayed_weight_unit = AMITK_WEIGHT_UNIT_KILOGRAM; data_set->cylinder_factor = 1.0; data_set->displayed_cylinder_unit = AMITK_CYLINDER_UNIT_MEGABECQUEREL_PER_CC_IMAGE_UNIT; data_set->inversion_time = NAN; /* unknown */ data_set->echo_time = NAN; /* unknown */ data_set->diffusion_b_value = NAN; /* unknown */ data_set->diffusion_direction = zero_point; data_set->view_start_gate = 0; data_set->view_end_gate = 0; data_set->num_view_gates= 1; data_set->scan_start = 0.0; for(i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { data_set->color_table[i_view_mode] = AMITK_COLOR_TABLE_BW_LINEAR; data_set->color_table_independent[i_view_mode] = FALSE; } data_set->interpolation = AMITK_INTERPOLATION_NEAREST_NEIGHBOR; data_set->rendering = AMITK_RENDERING_MPR; data_set->subject_orientation = AMITK_SUBJECT_ORIENTATION_UNKNOWN; data_set->subject_sex = AMITK_SUBJECT_SEX_UNKNOWN; data_set->slice_cache = NULL; data_set->slice_parent = NULL; for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) for (i_limit=0; i_limit < AMITK_LIMIT_NUM; i_limit++) data_set->threshold_window[i_window][i_limit] = amitk_window_default[i_window][i_limit]; /* set the scan date to the current time, good for an initial guess */ data_set->scan_date = NULL; amitk_data_set_set_scan_date(data_set, NULL); data_set->subject_name = NULL; amitk_data_set_set_subject_name(data_set, NULL); data_set->subject_id = NULL; amitk_data_set_set_subject_id(data_set, NULL); data_set->subject_dob = NULL; amitk_data_set_set_subject_dob(data_set, NULL); data_set->series_number = 0; data_set->dicom_image_type = NULL; data_set->instance_number=0; data_set->gate_num=-1; } static void data_set_finalize (GObject *object) { AmitkDataSet * data_set = AMITK_DATA_SET(object); if (data_set->raw_data != NULL) { #ifdef AMIDE_DEBUG if (data_set->raw_data->dim.z != 1) /* avoid slices */ g_print("\tfreeing data set: %s\n",AMITK_OBJECT_NAME(data_set)); #endif g_object_unref(data_set->raw_data); data_set->raw_data = NULL; } if (data_set->internal_scaling_factor != NULL) { g_object_unref(data_set->internal_scaling_factor); data_set->internal_scaling_factor = NULL; } if (data_set->internal_scaling_intercept != NULL) { g_object_unref(data_set->internal_scaling_intercept); data_set->internal_scaling_intercept = NULL; } if (data_set->current_scaling_factor != NULL) { g_object_unref(data_set->current_scaling_factor); data_set->current_scaling_factor = NULL; } if (data_set->distribution != NULL) { g_object_unref(data_set->distribution); data_set->distribution = NULL; } if (data_set->gate_time != NULL) { g_free(data_set->gate_time); data_set->gate_time = NULL; } if (data_set->frame_duration != NULL) { g_free(data_set->frame_duration); data_set->frame_duration = NULL; } if (data_set->frame_max != NULL) { g_free(data_set->frame_max); data_set->frame_max = NULL; } if (data_set->frame_min != NULL) { g_free(data_set->frame_min); data_set->frame_min = NULL; } if (data_set->scan_date != NULL) { g_free(data_set->scan_date); data_set->scan_date = NULL; } if (data_set->subject_name != NULL) { g_free(data_set->subject_name); data_set->subject_name = NULL; } if (data_set->subject_id != NULL) { g_free(data_set->subject_id); data_set->subject_id = NULL; } if (data_set->subject_dob != NULL) { g_free(data_set->subject_dob); data_set->subject_dob = NULL; } if (data_set->dicom_image_type != NULL) { g_free(data_set->dicom_image_type); data_set->dicom_image_type = NULL; } if (data_set->slice_cache != NULL) { amitk_objects_unref(data_set->slice_cache); data_set->slice_cache = NULL; } if (data_set->slice_parent != NULL) { g_object_remove_weak_pointer(G_OBJECT(data_set->slice_parent), (gpointer *) &(data_set->slice_parent)); data_set->slice_parent = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static void data_set_scale(AmitkSpace *space, AmitkPoint *ref_point, AmitkPoint *scaling) { AmitkDataSet * data_set; AmitkPoint voxel_size; g_return_if_fail(AMITK_IS_DATA_SET(space)); data_set = AMITK_DATA_SET(space); /* first, pass the signal on, this gets the volume corner value readjusted */ AMITK_SPACE_CLASS(parent_class)->space_scale (space, ref_point, scaling); /* readjust the voxel size based on the new corner */ if (AMITK_VOLUME_VALID(data_set)) { voxel_size = AMITK_VOLUME_CORNER(data_set); voxel_size.x /= AMITK_DATA_SET_DIM_X(data_set); voxel_size.y /= AMITK_DATA_SET_DIM_Y(data_set); voxel_size.z /= AMITK_DATA_SET_DIM_Z(data_set); data_set_set_voxel_size(data_set, voxel_size); } } static void data_set_space_changed(AmitkSpace * space) { AmitkDataSet * data_set; g_return_if_fail(AMITK_IS_DATA_SET(space)); data_set = AMITK_DATA_SET(space); g_signal_emit(G_OBJECT (data_set), data_set_signals[INVALIDATE_SLICE_CACHE], 0); if (AMITK_SPACE_CLASS(parent_class)->space_changed) AMITK_SPACE_CLASS(parent_class)->space_changed (space); } static void data_set_selection_changed(AmitkObject * object) { AmitkDataSet * data_set; g_return_if_fail(AMITK_IS_DATA_SET(object)); data_set = AMITK_DATA_SET(object); if (!amitk_object_get_selected(object, AMITK_SELECTION_ANY)) { data_set->slice_cache = slice_cache_trim(data_set->slice_cache, MIN_LOCAL_CACHE_SIZE); } return; } static AmitkObject * data_set_copy (const AmitkObject * object) { AmitkDataSet * copy; g_return_val_if_fail(AMITK_IS_DATA_SET(object), NULL); copy = amitk_data_set_new(NULL, -1); amitk_object_copy_in_place(AMITK_OBJECT(copy), object); return AMITK_OBJECT(copy); } /* Notes: - does not make a copy of the source raw_data, just adds a reference - does not make a copy of the distribution data, just adds a reference - does not make a copy of the internal scaling factor, just adds a reference - does not make a copy of the internal scaling intercept, just adds a reference */ static void data_set_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object) { AmitkDataSet * src_ds; AmitkDataSet * dest_ds; AmitkViewMode i_view_mode; guint i; g_return_if_fail(AMITK_IS_DATA_SET(src_object)); g_return_if_fail(AMITK_IS_DATA_SET(dest_object)); src_ds = AMITK_DATA_SET(src_object); dest_ds = AMITK_DATA_SET(dest_object); /* copy the data elements */ amitk_data_set_set_scan_date(dest_ds, AMITK_DATA_SET_SCAN_DATE(src_object)); amitk_data_set_set_subject_name(dest_ds, AMITK_DATA_SET_SUBJECT_NAME(src_object)); amitk_data_set_set_subject_id(dest_ds, AMITK_DATA_SET_SUBJECT_ID(src_object)); amitk_data_set_set_subject_dob(dest_ds, AMITK_DATA_SET_SUBJECT_DOB(src_object)); amitk_data_set_set_series_number(dest_ds, AMITK_DATA_SET_SERIES_NUMBER(src_object)); amitk_data_set_set_dicom_image_type(dest_ds, AMITK_DATA_SET_DICOM_IMAGE_TYPE(src_object)); amitk_data_set_set_modality(dest_ds, AMITK_DATA_SET_MODALITY(src_object)); dest_ds->voxel_size = AMITK_DATA_SET_VOXEL_SIZE(src_object); if (src_ds->raw_data != NULL) { if (dest_ds->raw_data != NULL) g_object_unref(dest_ds->raw_data); dest_ds->raw_data = g_object_ref(src_ds->raw_data); } /* just reference, as internal scaling is never suppose to change */ dest_ds->scaling_type = src_ds->scaling_type; if (src_ds->internal_scaling_factor != NULL) { if (dest_ds->internal_scaling_factor != NULL) g_object_unref(dest_ds->internal_scaling_factor); dest_ds->internal_scaling_factor = g_object_ref(src_ds->internal_scaling_factor); } if (src_ds->internal_scaling_intercept != NULL) { if (dest_ds->internal_scaling_intercept != NULL) g_object_unref(dest_ds->internal_scaling_intercept); dest_ds->internal_scaling_intercept = g_object_ref(src_ds->internal_scaling_intercept); } dest_ds->scan_start = AMITK_DATA_SET_SCAN_START(src_object); if (src_ds->distribution != NULL) { if (dest_ds->distribution != NULL) g_object_unref(dest_ds->distribution); dest_ds->distribution = g_object_ref(src_ds->distribution); } amitk_data_set_set_scale_factor(dest_ds, AMITK_DATA_SET_SCALE_FACTOR(src_object)); dest_ds->conversion = AMITK_DATA_SET_CONVERSION(src_object); dest_ds->injected_dose = AMITK_DATA_SET_INJECTED_DOSE(src_object); dest_ds->displayed_dose_unit = AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(src_object); dest_ds->subject_weight = AMITK_DATA_SET_SUBJECT_WEIGHT(src_object); dest_ds->displayed_weight_unit = AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(src_object); dest_ds->cylinder_factor = AMITK_DATA_SET_CYLINDER_FACTOR(src_object); dest_ds->displayed_cylinder_unit = AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(src_object); dest_ds->inversion_time = AMITK_DATA_SET_INVERSION_TIME(src_object); dest_ds->echo_time = AMITK_DATA_SET_ECHO_TIME(src_object); dest_ds->diffusion_b_value = AMITK_DATA_SET_DIFFUSION_B_VALUE(src_object); dest_ds->diffusion_direction = AMITK_DATA_SET_DIFFUSION_DIRECTION(src_object); for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table(dest_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE(src_object, i_view_mode)); for (i_view_mode=AMITK_VIEW_MODE_LINKED_2WAY; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table_independent(dest_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(src_object, i_view_mode)); amitk_data_set_set_interpolation(dest_ds, AMITK_DATA_SET_INTERPOLATION(src_object)); amitk_data_set_set_rendering(dest_ds, AMITK_DATA_SET_RENDERING(src_object)); amitk_data_set_set_subject_orientation(dest_ds, AMITK_DATA_SET_SUBJECT_ORIENTATION(src_object)); amitk_data_set_set_subject_sex(dest_ds, AMITK_DATA_SET_SUBJECT_SEX(src_object)); amitk_data_set_set_thresholding(dest_ds,AMITK_DATA_SET_THRESHOLDING(src_object)); amitk_data_set_set_threshold_style(dest_ds, AMITK_DATA_SET_THRESHOLD_STYLE(src_object)); for (i=0; i<2; i++) { dest_ds->threshold_max[i] = AMITK_DATA_SET_THRESHOLD_MAX(src_object, i); dest_ds->threshold_min[i] = AMITK_DATA_SET_THRESHOLD_MIN(src_object, i); dest_ds->threshold_ref_frame[i] = AMITK_DATA_SET_THRESHOLD_REF_FRAME(src_object, i); } amitk_data_set_set_view_start_gate(dest_ds, AMITK_DATA_SET_VIEW_START_GATE(src_object)); amitk_data_set_set_view_end_gate(dest_ds, AMITK_DATA_SET_VIEW_END_GATE(src_object)); /* make a separate copy in memory of the data set's gate times */ if (dest_ds->gate_time != NULL) g_free(dest_ds->gate_time); dest_ds->gate_time = amitk_data_set_get_gate_time_mem(dest_ds); g_return_if_fail(dest_ds->gate_time != NULL); for (i=0;igate_time[i] = amitk_data_set_get_gate_time(src_ds, i); /* make a separate copy in memory of the data set's frame durations */ if (dest_ds->frame_duration != NULL) g_free(dest_ds->frame_duration); dest_ds->frame_duration = amitk_data_set_get_frame_duration_mem(dest_ds); g_return_if_fail(dest_ds->frame_duration != NULL); for (i=0;iframe_duration[i] = amitk_data_set_get_frame_duration(src_ds, i); /* if they've already been calculated, make a copy in memory of the data set's max/min values */ dest_ds->min_max_calculated = AMITK_DATA_SET(src_object)->min_max_calculated; if (dest_ds->frame_max != NULL) { g_free(dest_ds->frame_max); dest_ds->frame_max = NULL; } if (dest_ds->frame_min != NULL) { g_free(dest_ds->frame_min); dest_ds->frame_min = NULL; } if (src_ds->min_max_calculated) { dest_ds->global_max = AMITK_DATA_SET(src_object)->global_max; dest_ds->global_min = AMITK_DATA_SET(src_object)->global_min; dest_ds->frame_max = amitk_data_set_get_frame_min_max_mem(dest_ds); g_return_if_fail(dest_ds->frame_max != NULL); for (i=0;iframe_max[i] = src_ds->frame_max[i]; dest_ds->frame_min = amitk_data_set_get_frame_min_max_mem(dest_ds); g_return_if_fail(dest_ds->frame_min != NULL); for (i=0;iframe_min[i] = src_ds->frame_min[i]; } AMITK_OBJECT_CLASS (parent_class)->object_copy_in_place (dest_object, src_object); } static void data_set_write_xml(const AmitkObject * object, xmlNodePtr nodes, FILE * study_file) { AmitkDataSet * ds; gchar * xml_filename; gchar * name; gchar * temp_string; guint64 location, size; AmitkWindow i_window; AmitkLimit i_limit; AmitkViewMode i_view_mode; AMITK_OBJECT_CLASS(parent_class)->object_write_xml(object, nodes, study_file); ds = AMITK_DATA_SET(object); xml_save_string(nodes, "scan_date", AMITK_DATA_SET_SCAN_DATE(ds)); xml_save_string(nodes, "subject_name", AMITK_DATA_SET_SUBJECT_NAME(ds)); xml_save_string(nodes, "subject_id", AMITK_DATA_SET_SUBJECT_ID(ds)); xml_save_string(nodes, "subject_dob", AMITK_DATA_SET_SUBJECT_DOB(ds)); xml_save_int(nodes, "series_number", AMITK_DATA_SET_SERIES_NUMBER(ds)); xml_save_string(nodes, "subject_dicom_image_type", AMITK_DATA_SET_DICOM_IMAGE_TYPE(ds)); xml_save_string(nodes, "modality", amitk_modality_get_name(AMITK_DATA_SET_MODALITY(ds))); amitk_point_write_xml(nodes,"voxel_size", AMITK_DATA_SET_VOXEL_SIZE(ds)); name = g_strdup_printf("data-set_%s_raw-data",AMITK_OBJECT_NAME(object)); amitk_raw_data_write_xml(AMITK_DATA_SET_RAW_DATA(ds), name, study_file, &xml_filename, &location, &size); g_free(name); if (study_file == NULL) { xml_save_string(nodes, "raw_data_file", xml_filename); g_free(xml_filename); } else { xml_save_location_and_size(nodes, "raw_data_location_and_size", location, size); } name = g_strdup_printf("data-set_%s_scaling-factors",AMITK_OBJECT_NAME(ds)); amitk_raw_data_write_xml(ds->internal_scaling_factor, name, study_file, &xml_filename, &location, &size); g_free(name); if (study_file == NULL) { xml_save_string(nodes, "internal_scaling_factor_file", xml_filename); g_free(xml_filename); } else { xml_save_location_and_size(nodes, "internal_scaling_factor_location_and_size", location, size); } if (ds->internal_scaling_intercept != NULL) { name = g_strdup_printf("data-set_%s_scaling-intercepts",AMITK_OBJECT_NAME(ds)); amitk_raw_data_write_xml(ds->internal_scaling_intercept, name, study_file, &xml_filename, &location, &size); g_free(name); if (study_file == NULL) { xml_save_string(nodes, "internal_scaling_intercepts_file", xml_filename); g_free(xml_filename); } else { xml_save_location_and_size(nodes, "internal_scaling_intercepts_location_and_size", location, size); } } if (ds->distribution != NULL) { name = g_strdup_printf("data-set_%s_distribution",AMITK_OBJECT_NAME(ds)); amitk_raw_data_write_xml(ds->distribution, name, study_file, &xml_filename, &location, &size); g_free(name); if (study_file == NULL) { xml_save_string(nodes, "distribution_file", xml_filename); g_free(xml_filename); } else { xml_save_location_and_size(nodes, "distribution_location_and_size", location, size); } } xml_save_string(nodes, "scaling_type", amitk_scaling_type_get_name(ds->scaling_type)); xml_save_data(nodes, "scale_factor", AMITK_DATA_SET_SCALE_FACTOR(ds)); xml_save_string(nodes, "conversion", amitk_conversion_get_name(ds->conversion)); xml_save_data(nodes, "injected_dose", AMITK_DATA_SET_INJECTED_DOSE(ds)); xml_save_string(nodes, "displayed_dose_unit", amitk_dose_unit_get_name(ds->displayed_dose_unit)); xml_save_data(nodes, "subject_weight", AMITK_DATA_SET_SUBJECT_WEIGHT(ds)); xml_save_string(nodes, "displayed_weight_unit", amitk_weight_unit_get_name(ds->displayed_weight_unit)); xml_save_data(nodes, "cylinder_factor", AMITK_DATA_SET_CYLINDER_FACTOR(ds)); xml_save_string(nodes, "displayed_cylinder_unit", amitk_cylinder_unit_get_name(ds->displayed_cylinder_unit)); xml_save_data(nodes, "inversion_time", AMITK_DATA_SET_INVERSION_TIME(ds)); xml_save_data(nodes, "echo_time", AMITK_DATA_SET_ECHO_TIME(ds)); xml_save_data(nodes, "diffusion_b_value", AMITK_DATA_SET_DIFFUSION_B_VALUE(ds)); amitk_point_write_xml(nodes, "diffusion_direction", AMITK_DATA_SET_DIFFUSION_DIRECTION(ds)); xml_save_time(nodes, "scan_start", AMITK_DATA_SET_SCAN_START(ds)); xml_save_times(nodes, "gate_time", ds->gate_time, AMITK_DATA_SET_NUM_GATES(ds)); xml_save_times(nodes, "frame_duration", ds->frame_duration, AMITK_DATA_SET_NUM_FRAMES(ds)); xml_save_string(nodes, "color_table", amitk_color_table_get_name(AMITK_DATA_SET_COLOR_TABLE(ds, AMITK_VIEW_MODE_SINGLE))); for (i_view_mode=AMITK_VIEW_MODE_LINKED_2WAY; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { temp_string = g_strdup_printf("color_table_%d", i_view_mode+1); xml_save_string(nodes, temp_string, amitk_color_table_get_name(AMITK_DATA_SET_COLOR_TABLE(ds, i_view_mode))); g_free(temp_string); temp_string = g_strdup_printf("color_table_%d_independent", i_view_mode+1); xml_save_int(nodes, temp_string, AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(ds, i_view_mode)); g_free(temp_string); } xml_save_string(nodes, "interpolation", amitk_interpolation_get_name(AMITK_DATA_SET_INTERPOLATION(ds))); xml_save_string(nodes, "rendering", amitk_rendering_get_name(AMITK_DATA_SET_RENDERING(ds))); xml_save_string(nodes, "subject_orientation", amitk_subject_orientation_get_name(AMITK_DATA_SET_SUBJECT_ORIENTATION(ds))); xml_save_string(nodes, "subject_sex", amitk_subject_sex_get_name(AMITK_DATA_SET_SUBJECT_SEX(ds))); xml_save_string(nodes, "thresholding", amitk_thresholding_get_name(AMITK_DATA_SET_THRESHOLDING(ds))); xml_save_string(nodes, "threshold_style", amitk_threshold_style_get_name(AMITK_DATA_SET_THRESHOLD_STYLE(ds))); xml_save_data(nodes, "threshold_max_0", ds->threshold_max[0]); xml_save_data(nodes, "threshold_min_0", ds->threshold_min[0]); xml_save_int(nodes, "threshold_ref_frame_0", ds->threshold_ref_frame[0]); xml_save_data(nodes, "threshold_max_1", ds->threshold_max[1]); xml_save_data(nodes, "threshold_min_1", ds->threshold_min[1]); xml_save_int(nodes, "threshold_ref_frame_1", ds->threshold_ref_frame[1]); for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) for (i_limit=0; i_limit < AMITK_LIMIT_NUM; i_limit++) { temp_string = g_strdup_printf("threshold_window_%s-%s", amitk_window_get_name(i_window), amitk_limit_get_name(i_limit)); xml_save_data(nodes, temp_string, ds->threshold_window[i_window][i_limit]); g_free(temp_string); } xml_save_int(nodes, "view_start_gate", AMITK_DATA_SET_VIEW_START_GATE(ds)); xml_save_int(nodes, "view_end_gate", AMITK_DATA_SET_VIEW_END_GATE(ds)); return; } static gchar * data_set_read_xml(AmitkObject * object, xmlNodePtr nodes, FILE * study_file, gchar * error_buf) { AmitkDataSet * ds; AmitkModality i_modality; AmitkColorTable i_color_table; AmitkViewMode i_view_mode; AmitkThresholding i_thresholding; AmitkThresholdStyle i_threshold_style; AmitkInterpolation i_interpolation; AmitkRendering i_rendering; AmitkSubjectOrientation i_subject_orientation; AmitkSubjectSex i_subject_sex; AmitkScalingType i_scaling_type; AmitkConversion i_conversion; AmitkDoseUnit i_dose_unit; AmitkWeightUnit i_weight_unit; AmitkCylinderUnit i_cylinder_unit; AmitkWindow i_window; AmitkLimit i_limit; gchar * temp_string; gchar * temp_string2; gchar * filename=NULL; guint64 location, size; gboolean intercept; error_buf = AMITK_OBJECT_CLASS(parent_class)->object_read_xml(object, nodes, study_file, error_buf); ds = AMITK_DATA_SET(object); temp_string = xml_get_string(nodes, "scan_date"); amitk_data_set_set_scan_date(ds, temp_string); g_free(temp_string); if (xml_node_exists(nodes, "subject_name")) { temp_string = xml_get_string(nodes, "subject_name"); amitk_data_set_set_subject_name(ds, temp_string); g_free(temp_string); } if (xml_node_exists(nodes, "subject_id")) { temp_string = xml_get_string(nodes, "subject_id"); amitk_data_set_set_subject_id(ds, temp_string); g_free(temp_string); } if (xml_node_exists(nodes, "subject_dob")) { temp_string = xml_get_string(nodes, "subject_dob"); amitk_data_set_set_subject_dob(ds, temp_string); g_free(temp_string); } ds->series_number = xml_get_int(nodes,"series_number", &error_buf); if (xml_node_exists(nodes, "dicom_image_type")) { temp_string = xml_get_string(nodes, "dicom_image_type"); amitk_data_set_set_subject_dob(ds, temp_string); g_free(temp_string); } temp_string = xml_get_string(nodes, "modality"); if (temp_string != NULL) for (i_modality=0; i_modality < AMITK_MODALITY_NUM; i_modality++) if (g_ascii_strcasecmp(temp_string, amitk_modality_get_name(i_modality)) == 0) amitk_data_set_set_modality(ds, i_modality); g_free(temp_string); ds->voxel_size = amitk_point_read_xml(nodes, "voxel_size", &error_buf); if (EQUAL_ZERO(ds->voxel_size.x)) { g_warning(_("Voxel size X was read as 0, setting to 1 mm. This may be an internationalization error.")); ds->voxel_size.x = 1.0; } if (EQUAL_ZERO(ds->voxel_size.y)) { g_warning(_("Voxel size Y was read as 0, setting to 1 mm. This may be an internationalization error.")); ds->voxel_size.y = 1.0; } if (EQUAL_ZERO(ds->voxel_size.z)) { g_warning(_("Voxel size Z was read as 0, setting to 1 mm. This may be an internationalization error.")); ds->voxel_size.z = 1.0; } if (study_file == NULL) filename = xml_get_string(nodes, "raw_data_file"); else xml_get_location_and_size(nodes, "raw_data_location_and_size", &location, &size, &error_buf); ds->raw_data = amitk_raw_data_read_xml(filename, study_file, location, size, &error_buf, NULL, NULL); if (filename != NULL) { g_free(filename); filename = NULL; } /* changed internal_scaling to internal_scaling_factor in 0.8.15 - compensate for old naming scheme */ if (study_file == NULL) { if (xml_node_exists(nodes, "internal_scaling_file")) filename = xml_get_string(nodes, "internal_scaling_file"); else filename = xml_get_string(nodes, "internal_scaling_factor_file"); } else { if (xml_node_exists(nodes, "internal_scaling_location_and_size")) xml_get_location_and_size(nodes, "internal_scaling_location_and_size", &location, &size, &error_buf); else xml_get_location_and_size(nodes, "internal_scaling_factor_location_and_size", &location, &size, &error_buf); } if (ds->internal_scaling_factor != NULL) { g_object_unref(ds->internal_scaling_factor); ds->internal_scaling_factor=NULL; } ds->internal_scaling_factor = amitk_raw_data_read_xml(filename, study_file, location, size, &error_buf, NULL, NULL); if (filename != NULL) { g_free(filename); filename = NULL; } if (ds->internal_scaling_factor == NULL) { amitk_append_str_with_newline(&error_buf, _("internal scaling factor returned NULL... either file is corrupt, or AMIDE has a bug")); return error_buf; /* something really bad has happened */ } /* added an optional internal_scaling_intercept in 0.8.15 */ if (ds->internal_scaling_intercept != NULL) { g_object_unref(ds->internal_scaling_intercept); ds->internal_scaling_intercept = NULL; } intercept = FALSE; if (study_file == NULL) { if (xml_node_exists(nodes, "internal_scaling_intercepts_file")) { filename = xml_get_string(nodes, "internal_scaling_intercepts_file"); intercept = TRUE; } } else { if (xml_node_exists(nodes, "internal_scaling_intercepts_location_and_size")) { xml_get_location_and_size(nodes, "internal_scaling_intercepts_location_and_size", &location, &size, &error_buf); intercept = TRUE; } } if (intercept) { ds->internal_scaling_intercept = amitk_raw_data_read_xml(filename, study_file, location, size, &error_buf, NULL, NULL); if (filename != NULL) { g_free(filename); filename = NULL; } if (!AMITK_DATA_SET_SCALING_HAS_INTERCEPT(ds)) ds->scaling_type += 3; /* quick hack for some 0.8.15 beta's */ } if (xml_node_exists(nodes, "distribution_file") || xml_node_exists(nodes, "distribution_location_and_size")) { if (study_file == NULL) filename = xml_get_string(nodes, "distribution_file"); else xml_get_location_and_size(nodes, "distribution_location_and_size", &location, &size, &error_buf); if (ds->distribution != NULL) g_object_unref(ds->distribution); ds->distribution = amitk_raw_data_read_xml(filename, study_file, location, size, &error_buf, NULL, NULL); if (filename != NULL) { g_free(filename); filename = NULL; } } /* figure out the scaling type */ temp_string = xml_get_string(nodes, "scaling_type"); if (temp_string != NULL) { for (i_scaling_type=0; i_scaling_type < AMITK_SCALING_TYPE_NUM; i_scaling_type++) if (g_ascii_strcasecmp(temp_string, amitk_scaling_type_get_name(i_scaling_type)) == 0) ds->scaling_type = i_scaling_type; } else { /* scaling_type is a new entry, circa 0.7.7 */ if (ds->internal_scaling_factor->dim.z > 1) ds->scaling_type = AMITK_SCALING_TYPE_2D; else if ((ds->internal_scaling_factor->dim.t > 1) || (ds->internal_scaling_factor->dim.g > 1)) ds->scaling_type = AMITK_SCALING_TYPE_1D; else ds->scaling_type = AMITK_SCALING_TYPE_0D; } g_free(temp_string); /* a little legacy bit, the type of internal_scaling has been changed to double as of amide 0.7.1 */ if (ds->internal_scaling_factor->format != AMITK_FORMAT_DOUBLE) { AmitkRawData * old_scaling; AmitkVoxel i; amitk_append_str_with_newline(&error_buf, _("wrong type found on internal scaling, converting to double")); old_scaling = ds->internal_scaling_factor; ds->internal_scaling_factor = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, old_scaling->dim); if (ds->internal_scaling_factor == NULL) { amitk_append_str_with_newline(&error_buf, _("Couldn't allocate memory space for the new scaling factors")); return error_buf; } for (i.t=0; i.tinternal_scaling_factor->dim.t; i.t++) for (i.g=0; i.ginternal_scaling_factor->dim.g; i.g++) for (i.z=0; i.zinternal_scaling_factor->dim.z; i.z++) for (i.y=0; i.yinternal_scaling_factor->dim.y; i.y++) for (i.x=0; i.xinternal_scaling_factor->dim.x; i.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->internal_scaling_factor,i) = amitk_raw_data_get_value(old_scaling, i); g_object_unref(old_scaling); } /* end legacy cruft */ amitk_data_set_set_scale_factor(ds, xml_get_data(nodes, "scale_factor", &error_buf)); ds->injected_dose = xml_get_data(nodes, "injected_dose", &error_buf); ds->subject_weight = xml_get_data(nodes, "subject_weight", &error_buf); ds->cylinder_factor = xml_get_data(nodes, "cylinder_factor", &error_buf); ds->inversion_time = xml_get_data(nodes, "inversion_time", &error_buf); ds->echo_time = xml_get_data(nodes, "echo_time", &error_buf); ds->diffusion_b_value = xml_get_data(nodes, "diffusion_b_value", &error_buf); ds->diffusion_direction = amitk_point_read_xml(nodes, "diffusion_direction", &error_buf); temp_string = xml_get_string(nodes, "conversion"); if (temp_string != NULL) { for (i_conversion=0; i_conversion < AMITK_CONVERSION_NUM; i_conversion++) if (g_ascii_strcasecmp(temp_string, amitk_conversion_get_name(i_conversion)) == 0) ds->conversion = i_conversion; if (g_ascii_strcasecmp(temp_string,"percent-id-per-g") == 0) /* in 0.9.0 changed to percent-id-per-cc */ ds->conversion = AMITK_CONVERSION_PERCENT_ID_PER_CC; } g_free(temp_string); temp_string = xml_get_string(nodes, "displayed_dose_unit"); if (temp_string != NULL) for (i_dose_unit=0; i_dose_unit < AMITK_DOSE_UNIT_NUM; i_dose_unit++) if (g_ascii_strcasecmp(temp_string, amitk_dose_unit_get_name(i_dose_unit)) == 0) ds->displayed_dose_unit = i_dose_unit; g_free(temp_string); temp_string = xml_get_string(nodes, "displayed_weight_unit"); if (temp_string != NULL) for (i_weight_unit=0; i_weight_unit < AMITK_WEIGHT_UNIT_NUM; i_weight_unit++) if (g_ascii_strcasecmp(temp_string, amitk_weight_unit_get_name(i_weight_unit)) == 0) ds->displayed_weight_unit = i_weight_unit; g_free(temp_string); temp_string = xml_get_string(nodes, "displayed_cylinder_unit"); if (temp_string != NULL) for (i_cylinder_unit=0; i_cylinder_unit < AMITK_CYLINDER_UNIT_NUM; i_cylinder_unit++) if (g_ascii_strcasecmp(temp_string, amitk_cylinder_unit_get_name(i_cylinder_unit)) == 0) ds->displayed_cylinder_unit = i_cylinder_unit; g_free(temp_string); ds->scan_start = xml_get_time(nodes, "scan_start", &error_buf); ds->gate_time = xml_get_times(nodes, "gate_time", AMITK_DATA_SET_NUM_GATES(ds), &error_buf); ds->frame_duration = xml_get_times(nodes, "frame_duration", AMITK_DATA_SET_NUM_FRAMES(ds), &error_buf); for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { if (i_view_mode == 0) { temp_string = xml_get_string(nodes, "color_table"); } else { temp_string2 = g_strdup_printf("color_table_%d", i_view_mode+1); temp_string = xml_get_string(nodes, temp_string2); g_free(temp_string2); } if (temp_string != NULL) for (i_color_table=0; i_color_table < AMITK_COLOR_TABLE_NUM; i_color_table++) if (g_ascii_strcasecmp(temp_string, amitk_color_table_get_name(i_color_table)) == 0) amitk_data_set_set_color_table(ds, i_view_mode, i_color_table); g_free(temp_string); } for (i_view_mode=AMITK_VIEW_MODE_LINKED_2WAY; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { temp_string = g_strdup_printf("color_table_%d_independent", i_view_mode+1); amitk_data_set_set_color_table_independent(ds, i_view_mode, xml_get_int(nodes,temp_string, &error_buf)); g_free(temp_string); } temp_string = xml_get_string(nodes, "interpolation"); if (temp_string != NULL) for (i_interpolation=0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) if (g_ascii_strcasecmp(temp_string, amitk_interpolation_get_name(i_interpolation)) == 0) amitk_data_set_set_interpolation(ds, i_interpolation); g_free(temp_string); temp_string = xml_get_string(nodes, "rendering"); if (temp_string != NULL) for (i_rendering=0; i_rendering < AMITK_RENDERING_NUM; i_rendering++) if (g_ascii_strcasecmp(temp_string, amitk_rendering_get_name(i_rendering)) == 0) amitk_data_set_set_rendering(ds, i_rendering); g_free(temp_string); temp_string = xml_get_string(nodes, "subject_orientation"); if (temp_string != NULL) for (i_subject_orientation=0; i_subject_orientation < AMITK_SUBJECT_ORIENTATION_NUM; i_subject_orientation++) if (g_ascii_strcasecmp(temp_string, amitk_subject_orientation_get_name(i_subject_orientation)) == 0) amitk_data_set_set_subject_orientation(ds, i_subject_orientation); g_free(temp_string); temp_string = xml_get_string(nodes, "subject_sex"); if (temp_string != NULL) for (i_subject_sex=0; i_subject_sex < AMITK_SUBJECT_SEX_NUM; i_subject_sex++) if (g_ascii_strcasecmp(temp_string, amitk_subject_sex_get_name(i_subject_sex)) == 0) amitk_data_set_set_subject_sex(ds, i_subject_sex); g_free(temp_string); temp_string = xml_get_string(nodes, "thresholding"); if (temp_string != NULL) for (i_thresholding=0; i_thresholding < AMITK_THRESHOLDING_NUM; i_thresholding++) if (g_ascii_strcasecmp(temp_string, amitk_thresholding_get_name(i_thresholding)) == 0) amitk_data_set_set_thresholding(ds, i_thresholding); g_free(temp_string); temp_string = xml_get_string(nodes, "threshold_style"); if (temp_string != NULL) for (i_threshold_style=0; i_threshold_style < AMITK_THRESHOLD_STYLE_NUM; i_threshold_style++) if (g_ascii_strcasecmp(temp_string, amitk_threshold_style_get_name(i_threshold_style)) == 0) amitk_data_set_set_threshold_style(ds, i_threshold_style); g_free(temp_string); ds->threshold_max[0] = xml_get_data(nodes, "threshold_max_0", &error_buf); ds->threshold_max[1] = xml_get_data(nodes, "threshold_max_1", &error_buf); ds->threshold_ref_frame[0] = xml_get_int(nodes,"threshold_ref_frame_0", &error_buf); ds->threshold_min[0] = xml_get_data(nodes, "threshold_min_0", &error_buf); ds->threshold_min[1] = xml_get_data(nodes, "threshold_min_1", &error_buf); ds->threshold_ref_frame[1] = xml_get_int(nodes,"threshold_ref_frame_1", &error_buf); for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) for (i_limit=0; i_limit < AMITK_LIMIT_NUM; i_limit++) { temp_string = g_strdup_printf("threshold_window_%s-%s", amitk_window_get_name(i_window), amitk_limit_get_name(i_limit)); ds->threshold_window[i_window][i_limit] = xml_get_data_with_default(nodes, temp_string, AMITK_DATA_SET_THRESHOLD_WINDOW(ds, i_window, i_limit)); g_free(temp_string); } amitk_data_set_set_view_start_gate(ds, xml_get_int(nodes, "view_start_gate", &error_buf)); amitk_data_set_set_view_end_gate(ds, xml_get_int(nodes, "view_end_gate", &error_buf)); /* recalc the temporary parameters */ amitk_data_set_calc_far_corner(ds); /* see if we can drop the intercept/reduce scaling dimensionality */ data_set_drop_intercept(ds); data_set_reduce_scaling_dimension(ds); return error_buf; } static void data_set_invalidate_slice_cache(AmitkDataSet * data_set) { /* invalidate cache */ if (data_set->slice_cache != NULL) { amitk_objects_unref(data_set->slice_cache); data_set->slice_cache = NULL; } return; } /* this does not recalc the far corner, needs to be done separately */ static void data_set_set_voxel_size(AmitkDataSet * ds, const AmitkPoint voxel_size) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (!POINT_EQUAL(AMITK_DATA_SET_VOXEL_SIZE(ds), voxel_size)) { ds->voxel_size = voxel_size; g_signal_emit(G_OBJECT (ds), data_set_signals[VOXEL_SIZE_CHANGED], 0); g_signal_emit(G_OBJECT (ds), data_set_signals[INVALIDATE_SLICE_CACHE], 0); g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } /* set preferences to NULL if we don't want to use, modality can be specified as -1 to not set */ AmitkDataSet * amitk_data_set_new (AmitkPreferences * preferences, const AmitkModality modality) { AmitkDataSet * data_set; AmitkWindow i_window; AmitkLimit i_limit; AmitkViewMode i_view_mode; data_set = g_object_new(amitk_data_set_get_type(), NULL); if (modality >= 0) amitk_data_set_set_modality(data_set, modality); if (preferences != NULL) { /* apply our preferential colortable*/ for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table(data_set,i_view_mode, AMITK_PREFERENCES_COLOR_TABLE(preferences, modality)); /* and copy in the default windows */ for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) for (i_limit=0; i_limit < AMITK_LIMIT_NUM; i_limit++) { amitk_data_set_set_threshold_window(data_set, i_window, i_limit, AMITK_PREFERENCES_WINDOW(preferences, i_window, i_limit)); } amitk_data_set_set_threshold_style(data_set, AMITK_PREFERENCES_THRESHOLD_STYLE(preferences)); } return data_set; } AmitkDataSet * amitk_data_set_new_with_data(AmitkPreferences * preferences, const AmitkModality modality, const AmitkFormat format, const AmitkVoxel dim, const AmitkScalingType scaling_type) { AmitkDataSet * data_set; AmitkVoxel scaling_dim; gint i; data_set = amitk_data_set_new(preferences, modality); g_return_val_if_fail(data_set != NULL, NULL); g_assert(data_set->raw_data == NULL); data_set->raw_data = amitk_raw_data_new_with_data(format, dim); if (data_set->raw_data == NULL) { amitk_object_unref(data_set); g_return_val_if_reached(NULL); } g_assert(data_set->gate_time == NULL); data_set->gate_time = amitk_data_set_get_gate_time_mem(data_set); if (data_set->gate_time == NULL) { amitk_object_unref(data_set); g_return_val_if_reached(NULL); } for (i=0; i < dim.g; i++) data_set->gate_time[i] = 0.0; g_assert(data_set->frame_duration == NULL); data_set->frame_duration = amitk_data_set_get_frame_duration_mem(data_set); if (data_set->frame_duration == NULL) { amitk_object_unref(data_set); g_return_val_if_reached(NULL); } for (i=0; i < dim.t; i++) data_set->frame_duration[i] = 1.0; if (data_set->internal_scaling_factor != NULL) { g_object_unref(data_set->internal_scaling_factor); data_set->internal_scaling_factor=NULL; } if (data_set->internal_scaling_intercept != NULL) { g_object_unref(data_set->internal_scaling_intercept); data_set->internal_scaling_intercept=NULL; } scaling_dim = one_voxel; data_set->scaling_type = scaling_type; switch(scaling_type) { case AMITK_SCALING_TYPE_2D: case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: scaling_dim.t = dim.t; scaling_dim.g = dim.g; scaling_dim.z = dim.z; break; case AMITK_SCALING_TYPE_1D: case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: scaling_dim.t = dim.t; scaling_dim.g = dim.g; break; case AMITK_SCALING_TYPE_0D: default: break; } data_set->internal_scaling_factor = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, scaling_dim); if (data_set->internal_scaling_factor == NULL) { amitk_object_unref(data_set); g_return_val_if_reached(NULL); } amitk_raw_data_DOUBLE_initialize_data(data_set->internal_scaling_factor, 1.0); if (AMITK_DATA_SET_SCALING_HAS_INTERCEPT(data_set)) { data_set->internal_scaling_intercept = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, scaling_dim); if (data_set->internal_scaling_intercept == NULL) { amitk_object_unref(data_set); g_return_val_if_reached(NULL); } amitk_raw_data_DOUBLE_initialize_data(data_set->internal_scaling_intercept, 0.0); } return data_set; } /* reads the contents of a raw data file into an amide data set structure, note: returned structure will have 1 second frame durations entered note: file_offset is bytes for a binary file, lines for an ascii file */ AmitkDataSet * amitk_data_set_import_raw_file(const gchar * file_name, AmitkRawFormat raw_format, AmitkVoxel data_dim, guint file_offset, AmitkPreferences * preferences, const AmitkModality modality, const gchar * data_set_name, const AmitkPoint voxel_size, const amide_data_t scale_factor, AmitkUpdateFunc update_func, gpointer update_data) { guint g,t; AmitkDataSet * ds; if ((ds = amitk_data_set_new(preferences, modality)) == NULL) { g_warning(_("couldn't allocate memory space for the data set structure to hold data")); return NULL; } /* read in the data set */ ds->raw_data = amitk_raw_data_import_raw_file(file_name, NULL, raw_format, data_dim, file_offset, update_func, update_data); if (ds->raw_data == NULL) { g_warning(_("raw_data_read_file failed returning NULL data set")); amitk_object_unref(ds); return NULL; } /* allocate space for the array containing info on the gate times */ if ((ds->gate_time = amitk_data_set_get_gate_time_mem(ds)) == NULL) { g_warning(_("couldn't allocate memory space for the gate time info")); amitk_object_unref(ds); return NULL; } /* put in fake gate times*/ for (g=0; g < AMITK_DATA_SET_NUM_GATES(ds); g++) ds->gate_time[g] = 0.0; /* allocate space for the array containing info on the duration of the frames */ if ((ds->frame_duration = amitk_data_set_get_frame_duration_mem(ds)) == NULL) { g_warning(_("couldn't allocate memory space for the frame duration info")); amitk_object_unref(ds); return NULL; } /* put in fake frame durations */ for (t=0; t < AMITK_DATA_SET_NUM_FRAMES(ds); t++) ds->frame_duration[t] = 1.0; /* calc max/min values now, as we have a progress dialog */ amitk_data_set_calc_min_max(ds, update_func, update_data); /* set any remaining parameters */ amitk_object_set_name(AMITK_OBJECT(ds),data_set_name); amitk_data_set_set_scale_factor(ds, scale_factor); amitk_data_set_set_voxel_size(ds, voxel_size); amitk_data_set_calc_far_corner(ds); amitk_volume_set_center(AMITK_VOLUME(ds), zero_point); return ds; } /* function to import a file into a data set */ GList * amitk_data_set_import_file(AmitkImportMethod method, int submethod, const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { AmitkDataSet * import_ds=NULL; GList * import_data_sets=NULL; GList * temp_list; gchar * filename_base; gchar * filename_extension; gchar * header_filename=NULL; gchar * raw_filename=NULL; gchar ** frags; gint j; #ifdef AMIDE_LIBMDC_SUPPORT gboolean incorrect_permissions=FALSE; gboolean incorrect_hdr_permissions=FALSE; gboolean incorrect_raw_permissions=FALSE; GtkWidget * question; struct stat file_info; gint return_val; #endif g_return_val_if_fail(filename != NULL, NULL); #ifdef AMIDE_LIBMDC_SUPPORT /* figure out if this is a Siemens/Concorde Header file */ if (strstr(filename, ".hdr") != NULL) { /* try to see if a corresponding raw file exists */ raw_filename = g_strdup(filename); raw_filename[strlen(raw_filename)-4] = '\0'; if (stat(raw_filename, &file_info) != 0) {/* file doesn't exist*/ g_free(raw_filename); raw_filename = NULL; } } else { /* try to see if a header file exists */ header_filename = g_strdup_printf("%s.hdr", filename); if (stat(header_filename, &file_info) != 0) {/* file doesn't exist */ g_free(header_filename); header_filename = NULL; } } #if 1 /* hack for illogical permission problems... we get this sometimes at UCLA as one of our disk servers is a windows machine */ if (stat(filename, &file_info) == 0) incorrect_permissions = (access(filename, R_OK) != 0); if (header_filename != NULL) if (stat(header_filename, &file_info) == 0) incorrect_hdr_permissions = (access(header_filename, R_OK) != 0); if (raw_filename != NULL) if (stat(raw_filename, &file_info) == 0) incorrect_raw_permissions = (access(raw_filename, R_OK) != 0); if (incorrect_permissions || incorrect_hdr_permissions || incorrect_raw_permissions) { /* check if it's okay to change permission of file */ question = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("File has incorrect permissions for reading\nCan I try changing access permissions on:\n %s?"), filename); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val == GTK_RESPONSE_OK) { if (incorrect_permissions) { stat(filename, &file_info); if (chmod(filename, 0400 | file_info.st_mode) != 0) g_warning(_("failed to change read permissions, you're probably not the owner")); /* we'll go ahead and try reading anyway, even if chmod was unsuccessful */ } if (incorrect_hdr_permissions) { stat(header_filename, &file_info); if (chmod(header_filename, 0400 | file_info.st_mode) != 0) g_warning(_("failed to change read permissions, you're probably not the owner")); /* we'll go ahead and try reading anyway, even if chmod was unsuccessful */ } if (incorrect_raw_permissions) { stat(raw_filename, &file_info); if (chmod(raw_filename, 0400 | file_info.st_mode) != 0) g_warning(_("failed to change read permissions on raw data file, you're probably not the owner")); /* we'll go ahead and try reading anyway, even if chmod was unsuccessful */ } } else { /* we hit cancel */ return NULL; } } #endif #endif /* AMITK_LIBMDC_SUPPORT */ /* if we're guessing how to import.... */ if (method == AMITK_IMPORT_METHOD_GUESS) { /* extract the extension of the file */ filename_base = g_path_get_basename(filename); g_strreverse(filename_base); frags = g_strsplit(filename_base, ".", 2); g_free(filename_base); filename_extension = g_strdup(frags[0]); g_strreverse(filename_extension); g_strfreev(frags); #ifdef AMIDE_LIBMDC_SUPPORT if (header_filename != NULL) { method = AMITK_IMPORT_METHOD_LIBMDC; } else #endif #ifdef AMIDE_VISTAIO_SUPPORT if (vistaio_test_vista(filename)) { method = AMITK_IMPORT_METHOD_VISTAIO; } else #endif #ifdef AMIDE_LIBDCMDATA_SUPPORT if (dcmtk_test_dicom(filename)) { method = AMITK_IMPORT_METHOD_DCMTK; } else #endif if ((g_ascii_strcasecmp(filename_extension, "dat")==0) || (g_ascii_strcasecmp(filename_extension, "raw")==0)) { /* .dat and .raw are assumed to be raw data */ method = AMITK_IMPORT_METHOD_RAW; #ifdef AMIDE_LIBECAT_SUPPORT } else if ((g_ascii_strcasecmp(filename_extension, "img")==0) || (g_ascii_strcasecmp(filename_extension, "v")==0) || (g_ascii_strcasecmp(filename_extension, "atn")==0) || (g_ascii_strcasecmp(filename_extension, "scn")==0)) { /* if it appears to be a cti file */ method = AMITK_IMPORT_METHOD_LIBECAT; #endif } else { /* fallback methods */ #ifdef AMIDE_LIBMDC_SUPPORT /* try passing it to the libmdc library.... */ method = AMITK_IMPORT_METHOD_LIBMDC; #else /* unrecognized file type */ g_warning(_("Extension %s not recognized on file: %s\nGuessing File Type"), filename_extension, filename); method = AMITK_IMPORT_METHOD_RAW; #endif } g_free(filename_extension); } switch (method) { #ifdef AMIDE_LIBDCMDATA_SUPPORT case AMITK_IMPORT_METHOD_DCMTK: import_data_sets = dcmtk_import(filename, pstudyname, preferences, update_func, update_data); break; #endif #ifdef AMIDE_VISTAIO_SUPPORT case AMITK_IMPORT_METHOD_VISTAIO: import_ds = vistaio_import(filename, preferences, update_func, update_data); break; #endif #ifdef AMIDE_LIBECAT_SUPPORT case AMITK_IMPORT_METHOD_LIBECAT: import_ds =libecat_import(filename, preferences, update_func, update_data); break; #endif #ifdef AMIDE_LIBMDC_SUPPORT case AMITK_IMPORT_METHOD_LIBMDC: import_ds = libmdc_import(header_filename == NULL ? filename : header_filename, submethod, preferences, update_func, update_data); break; #endif case AMITK_IMPORT_METHOD_RAW: default: import_ds= raw_data_import(filename, preferences); break; } if (raw_filename != NULL) g_free(raw_filename); if (header_filename != NULL) g_free(header_filename); if ((import_ds == NULL) && (import_data_sets == NULL)) return NULL; if (import_data_sets == NULL) { import_data_sets = g_list_append(import_data_sets, import_ds); } /* run through the list, and do some last minute corrections */ temp_list = import_data_sets; while (temp_list != NULL) { import_ds = temp_list->data; /* set the thresholds */ import_ds->threshold_max[0] = import_ds->threshold_max[1] = amitk_data_set_get_global_max(import_ds); import_ds->threshold_min[0] = import_ds->threshold_min[1] = ((amitk_data_set_get_global_min(import_ds) > 0.0) || (import_ds->threshold_max[0] <= 0.0)) ? amitk_data_set_get_global_min(import_ds) : 0.0; import_ds->threshold_ref_frame[1] = AMITK_DATA_SET_NUM_FRAMES(import_ds)-1; /* set some sensible thresholds for CT */ if (AMITK_DATA_SET_MODALITY(import_ds) == AMITK_MODALITY_CT) { if (AMITK_DATA_SET_THRESHOLD_WINDOW(import_ds, AMITK_WINDOW_THORAX_SOFT_TISSUE, AMITK_LIMIT_MAX) < amitk_data_set_get_global_max(import_ds)) for (j=0; j<2; j++) { amitk_data_set_set_threshold_min(import_ds, j, AMITK_DATA_SET_THRESHOLD_WINDOW(import_ds, AMITK_WINDOW_THORAX_SOFT_TISSUE, AMITK_LIMIT_MIN)); amitk_data_set_set_threshold_max(import_ds, j, AMITK_DATA_SET_THRESHOLD_WINDOW(import_ds, AMITK_WINDOW_THORAX_SOFT_TISSUE, AMITK_LIMIT_MAX)); } } /* see if we can drop the offset/reducing scaling dimension */ data_set_drop_intercept(import_ds); data_set_reduce_scaling_dimension(import_ds); if (!((AMITK_DATA_SET_VOXEL_SIZE_Z(import_ds) > 0.0) && (AMITK_DATA_SET_VOXEL_SIZE_Y(import_ds) > 0.0) && (AMITK_DATA_SET_VOXEL_SIZE_X(import_ds) > 0.0))) { g_warning(_("Data Set %s has erroneous voxel size of %gx%gx%g, setting to 1.0x1.0x1.0"), AMITK_OBJECT_NAME(import_ds), AMITK_DATA_SET_VOXEL_SIZE_X(import_ds), AMITK_DATA_SET_VOXEL_SIZE_Y(import_ds), AMITK_DATA_SET_VOXEL_SIZE_Z(import_ds)); amitk_data_set_set_voxel_size(import_ds, one_point); } temp_list = temp_list->next; } return import_data_sets; } /* voxel_size only used if resliced=TRUE */ /* if bounding_box == NULL, will create its own using the minimal necessary */ static gboolean export_raw(AmitkDataSet *ds, const gchar * filename, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel i,j; FILE * file_pointer=NULL; gfloat * row_data=NULL; AmitkVoxel dim; gint divider; gint num_planes, plane; div_t x; gboolean continue_work=TRUE; size_t num_wrote; size_t total_wrote=0; gchar * temp_string; amide_time_t frame_start, frame_duration; AmitkPoint corner; AmitkVolume * output_volume=NULL; AmitkPoint output_start_pt; AmitkDataSet * slice = NULL; AmitkPoint new_offset; AmitkCanvasPoint pixel_size; gboolean successful = FALSE; #ifdef AMIDE_DEBUG g_print("\t- exporting raw data to file %s\n",filename); #endif dim = AMITK_DATA_SET_DIM(ds); if (resliced) { if (bounding_box != NULL) output_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(bounding_box))); else output_volume = amitk_volume_new(); if (output_volume == NULL) goto exit_strategy; if (bounding_box != NULL) { corner = AMITK_VOLUME_CORNER(output_volume); } else { AmitkCorners corners; amitk_volume_get_enclosing_corners(AMITK_VOLUME(ds), AMITK_SPACE(output_volume), corners); corner = point_diff(corners[0], corners[1]); amitk_space_set_offset(AMITK_SPACE(output_volume), amitk_space_s2b(AMITK_SPACE(output_volume), corners[0])); } pixel_size.x = voxel_size.x; pixel_size.y = voxel_size.y; dim.x = ceil(corner.x/voxel_size.x); dim.y = ceil(corner.y/voxel_size.y); dim.z = ceil(corner.z/voxel_size.z); corner.z = voxel_size.z; amitk_volume_set_corner(output_volume, corner); output_start_pt = AMITK_SPACE_OFFSET(output_volume); } g_message("dimensions of output data set will be %dx%dx%dx%dx%d, voxel size of %fx%fx%f", dim.x, dim.y, dim.z, dim.g, dim.t, voxel_size.x, voxel_size.y, voxel_size.z); if ((row_data = g_try_new(gfloat,dim.x)) == NULL) { g_warning(_("Couldn't allocate memory space for row_data")); goto exit_strategy; } /* Note, "wb" is same as "w" on Unix, but not in Windows */ if ((file_pointer = fopen(filename, "wb")) == NULL) { g_warning(_("couldn't open file for writing: %s"),filename); goto exit_strategy; } /* setup the wait dialog */ if (update_func != NULL) { temp_string = g_strdup_printf(_("Exporting Raw Data for:\n %s"), AMITK_OBJECT_NAME(ds)); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } num_planes = dim.g*dim.t*dim.z; plane = 0; divider = ((num_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (num_planes/AMITK_UPDATE_DIVIDER); j = zero_voxel; for(i.t = 0; i.t < dim.t; i.t++) { frame_start = amitk_data_set_get_start_time(ds, i.t) + EPSILON; frame_duration = amitk_data_set_get_frame_duration(ds, i.t) - EPSILON; for (i.g = 0; i.g < dim.g; i.g++) { if (resliced) /* reset the output slice */ amitk_space_set_offset(AMITK_SPACE(output_volume), output_start_pt); for (i.z = 0; (i.z < dim.z) && continue_work; i.z++, plane++) { if (update_func != NULL) { x = div(plane,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, (gdouble) plane/num_planes); } if (resliced) { slice = amitk_data_set_get_slice(ds, frame_start, frame_duration, i.g, pixel_size, output_volume); if ((AMITK_DATA_SET_DIM_X(slice) != dim.x) || (AMITK_DATA_SET_DIM_Y(slice) != dim.y)) { g_warning(_("Error in generating resliced data, %dx%d != %dx%d"), AMITK_DATA_SET_DIM_X(slice), AMITK_DATA_SET_DIM_Y(slice), dim.x, dim.y); goto exit_strategy; } /* advance for next iteration */ new_offset = AMITK_SPACE_OFFSET(output_volume); new_offset.z += voxel_size.z; amitk_space_set_offset(AMITK_SPACE(output_volume), new_offset); } if (resliced) { if (i.z == 0) { gdouble max=0.0; gdouble value=0.0; for (i.y=0, j.y=0; i.y < dim.y; i.y++, j.y++) { for (j.x = 0; j.x < dim.x; j.x++) { value = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice, j); if (value > max) max = value; } } #ifdef AMIDE_DEBUG g_print("slice max %f\tstart-duration %f %f\n", max, frame_start, frame_duration); #endif } } for (i.y=0, j.y=0; i.y < dim.y; i.y++, j.y++) { if (resliced) { for (j.x = 0; j.x < dim.x; j.x++) row_data[j.x] = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice, j); } else { i.x = 3; for (i.x = 0; i.x < dim.x; i.x++) row_data[i.x] = amitk_data_set_get_value(ds, i); } num_wrote = fwrite(row_data, sizeof(gfloat), dim.x, file_pointer); total_wrote += num_wrote; if ( num_wrote != dim.x) { g_warning(_("incomplete save of raw data, wrote %lx (bytes), file: %s"), total_wrote*sizeof(gfloat), filename); goto exit_strategy; } } /* i.y */ if (slice != NULL) slice = amitk_object_unref(slice); } /* i.z */ } } if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); /* if (!continue_work) goto exit_strategy; */ successful = TRUE; exit_strategy: if (file_pointer != NULL) fclose(file_pointer); if (row_data != NULL) g_free(row_data); if (output_volume != NULL) output_volume = amitk_object_unref(output_volume); if (slice != NULL) slice = amitk_object_unref(slice); return successful; } /* if bounding_box == NULL, will create its own using the minimal necessary */ gboolean amitk_data_set_export_to_file(AmitkDataSet *ds, const AmitkExportMethod method, const int submethod, const gchar * filename, const gchar * studyname, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data) { gboolean successful = FALSE; switch (method) { #ifdef AMIDE_LIBDCMDATA_SUPPORT case AMITK_EXPORT_METHOD_DCMTK: successful = dcmtk_export(ds, filename, studyname, resliced, voxel_size, bounding_box, update_func, update_data); break; #endif #ifdef AMIDE_LIBMDC_SUPPORT case AMITK_EXPORT_METHOD_LIBMDC: successful = libmdc_export(ds, filename, submethod, resliced, voxel_size, bounding_box, update_func, update_data); break; #endif case AMITK_EXPORT_METHOD_RAW: default: successful = export_raw(ds, filename, resliced, voxel_size, bounding_box, update_func, update_data); break; } return successful; } /* note, this function is fairly stupid. If you put two different dynamic data sets in, it'll just take the one with the most frames, and use those frame durations */ /* if bounding_box == NULL, will create its own using the minimal necessary */ gboolean amitk_data_sets_export_to_file(GList * data_sets, const AmitkExportMethod method, const int submethod, const gchar * filename, const gchar * studyname, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data) { AmitkDataSet * export_ds=NULL; AmitkVoxel dim; AmitkVolume * volume; GList * temp_data_sets; AmitkDataSet * max_frames_ds; AmitkDataSet * max_gates_ds; AmitkVoxel i_voxel, j_voxel; GList * slices = NULL; GList * temp_slices; AmitkPoint new_offset; amitk_format_DOUBLE_t value; div_t x; gint divider; gint num_planes, plane; gboolean continue_work=TRUE; gchar * temp_string; gchar * export_name; AmitkCanvasPoint pixel_size; AmitkPoint corner; gboolean successful = FALSE; /* setup the wait dialog */ if (update_func != NULL) { temp_string = g_strdup_printf(_("Generating new data set")); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } /* allocate export data set - use the first data set in the list for info */ /* figure out all encompasing corners for the data sets in the base viewing axis */ if (bounding_box != NULL) volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(bounding_box))); else { AmitkCorners corners; volume = amitk_volume_new(); /* base coordinate frame */ if (volume == NULL) { g_warning(_("Could not allocate memory space for volume")); goto exit_strategy; } amitk_volumes_get_enclosing_corners(data_sets, AMITK_SPACE(volume), corners); amitk_space_set_offset(AMITK_SPACE(volume), corners[0]); amitk_volume_set_corner(volume, amitk_space_b2s(AMITK_SPACE(volume), corners[1])); } pixel_size.x = voxel_size.x; pixel_size.y = voxel_size.y; dim.x = ceil(fabs(AMITK_VOLUME_X_CORNER(volume))/voxel_size.x); dim.y = ceil(fabs(AMITK_VOLUME_Y_CORNER(volume))/voxel_size.y); dim.z = ceil(fabs(AMITK_VOLUME_Z_CORNER(volume))/voxel_size.z); dim.t = 1; dim.g = 1; temp_data_sets = data_sets; max_frames_ds = max_gates_ds = data_sets->data; while (temp_data_sets != NULL) { if (AMITK_DATA_SET_NUM_FRAMES(temp_data_sets->data) > dim.t) { dim.t = AMITK_DATA_SET_NUM_FRAMES(temp_data_sets->data); max_frames_ds = temp_data_sets->data; } if (AMITK_DATA_SET_NUM_GATES(temp_data_sets->data) > dim.g) { dim.g = AMITK_DATA_SET_NUM_GATES(temp_data_sets->data); max_gates_ds = temp_data_sets->data; } temp_data_sets = temp_data_sets->next; } export_ds = amitk_data_set_new_with_data(NULL, AMITK_DATA_SET_MODALITY(max_frames_ds), AMITK_FORMAT_DOUBLE, dim, AMITK_SCALING_TYPE_0D); if (export_ds == NULL) { g_warning(_("Failed to allocate export data set")); goto exit_strategy; } /* get a name */ export_name = g_strdup(AMITK_OBJECT_NAME(data_sets->data)); temp_data_sets = data_sets->next; while (temp_data_sets != NULL) { temp_string = g_strdup_printf("%s+%s",export_name, AMITK_OBJECT_NAME(temp_data_sets->data)); g_free(export_name); export_name = temp_string; temp_data_sets = temp_data_sets->next; } amitk_object_set_name(AMITK_OBJECT(export_ds), export_name); g_free(export_name); /* set various other parameters */ amitk_space_copy_in_place(AMITK_SPACE(export_ds), AMITK_SPACE(volume)); amitk_data_set_set_scale_factor(export_ds, 1.0); export_ds->voxel_size.x = voxel_size.x; export_ds->voxel_size.y = voxel_size.y; export_ds->voxel_size.z = voxel_size.z; amitk_data_set_calc_far_corner(export_ds); amitk_raw_data_DOUBLE_initialize_data(AMITK_DATA_SET_RAW_DATA(export_ds), -INFINITY); export_ds->scan_start = AMITK_DATA_SET_SCAN_START(max_frames_ds); amitk_data_set_set_subject_orientation(export_ds, AMITK_DATA_SET_SUBJECT_ORIENTATION(max_frames_ds)); amitk_data_set_set_subject_sex(export_ds, AMITK_DATA_SET_SUBJECT_SEX(max_frames_ds)); for (i_voxel.t = 0; i_voxel.t < dim.t; i_voxel.t++) { amitk_data_set_set_frame_duration(export_ds, i_voxel.t, amitk_data_set_get_frame_duration(max_frames_ds, i_voxel.t)); } /* fill in export data set from the data sets */ corner = AMITK_VOLUME_CORNER(volume); corner.z = voxel_size.z; amitk_volume_set_corner(volume, corner); /* set the z dim of the slices */ j_voxel.t = j_voxel.g = j_voxel.z = 0; num_planes = dim.g*dim.t*dim.z; plane=0; divider = ((num_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (num_planes/AMITK_UPDATE_DIVIDER); for (i_voxel.t=0; (i_voxel.t< dim.t) && continue_work; i_voxel.t++) for (i_voxel.g=0; (i_voxel.gdata), j_voxel); if (finite(value)) { if (value > AMITK_RAW_DATA_DOUBLE_CONTENT(export_ds->raw_data, i_voxel)) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(export_ds->raw_data, i_voxel) = value; } } temp_slices = temp_slices->next; } amitk_objects_unref(slices); slices = NULL; } if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); if (!continue_work) goto exit_strategy; /* we hit cancel */ /* export data set */ switch (method) { #ifdef AMIDE_LIBDCMDATA_SUPPORT case AMITK_EXPORT_METHOD_DCMTK: successful = dcmtk_export(export_ds, filename, studyname, FALSE, zero_point, volume, update_func, update_data); break; #endif #ifdef AMIDE_LIBMDC_SUPPORT case AMITK_EXPORT_METHOD_LIBMDC: /* clean - libmdc handles infinities, etc. badly */ for (i_voxel.t=0; i_voxel.t< dim.t; i_voxel.t++) for (i_voxel.g=0; i_voxel.graw_data, i_voxel))) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(export_ds->raw_data, i_voxel) = 0.0; successful = libmdc_export(export_ds, filename, submethod, FALSE, zero_point, volume, update_func, update_data); break; #endif case AMITK_EXPORT_METHOD_RAW: default: successful = export_raw(export_ds, filename, FALSE, AMITK_DATA_SET_VOXEL_SIZE(export_ds), volume, update_func, update_data); break; } exit_strategy: if (volume != NULL) { amitk_object_unref(volume); volume = NULL; } if (export_ds != NULL) { amitk_object_unref(export_ds); export_ds = NULL; } if (slices != NULL) { amitk_objects_unref(slices); slices = NULL; } return successful; } /* look through the scaling_intercept factors and see if we they're all zero/we can drop them */ static void data_set_drop_intercept(AmitkDataSet * ds) { AmitkVoxel i_voxel; g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (!AMITK_DATA_SET_SCALING_HAS_INTERCEPT(ds)) return; g_return_if_fail(ds->internal_scaling_intercept != NULL); i_voxel = zero_voxel; for (i_voxel.t=0; i_voxel.t < ds->internal_scaling_intercept->dim.t; i_voxel.t++) for (i_voxel.g=0; i_voxel.g < ds->internal_scaling_intercept->dim.g; i_voxel.g++) for (i_voxel.z=0; i_voxel.z < ds->internal_scaling_intercept->dim.z; i_voxel.z++) /* note, the 2D_SCALING_POINTER macro will work for all SCALING_TYPES */ if (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept, i_voxel) != 0.0) return; g_object_unref(ds->internal_scaling_intercept); ds->internal_scaling_intercept=NULL; switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: ds->scaling_type = AMITK_SCALING_TYPE_0D; break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: ds->scaling_type = AMITK_SCALING_TYPE_1D; break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: ds->scaling_type = AMITK_SCALING_TYPE_2D; break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } /* look through the scaling factors, and see if we can reduce the dimensionality */ static void data_set_reduce_scaling_dimension(AmitkDataSet * ds) { AmitkVoxel i_voxel; amitk_format_DOUBLE_t initial_scale_factor; amitk_format_DOUBLE_t initial_scale_intercept=0.0; g_return_if_fail(AMITK_IS_DATA_SET(ds)); if ((AMITK_DATA_SET_SCALING_TYPE(ds) == AMITK_SCALING_TYPE_0D) || (AMITK_DATA_SET_SCALING_TYPE(ds) == AMITK_SCALING_TYPE_0D_WITH_INTERCEPT)) return; i_voxel = zero_voxel; initial_scale_factor = *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, i_voxel); for (i_voxel.t=0; i_voxel.t < ds->internal_scaling_factor->dim.t; i_voxel.t++) for (i_voxel.g=0; i_voxel.g < ds->internal_scaling_factor->dim.g; i_voxel.g++) for (i_voxel.z=0; i_voxel.z < ds->internal_scaling_factor->dim.z; i_voxel.z++) /* note, the 2D_SCALING_POINTER macro will work for all SCALING_TYPES */ if (initial_scale_factor != *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, i_voxel)) return; if (AMITK_DATA_SET_SCALING_HAS_INTERCEPT(ds)) { i_voxel = zero_voxel; initial_scale_intercept = *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept, i_voxel); for (i_voxel.t=0; i_voxel.t < ds->internal_scaling_intercept->dim.t; i_voxel.t++) for (i_voxel.g=0; i_voxel.g < ds->internal_scaling_intercept->dim.g; i_voxel.g++) for (i_voxel.z=0; i_voxel.z < ds->internal_scaling_intercept->dim.z; i_voxel.z++) /* note, the 2D_SCALING_POINTER macro will work for all SCALING_TYPES */ if (initial_scale_intercept != *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept, i_voxel)) return; } g_object_unref(ds->internal_scaling_factor); ds->internal_scaling_factor=NULL; if (AMITK_DATA_SET_SCALING_HAS_INTERCEPT(ds)) { g_object_unref(ds->internal_scaling_intercept); ds->internal_scaling_intercept=NULL; } switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: ds->scaling_type = AMITK_SCALING_TYPE_0D_WITH_INTERCEPT; break; default: ds->scaling_type = AMITK_SCALING_TYPE_0D; break; } ds->internal_scaling_factor = amitk_raw_data_DOUBLE_0D_SCALING_init(initial_scale_factor); if (ds->internal_scaling_factor==NULL) g_error("malloc for internal scaling factor failed - fatal"); if (AMITK_DATA_SET_SCALING_HAS_INTERCEPT(ds)) { ds->internal_scaling_intercept = amitk_raw_data_DOUBLE_0D_SCALING_init(initial_scale_intercept); if (ds->internal_scaling_intercept == NULL) g_error("malloc for internal scaling factor failed - fatal"); } amitk_data_set_set_scale_factor(ds, AMITK_DATA_SET_SCALE_FACTOR(ds)); /* reset the current_scale_factor */ g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } amide_data_t amitk_data_set_get_global_max(AmitkDataSet * ds) { amitk_data_set_calc_min_max_if_needed(ds, NULL, NULL); return ds->global_max; } amide_data_t amitk_data_set_get_global_min(AmitkDataSet * ds) { amitk_data_set_calc_min_max_if_needed(ds, NULL, NULL); return ds->global_min; } amide_data_t amitk_data_set_get_frame_max(AmitkDataSet * ds, const guint frame) { amitk_data_set_calc_min_max_if_needed(ds, NULL, NULL); return ds->frame_max[frame]; } amide_data_t amitk_data_set_get_frame_min(AmitkDataSet * ds, const guint frame) { amitk_data_set_calc_min_max_if_needed(ds, NULL, NULL); return ds->frame_min[frame]; } AmitkColorTable amitk_data_set_get_color_table_to_use(AmitkDataSet * ds, const AmitkViewMode view_mode) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), AMITK_COLOR_TABLE_BW_LINEAR); g_return_val_if_fail(view_mode >= 0, AMITK_COLOR_TABLE_BW_LINEAR); g_return_val_if_fail(view_mode < AMITK_VIEW_MODE_NUM, AMITK_COLOR_TABLE_BW_LINEAR); if ((view_mode != AMITK_VIEW_MODE_SINGLE) && (AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(ds, view_mode))) return AMITK_DATA_SET_COLOR_TABLE(ds, view_mode); else return AMITK_DATA_SET_COLOR_TABLE(ds, AMITK_VIEW_MODE_SINGLE); } void amitk_data_set_set_modality(AmitkDataSet * ds, const AmitkModality modality) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if ( ds->modality != modality) { ds->modality = modality; g_signal_emit(G_OBJECT (ds), data_set_signals[MODALITY_CHANGED], 0); g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } void amitk_data_set_set_scan_start (AmitkDataSet * ds, const amide_time_t start) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->scan_start != start) { ds->scan_start = start; g_signal_emit(G_OBJECT (ds), data_set_signals[TIME_CHANGED], 0); g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } void amitk_data_set_set_frame_duration(AmitkDataSet * ds, const guint frame, amide_time_t duration) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(frame < AMITK_DATA_SET_NUM_FRAMES(ds)); g_return_if_fail(ds->frame_duration != NULL); if (duration < EPSILON) duration = EPSILON; /* guard against bad values */ if (ds->frame_duration[frame] != duration) { ds->frame_duration[frame] = duration; g_signal_emit(G_OBJECT (ds), data_set_signals[TIME_CHANGED], 0); g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } void amitk_data_set_set_voxel_size(AmitkDataSet * ds, const AmitkPoint voxel_size) { GList * children; AmitkPoint ref_point; AmitkPoint scaling; AmitkPoint old_corner; g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (!POINT_EQUAL(AMITK_DATA_SET_VOXEL_SIZE(ds), voxel_size)) { if (AMITK_VOLUME_VALID(ds)) old_corner = AMITK_VOLUME_CORNER(ds); else old_corner = one_point; /* guard for zero's */ if (EQUAL_ZERO(old_corner.x) || EQUAL_ZERO(old_corner.y) || EQUAL_ZERO(old_corner.z)) old_corner = one_point; data_set_set_voxel_size(ds, voxel_size); amitk_data_set_calc_far_corner(ds); scaling = point_div(AMITK_VOLUME_CORNER(ds), old_corner); scaling = amitk_space_s2b_dim(AMITK_SPACE(ds), scaling); ref_point = AMITK_SPACE_OFFSET(ds); /* propagate this scaling operation to the children */ children = AMITK_OBJECT_CHILDREN(ds); while (children != NULL) { amitk_space_scale(children->data, ref_point, scaling); children = children->next; } } } void amitk_data_set_set_thresholding(AmitkDataSet * ds, const AmitkThresholding thresholding) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->thresholding != thresholding) { ds->thresholding = thresholding; g_signal_emit(G_OBJECT (ds), data_set_signals[THRESHOLDING_CHANGED], 0); } } void amitk_data_set_set_threshold_style(AmitkDataSet * ds, const AmitkThresholdStyle threshold_style) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->threshold_style != threshold_style) { ds->threshold_style = threshold_style; g_signal_emit(G_OBJECT (ds), data_set_signals[THRESHOLD_STYLE_CHANGED], 0); } } void amitk_data_set_set_threshold_max(AmitkDataSet * ds, guint which_reference, amide_data_t value) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if ((ds->threshold_max[which_reference] != value) && (value > amitk_data_set_get_global_min(ds))) { ds->threshold_max[which_reference] = value; if (ds->threshold_max[which_reference] < ds->threshold_min[which_reference]) ds->threshold_min[which_reference] = ds->threshold_max[which_reference]-EPSILON*fabs(ds->threshold_max[which_reference]); g_signal_emit(G_OBJECT (ds), data_set_signals[THRESHOLDS_CHANGED], 0); } } void amitk_data_set_set_threshold_min(AmitkDataSet * ds, guint which_reference, amide_data_t value) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if ((ds->threshold_min[which_reference] != value ) && (value < amitk_data_set_get_global_max(ds))) { ds->threshold_min[which_reference] = value; if (ds->threshold_min[which_reference] > ds->threshold_max[which_reference]) ds->threshold_max[which_reference] = ds->threshold_min[which_reference]+EPSILON*fabs(ds->threshold_min[which_reference]); g_signal_emit(G_OBJECT (ds), data_set_signals[THRESHOLDS_CHANGED], 0); } } void amitk_data_set_set_threshold_ref_frame(AmitkDataSet * ds, guint which_reference, guint frame) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->threshold_ref_frame[which_reference] != frame) { ds->threshold_ref_frame[which_reference] = frame; g_signal_emit(G_OBJECT (ds), data_set_signals[THRESHOLDS_CHANGED], 0); } } void amitk_data_set_set_color_table(AmitkDataSet * ds, const AmitkViewMode view_mode, const AmitkColorTable new_color_table) { AmitkViewMode i_view_mode; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(view_mode >= 0); g_return_if_fail(view_mode < AMITK_VIEW_MODE_NUM); if (new_color_table != ds->color_table[view_mode]) { ds->color_table[view_mode] = new_color_table; g_signal_emit(G_OBJECT (ds), data_set_signals[COLOR_TABLE_CHANGED], 0, view_mode); if (view_mode == AMITK_VIEW_MODE_SINGLE) { for (i_view_mode=AMITK_VIEW_MODE_LINKED_2WAY; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { if (!AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(ds, i_view_mode)) g_signal_emit(G_OBJECT (ds), data_set_signals[COLOR_TABLE_CHANGED], 0, i_view_mode); } } } } void amitk_data_set_set_color_table_independent(AmitkDataSet * ds, const AmitkViewMode view_mode, const gboolean independent) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(view_mode >= AMITK_VIEW_MODE_SINGLE); g_return_if_fail(view_mode < AMITK_VIEW_MODE_NUM); if (independent != ds->color_table_independent[view_mode]) { ds->color_table_independent[view_mode] = independent; g_signal_emit(G_OBJECT (ds), data_set_signals[COLOR_TABLE_INDEPENDENT_CHANGED], 0, view_mode); if (ds->color_table[view_mode] != ds->color_table[AMITK_VIEW_MODE_SINGLE]) g_signal_emit(G_OBJECT (ds), data_set_signals[COLOR_TABLE_CHANGED], 0, view_mode); } } void amitk_data_set_set_interpolation(AmitkDataSet * ds, const AmitkInterpolation new_interpolation) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->interpolation != new_interpolation) { ds->interpolation = new_interpolation; g_signal_emit(G_OBJECT (ds), data_set_signals[INTERPOLATION_CHANGED], 0); } return; } void amitk_data_set_set_rendering(AmitkDataSet * ds, const AmitkRendering new_rendering) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->rendering != new_rendering) { ds->rendering = new_rendering; g_signal_emit(G_OBJECT (ds), data_set_signals[RENDERING_CHANGED], 0); } return; } void amitk_data_set_set_subject_orientation(AmitkDataSet * ds, const AmitkSubjectOrientation subject_orientation) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->subject_orientation != subject_orientation) { ds->subject_orientation = subject_orientation; g_signal_emit(G_OBJECT (ds), data_set_signals[SUBJECT_ORIENTATION_CHANGED], 0); } return; } void amitk_data_set_set_subject_sex(AmitkDataSet * ds, const AmitkSubjectSex subject_sex) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->subject_sex != subject_sex) { ds->subject_sex = subject_sex; g_signal_emit(G_OBJECT (ds), data_set_signals[SUBJECT_SEX_CHANGED], 0); } return; } /* sets the scan date of a data set note: no error checking is done on the date, as of yet */ void amitk_data_set_set_scan_date(AmitkDataSet * ds, const gchar * new_date) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->scan_date != NULL) { g_free(ds->scan_date); ds->scan_date = NULL; } if (new_date != NULL) { ds->scan_date = g_strdup(new_date); g_strdelimit(ds->scan_date, "\n", ' '); /* turns newlines to white space */ g_strstrip(ds->scan_date); /* removes trailing and leading white space */ } else { ds->scan_date = g_strdup(_("unknown")); } return; } /* sets the subject name associated with the data set */ void amitk_data_set_set_subject_name(AmitkDataSet * ds, const gchar * new_name) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->subject_name != NULL) { g_free(ds->subject_name); ds->subject_name = NULL; } if (new_name != NULL) { ds->subject_name = g_strdup(new_name); g_strdelimit(ds->subject_name, "\n", ' '); /* turns newlines to white space */ g_strstrip(ds->subject_name); /* removes trailing and leading white space */ } else { ds->subject_name = g_strdup(_("unknown")); } return; } /* sets the subject id associated with the data set */ void amitk_data_set_set_subject_id(AmitkDataSet * ds, const gchar * new_id) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->subject_id != NULL) { g_free(ds->subject_id); ds->subject_id = NULL; } if (new_id != NULL) { ds->subject_id = g_strdup(new_id); g_strdelimit(ds->subject_id, "\n", ' '); /* turns newlines to white space */ g_strstrip(ds->subject_id); /* removes trailing and leading white space */ } else { ds->subject_id = g_strdup(_("unknown")); } return; } /* sets the subject's date of birth note: no error checking is done on the date, as of yet */ void amitk_data_set_set_subject_dob(AmitkDataSet * ds, const gchar * new_dob) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->subject_dob != NULL) { g_free(ds->subject_dob); ds->subject_dob = NULL; } if (new_dob != NULL) { ds->subject_dob = g_strdup(new_dob); g_strdelimit(ds->subject_dob, "\n", ' '); /* turns newlines to white space */ g_strstrip(ds->subject_dob); /* removes trailing and leading white space */ } else { ds->subject_dob = g_strdup(_("unknown")); } return; } /* sets the series number - parameter used by dicom */ void amitk_data_set_set_series_number(AmitkDataSet * ds, const gint new_series_number) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->series_number != new_series_number) { ds->series_number = new_series_number; } return; } /* sets the dicom image type of the data set */ void amitk_data_set_set_dicom_image_type(AmitkDataSet * ds, const gchar * new_image_type) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->dicom_image_type != NULL) { g_free(ds->dicom_image_type); ds->dicom_image_type = NULL; } if (new_image_type != NULL) { ds->dicom_image_type = g_strdup(new_image_type); g_strdelimit(ds->dicom_image_type, "\n", ' '); /* turns newlines to white space */ g_strstrip(ds->dicom_image_type); /* removes trailing and leading white space */ } else { ; /* leave it as NULL */ } return; } /* used when changing the external scale factor, so that we can keep a pregenerated scaling factor */ void amitk_data_set_set_scale_factor(AmitkDataSet * ds, amide_data_t new_scale_factor) { AmitkVoxel i; gint j; amide_data_t scaling; gboolean need_update = FALSE; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(ds->internal_scaling_factor != NULL); if (new_scale_factor <= 0.0) return; if ((ds->scale_factor != new_scale_factor) || (ds->current_scaling_factor == NULL) || (ds->current_scaling_factor->dim.x != ds->internal_scaling_factor->dim.x) || (ds->current_scaling_factor->dim.y != ds->internal_scaling_factor->dim.y) || (ds->current_scaling_factor->dim.z != ds->internal_scaling_factor->dim.z) || (ds->current_scaling_factor->dim.g != ds->internal_scaling_factor->dim.g) || (ds->current_scaling_factor->dim.t != ds->internal_scaling_factor->dim.t)) { need_update = TRUE; } else { /* make absolutely sure we don't need an update */ for(i.t = 0; i.t < ds->current_scaling_factor->dim.t; i.t++) for (i.g = 0; i.g < ds->current_scaling_factor->dim.g; i.g++) for (i.z = 0; i.z < ds->current_scaling_factor->dim.z; i.z++) for (i.y = 0; i.y < ds->current_scaling_factor->dim.y; i.y++) for (i.x = 0; i.x < ds->current_scaling_factor->dim.x; i.x++) if (AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->current_scaling_factor, i) != ds->scale_factor * AMITK_RAW_DATA_DOUBLE_CONTENT(ds->internal_scaling_factor, i)) need_update = TRUE; } if (need_update) { if (ds->current_scaling_factor == NULL) /* first time */ scaling = 1.0; else scaling = new_scale_factor/ds->scale_factor; ds->scale_factor = new_scale_factor; if (ds->current_scaling_factor != NULL) if ((ds->current_scaling_factor->dim.x != ds->internal_scaling_factor->dim.x) || (ds->current_scaling_factor->dim.y != ds->internal_scaling_factor->dim.y) || (ds->current_scaling_factor->dim.z != ds->internal_scaling_factor->dim.z) || (ds->current_scaling_factor->dim.g != ds->internal_scaling_factor->dim.g) || (ds->current_scaling_factor->dim.t != ds->internal_scaling_factor->dim.t)) { g_object_unref(ds->current_scaling_factor); ds->current_scaling_factor = NULL; } if (ds->current_scaling_factor == NULL) { ds->current_scaling_factor = amitk_raw_data_new_with_data(ds->internal_scaling_factor->format, ds->internal_scaling_factor->dim); g_return_if_fail(ds->current_scaling_factor != NULL); } for(i.t = 0; i.t < ds->current_scaling_factor->dim.t; i.t++) for (i.g = 0; i.g < ds->current_scaling_factor->dim.g; i.g++) for (i.z = 0; i.z < ds->current_scaling_factor->dim.z; i.z++) for (i.y = 0; i.y < ds->current_scaling_factor->dim.y; i.y++) for (i.x = 0; i.x < ds->current_scaling_factor->dim.x; i.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->current_scaling_factor, i) = ds->scale_factor * AMITK_RAW_DATA_DOUBLE_CONTENT(ds->internal_scaling_factor, i); /* adjust all thresholds and other variables so they remain constant relative the change in scale factors */ for (j=0; j<2; j++) { ds->threshold_max[j] *= scaling; ds->threshold_min[j] *= scaling; } ds->global_max *= scaling; ds->global_min *= scaling; if ((AMITK_DATA_SET_RAW_DATA(ds) != NULL) && (ds->frame_max != NULL) && (ds->frame_min != NULL)) for (j=0; j < AMITK_DATA_SET_NUM_FRAMES(ds); j++) { ds->frame_max[j] *= scaling; ds->frame_min[j] *= scaling; } /* and emit the signal */ g_signal_emit (G_OBJECT (ds), data_set_signals[SCALE_FACTOR_CHANGED], 0); g_signal_emit (G_OBJECT (ds), data_set_signals[INVALIDATE_SLICE_CACHE], 0); g_signal_emit (G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); g_signal_emit (G_OBJECT (ds), data_set_signals[THRESHOLDS_CHANGED], 0); } return; } static amide_data_t calculate_scale_factor(AmitkDataSet * ds) { amide_data_t value; switch(ds->conversion) { case AMITK_CONVERSION_STRAIGHT: value = AMITK_DATA_SET_SCALE_FACTOR(ds); break; case AMITK_CONVERSION_PERCENT_ID_PER_CC: if (!isfinite(ds->injected_dose) || (EQUAL_ZERO(ds->injected_dose))) value = 1.0; else value = 100.0*ds->cylinder_factor/ds->injected_dose; break; case AMITK_CONVERSION_SUV: if (!isfinite(ds->subject_weight) || (EQUAL_ZERO(ds->subject_weight))) value = 1.0; else if (!finite(ds->injected_dose) || (EQUAL_ZERO(ds->injected_dose))) value = 1.0; else value = ds->cylinder_factor/(ds->injected_dose/(1000.0*ds->subject_weight)); break; default: value = 1.0; g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } return value; } void amitk_data_set_set_conversion(AmitkDataSet * ds, AmitkConversion new_conversion) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->conversion != new_conversion) { ds->conversion = new_conversion; amitk_data_set_set_scale_factor(ds, calculate_scale_factor(ds)); g_signal_emit(G_OBJECT (ds), data_set_signals[CONVERSION_CHANGED], 0); } } void amitk_data_set_set_injected_dose(AmitkDataSet * ds,amide_data_t new_injected_dose) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->injected_dose != new_injected_dose) { ds->injected_dose = new_injected_dose; amitk_data_set_set_scale_factor(ds, calculate_scale_factor(ds)); } } void amitk_data_set_set_subject_weight(AmitkDataSet * ds,amide_data_t new_subject_weight) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->subject_weight != new_subject_weight) { ds->subject_weight = new_subject_weight; amitk_data_set_set_scale_factor(ds, calculate_scale_factor(ds)); } } void amitk_data_set_set_cylinder_factor(AmitkDataSet * ds, amide_data_t new_cylinder_factor) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (ds->cylinder_factor != new_cylinder_factor) { ds->cylinder_factor = new_cylinder_factor; amitk_data_set_set_scale_factor(ds, calculate_scale_factor(ds)); } } void amitk_data_set_set_displayed_dose_unit(AmitkDataSet * ds, AmitkDoseUnit new_dose_unit) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->displayed_dose_unit = new_dose_unit; } void amitk_data_set_set_displayed_weight_unit(AmitkDataSet * ds, AmitkWeightUnit new_weight_unit) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->displayed_weight_unit = new_weight_unit; } void amitk_data_set_set_displayed_cylinder_unit(AmitkDataSet * ds, AmitkCylinderUnit new_cylinder_unit) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->displayed_cylinder_unit = new_cylinder_unit; } void amitk_data_set_set_inversion_time(AmitkDataSet * ds, amide_time_t new_inversion_time) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->inversion_time = new_inversion_time; } void amitk_data_set_set_echo_time(AmitkDataSet * ds, amide_time_t new_echo_time) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->echo_time = new_echo_time; } void amitk_data_set_set_diffusion_b_value(AmitkDataSet * ds, gdouble b_value) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->diffusion_b_value = b_value; } void amitk_data_set_set_diffusion_direction(AmitkDataSet * ds, AmitkPoint direction) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); ds->diffusion_direction = direction; } void amitk_data_set_set_threshold_window(AmitkDataSet * ds, const AmitkWindow window, const AmitkLimit limit, const amide_data_t value) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (!REAL_EQUAL(AMITK_DATA_SET_THRESHOLD_WINDOW(ds, window, limit), value)) { ds->threshold_window[window][limit] = value; } g_signal_emit (G_OBJECT (ds), data_set_signals[WINDOWS_CHANGED], 0); } void amitk_data_set_set_view_start_gate(AmitkDataSet * ds, amide_intpoint_t start_gate) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if ((AMITK_DATA_SET_VIEW_START_GATE(ds) != start_gate) && (start_gate >= 0) && (start_gate < AMITK_DATA_SET_NUM_GATES(ds))){ ds->view_start_gate = start_gate; if (ds->view_start_gate > ds->view_end_gate) ds->num_view_gates = AMITK_DATA_SET_NUM_GATES(ds) - (ds->view_start_gate-ds->view_end_gate-1); else ds->num_view_gates = ds->view_end_gate-ds->view_start_gate+1; g_signal_emit(G_OBJECT (ds), data_set_signals[VIEW_GATES_CHANGED], 0); } return; } void amitk_data_set_set_view_end_gate(AmitkDataSet * ds, amide_intpoint_t end_gate) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); if ((AMITK_DATA_SET_VIEW_END_GATE(ds) != end_gate) && (end_gate >= 0) && (end_gate < AMITK_DATA_SET_NUM_GATES(ds))) { ds->view_end_gate = end_gate; if (ds->view_start_gate > ds->view_end_gate) ds->num_view_gates = AMITK_DATA_SET_NUM_GATES(ds) - (ds->view_start_gate-ds->view_end_gate-1); else ds->num_view_gates = ds->view_end_gate-ds->view_start_gate+1; g_signal_emit(G_OBJECT (ds), data_set_signals[VIEW_GATES_CHANGED], 0); } return; } void amitk_data_set_set_gate_time(AmitkDataSet * ds, const guint gate, amide_time_t time) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(gate < AMITK_DATA_SET_NUM_GATES(ds)); g_return_if_fail(ds->gate_time != NULL); if (ds->gate_time[gate] != time) { ds->gate_time[gate] = time; g_signal_emit(G_OBJECT (ds), data_set_signals[VIEW_GATES_CHANGED], 0); g_signal_emit(G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } amide_time_t amitk_data_set_get_gate_time(const AmitkDataSet * ds, guint gate) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 0.0); g_return_val_if_fail(ds->gate_time != NULL, 0.0); if (gate >= AMITK_DATA_SET_NUM_GATES(ds)) return 0.0; return ds->gate_time[gate]; } /* returns the start time of the given frame */ amide_time_t amitk_data_set_get_start_time(const AmitkDataSet * ds, const guint frame) { amide_time_t time; guint i_frame; guint check_frame; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 0.0); if (frame >= AMITK_DATA_SET_NUM_FRAMES(ds)) check_frame = AMITK_DATA_SET_NUM_FRAMES(ds)-1; else check_frame = frame; time = ds->scan_start; for(i_frame=0;i_frame= AMITK_DATA_SET_NUM_FRAMES(ds)) check_frame = AMITK_DATA_SET_NUM_FRAMES(ds)-1; else check_frame = frame; return (amitk_data_set_get_start_time(ds, check_frame) +amitk_data_set_get_frame_duration(ds, check_frame)); } /* returns the midpoint of a given frame */ amide_time_t amitk_data_set_get_midpt_time(const AmitkDataSet * ds, const guint frame) { guint check_frame; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 1.0); if (frame >= AMITK_DATA_SET_NUM_FRAMES(ds)) check_frame = AMITK_DATA_SET_NUM_FRAMES(ds)-1; else check_frame = frame; return (amitk_data_set_get_start_time(ds, check_frame) + amitk_data_set_get_frame_duration(ds, check_frame)/2.0); } /* returns the frame that corresponds to the time */ guint amitk_data_set_get_frame(const AmitkDataSet * ds, const amide_time_t time) { amide_time_t start, end; guint i_frame; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 0); start = amitk_data_set_get_start_time(ds, 0); if (time <= start) return 0; for(i_frame=0; i_frame < AMITK_DATA_SET_NUM_FRAMES(ds); i_frame++) { start = amitk_data_set_get_start_time(ds, i_frame); end = amitk_data_set_get_end_time(ds, i_frame); if ((start <= time) && (time <= end)) return i_frame; } /* must be past the end */ return AMITK_DATA_SET_NUM_FRAMES(ds)-1; } amide_time_t amitk_data_set_get_frame_duration (const AmitkDataSet * ds, guint frame) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 1.0); g_return_val_if_fail(ds->frame_duration != NULL, 1.0); if (frame >= AMITK_DATA_SET_NUM_FRAMES(ds)) frame = AMITK_DATA_SET_NUM_FRAMES(ds)-1; return ds->frame_duration[frame]; } /* return the minimal frame duration in this data set */ amide_time_t amitk_data_set_get_min_frame_duration(const AmitkDataSet * ds) { amide_time_t min_frame_duration; guint i_frame; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 1.0); min_frame_duration = amitk_data_set_get_frame_duration(ds,0); for(i_frame=1;i_frameraw_data->dim, ds->voxel_size, new_point); amitk_volume_set_corner(AMITK_VOLUME(ds), new_point); return; } static void (*calc_slice_min_max_func[AMITK_FORMAT_NUM][AMITK_SCALING_TYPE_NUM])(AmitkDataSet *, const amide_intpoint_t, const amide_intpoint_t, const amide_intpoint_t, amitk_format_DOUBLE_t *, amitk_format_DOUBLE_t *) = { {amitk_data_set_UBYTE_0D_SCALING_calc_slice_min_max, amitk_data_set_UBYTE_1D_SCALING_calc_slice_min_max, amitk_data_set_UBYTE_2D_SCALING_calc_slice_min_max, amitk_data_set_UBYTE_0D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_UBYTE_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_UBYTE_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_SBYTE_0D_SCALING_calc_slice_min_max, amitk_data_set_SBYTE_1D_SCALING_calc_slice_min_max, amitk_data_set_SBYTE_2D_SCALING_calc_slice_min_max, amitk_data_set_SBYTE_0D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_SBYTE_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_SBYTE_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_USHORT_0D_SCALING_calc_slice_min_max,amitk_data_set_USHORT_1D_SCALING_calc_slice_min_max, amitk_data_set_USHORT_2D_SCALING_calc_slice_min_max,amitk_data_set_USHORT_0D_SCALING_INTERCEPT_calc_slice_min_max,amitk_data_set_USHORT_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_USHORT_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_SSHORT_0D_SCALING_calc_slice_min_max,amitk_data_set_SSHORT_1D_SCALING_calc_slice_min_max, amitk_data_set_SSHORT_2D_SCALING_calc_slice_min_max,amitk_data_set_SSHORT_0D_SCALING_INTERCEPT_calc_slice_min_max,amitk_data_set_SSHORT_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_SSHORT_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_UINT_0D_SCALING_calc_slice_min_max, amitk_data_set_UINT_1D_SCALING_calc_slice_min_max, amitk_data_set_UINT_2D_SCALING_calc_slice_min_max, amitk_data_set_UINT_0D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_UINT_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_UINT_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_SINT_0D_SCALING_calc_slice_min_max, amitk_data_set_SINT_1D_SCALING_calc_slice_min_max, amitk_data_set_SINT_2D_SCALING_calc_slice_min_max, amitk_data_set_SINT_0D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_SINT_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_SINT_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_FLOAT_0D_SCALING_calc_slice_min_max, amitk_data_set_FLOAT_1D_SCALING_calc_slice_min_max, amitk_data_set_FLOAT_2D_SCALING_calc_slice_min_max, amitk_data_set_FLOAT_0D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_FLOAT_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_FLOAT_2D_SCALING_INTERCEPT_calc_slice_min_max }, {amitk_data_set_DOUBLE_0D_SCALING_calc_slice_min_max,amitk_data_set_DOUBLE_1D_SCALING_calc_slice_min_max, amitk_data_set_DOUBLE_2D_SCALING_calc_slice_min_max,amitk_data_set_DOUBLE_0D_SCALING_INTERCEPT_calc_slice_min_max,amitk_data_set_DOUBLE_1D_SCALING_INTERCEPT_calc_slice_min_max, amitk_data_set_DOUBLE_2D_SCALING_INTERCEPT_calc_slice_min_max } }; void amitk_data_set_slice_calc_min_max (AmitkDataSet * ds, const amide_intpoint_t frame, const amide_intpoint_t gate, const amide_intpoint_t z, amitk_format_DOUBLE_t * pmin, amitk_format_DOUBLE_t * pmax) { (*calc_slice_min_max_func[ds->raw_data->format][ds->scaling_type])(ds, frame, gate, z, pmin, pmax); } /* function to calculate the max and min over the data frames */ void amitk_data_set_calc_min_max(AmitkDataSet * ds, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel i; amide_data_t max, min, temp; amide_data_t slice_max, slice_min; div_t x; gint divider; gint total_planes; gint i_plane; gchar * temp_string; AmitkVoxel dim; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(ds->raw_data != NULL); dim = AMITK_DATA_SET_DIM(ds); /* allocate the arrays if we haven't already */ if (ds->frame_max == NULL) { ds->frame_max = amitk_data_set_get_frame_min_max_mem(ds); ds->frame_min = amitk_data_set_get_frame_min_max_mem(ds); } g_return_if_fail(ds->frame_max != NULL); g_return_if_fail(ds->frame_min != NULL); /* note, we can't cancel this */ if (update_func != NULL) { temp_string = g_strdup_printf(_("Calculating Max/Min Values for:\n %s"), AMITK_OBJECT_NAME(ds) == NULL ? "dataset" : AMITK_OBJECT_NAME(ds)); (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = AMITK_DATA_SET_TOTAL_PLANES(ds); divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); i_plane=0; for (i.t = 0; i.t < dim.t; i.t++) { i.x = i.y = i.z = i.g = 0; temp = amitk_data_set_get_value(ds,i); if (finite(temp)) max = min = temp; else max = min = 0.0; /* just throw in zero */ for (i.g = 0; i.g < dim.g; i.g++) { for (i.z = 0; i.z < dim.z; i.z++, i_plane++) { if (update_func != NULL) { x = div(i_plane, divider); if (x.rem == 0) (*update_func)(update_data, NULL, ((gdouble) i_plane)/((gdouble)total_planes)); } amitk_data_set_slice_calc_min_max(ds, i.t, i.g, i.z, &slice_min, &slice_max); if (finite(slice_min)) if (slice_min < min) min = slice_min; if (finite(slice_max)) if (slice_max > max) max = slice_max; } } ds->frame_max[i.t] = max; ds->frame_min[i.t] = min; #ifdef AMIDE_DEBUG if (dim.z > 1) /* don't print for slices */ g_print("\tframe %d max %5.3g frame min %5.3g\n",i.t, ds->frame_max[i.t],ds->frame_min[i.t]); #endif } if (update_func != NULL) (*update_func)(update_data, NULL, (gdouble) 2.0); /* remove progress bar */ /* calc the global max/min */ ds->global_max = ds->frame_max[0]; ds->global_min = ds->frame_min[0]; for (i.t=1; i.tglobal_max < ds->frame_max[i.t]) ds->global_max = ds->frame_max[i.t]; if (ds->global_min > ds->frame_min[i.t]) ds->global_min = ds->frame_min[i.t]; } /* note that we've calculated the max and mins */ ds->min_max_calculated = TRUE; #ifdef AMIDE_DEBUG if (AMITK_DATA_SET_DIM_Z(ds) > 1) /* don't print for slices */ g_print("\tglobal max %5.3g global min %5.3g\n",ds->global_max,ds->global_min); #endif return; } void amitk_data_set_calc_min_max_if_needed(AmitkDataSet * ds, AmitkUpdateFunc update_func, gpointer update_data) { if (!ds->min_max_calculated) amitk_data_set_calc_min_max(ds, update_func, update_data); return; } amide_data_t amitk_data_set_get_max(AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration) { guint start_frame; guint end_frame; guint i_frame; amide_time_t used_start, used_end, used_duration; amide_time_t ds_start, ds_end; amide_data_t max; amide_data_t time_weight; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 1.0); g_return_val_if_fail(duration >= 0.0, 1.0); /* figure out what frames of this data set to use */ used_start = start; start_frame = amitk_data_set_get_frame(ds, used_start); ds_start = amitk_data_set_get_start_time(ds, start_frame); used_end = start+duration; end_frame = amitk_data_set_get_frame(ds, used_end); ds_end = amitk_data_set_get_end_time(ds, end_frame); if (start_frame == end_frame) { max = amitk_data_set_get_frame_max(ds, start_frame); } else { if (ds_end < used_end) used_end = ds_end; if (ds_start > used_start) used_start = ds_start; used_duration = used_end-used_start; max = 0; for (i_frame=start_frame; i_frame <= end_frame; i_frame++) { if (i_frame == start_frame) time_weight = (amitk_data_set_get_end_time(ds, start_frame)-used_start)/used_duration; else if (i_frame == end_frame) time_weight = (used_end-amitk_data_set_get_start_time(ds, end_frame))/used_duration; else time_weight = amitk_data_set_get_frame_duration(ds, i_frame)/used_duration; max += time_weight*amitk_data_set_get_frame_max(ds, i_frame); } } return max; } amide_data_t amitk_data_set_get_min(AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration) { guint start_frame; guint end_frame; guint i_frame; amide_time_t used_start, used_end, used_duration; amide_time_t ds_start, ds_end; amide_data_t min; amide_data_t time_weight; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), 0.0); g_return_val_if_fail(duration>=0.0, 0.0); /* figure out what frames of this data set to use */ used_start = start; start_frame = amitk_data_set_get_frame(ds, used_start); ds_start = amitk_data_set_get_start_time(ds, start_frame); used_end = start+duration; end_frame = amitk_data_set_get_frame(ds, used_end); ds_end = amitk_data_set_get_end_time(ds, end_frame); if (start_frame == end_frame) { min = amitk_data_set_get_frame_min(ds, start_frame); } else { if (ds_end < used_end) used_end = ds_end; if (ds_start > used_start) used_start = ds_start; used_duration = used_end-used_start; min = 0; for (i_frame=start_frame; i_frame <= end_frame; i_frame++) { if (i_frame == start_frame) time_weight = (amitk_data_set_get_end_time(ds, start_frame)-used_start)/used_duration; else if (i_frame == end_frame) time_weight = (used_end-amitk_data_set_get_start_time(ds, end_frame))/used_duration; else time_weight = amitk_data_set_get_frame_duration(ds, i_frame)/used_duration; min += time_weight*amitk_data_set_get_frame_min(ds, i_frame); } } return min; } /* figure out the min and max threshold values given a threshold type */ /* slice is only needed for THRESHOLDING_PER_SLICE */ /* valid values for start and duration only needed for THRESHOLDING_PER_FRAME and THRESHOLDING_INTERPOLATE_FRAMES */ void amitk_data_set_get_thresholding_min_max(AmitkDataSet * ds, AmitkDataSet * slice, const amide_time_t start, const amide_time_t duration, amide_data_t * min, amide_data_t * max) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); /* get the max/min values for thresholding */ switch(AMITK_DATA_SET_THRESHOLDING(ds)) { case AMITK_THRESHOLDING_PER_SLICE: { amide_data_t slice_max,slice_min; amide_data_t threshold_range; g_return_if_fail(AMITK_IS_DATA_SET(slice)); /* find the slice's max and min, and then adjust these values to * correspond to the current threshold values */ slice_max = amitk_data_set_get_global_max(slice); slice_min = amitk_data_set_get_global_min(slice); threshold_range = amitk_data_set_get_global_max(ds)-amitk_data_set_get_global_min(ds); *max = ds->threshold_max[0]*(slice_max-slice_min)/threshold_range; *min = ds->threshold_min[0]*(slice_max-slice_min)/threshold_range; } break; case AMITK_THRESHOLDING_PER_FRAME: { amide_data_t frame_max,frame_min; amide_data_t threshold_range; frame_max = amitk_data_set_get_max(ds, start,duration); frame_min = amitk_data_set_get_min(ds, start,duration); threshold_range = amitk_data_set_get_global_max(ds)-amitk_data_set_get_global_min(ds); *max = ds->threshold_max[0]*(frame_max-frame_min)/threshold_range; *min = ds->threshold_min[0]*(frame_max-frame_min)/threshold_range; } break; case AMITK_THRESHOLDING_INTERPOLATE_FRAMES: { guint middle_frame; if (ds->threshold_ref_frame[1]==ds->threshold_ref_frame[0]) { *max = ds->threshold_max[0]; *min = ds->threshold_min[0]; } else { middle_frame = amitk_data_set_get_frame(ds, start+duration/2.0); if (middle_frame < ds->threshold_ref_frame[0]) middle_frame = ds->threshold_ref_frame[0]; else if (middle_frame > ds->threshold_ref_frame[1]) middle_frame = ds->threshold_ref_frame[1]; *max= (((ds->threshold_ref_frame[1]-middle_frame)*ds->threshold_max[0]+ (middle_frame-ds->threshold_ref_frame[0])*ds->threshold_max[1]) /(ds->threshold_ref_frame[1]-ds->threshold_ref_frame[0])); *min= (((ds->threshold_ref_frame[1]-middle_frame)*ds->threshold_min[0]+ (middle_frame-ds->threshold_ref_frame[0])*ds->threshold_min[1]) /(ds->threshold_ref_frame[1]-ds->threshold_ref_frame[0])); } } break; case AMITK_THRESHOLDING_GLOBAL: *max = ds->threshold_max[0]; *min = ds->threshold_min[0]; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return; } static void (*calc_distribution_func[AMITK_FORMAT_NUM][AMITK_SCALING_TYPE_NUM])(AmitkDataSet *, AmitkUpdateFunc, gpointer) = { {amitk_data_set_UBYTE_0D_SCALING_calc_distribution, amitk_data_set_UBYTE_1D_SCALING_calc_distribution, amitk_data_set_UBYTE_2D_SCALING_calc_distribution, amitk_data_set_UBYTE_0D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_UBYTE_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_UBYTE_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_SBYTE_0D_SCALING_calc_distribution, amitk_data_set_SBYTE_1D_SCALING_calc_distribution, amitk_data_set_SBYTE_2D_SCALING_calc_distribution, amitk_data_set_SBYTE_0D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_SBYTE_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_SBYTE_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_USHORT_0D_SCALING_calc_distribution,amitk_data_set_USHORT_1D_SCALING_calc_distribution, amitk_data_set_USHORT_2D_SCALING_calc_distribution,amitk_data_set_USHORT_0D_SCALING_INTERCEPT_calc_distribution,amitk_data_set_USHORT_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_USHORT_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_SSHORT_0D_SCALING_calc_distribution,amitk_data_set_SSHORT_1D_SCALING_calc_distribution, amitk_data_set_SSHORT_2D_SCALING_calc_distribution,amitk_data_set_SSHORT_0D_SCALING_INTERCEPT_calc_distribution,amitk_data_set_SSHORT_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_SSHORT_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_UINT_0D_SCALING_calc_distribution, amitk_data_set_UINT_1D_SCALING_calc_distribution, amitk_data_set_UINT_2D_SCALING_calc_distribution, amitk_data_set_UINT_0D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_UINT_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_UINT_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_SINT_0D_SCALING_calc_distribution, amitk_data_set_SINT_1D_SCALING_calc_distribution, amitk_data_set_SINT_2D_SCALING_calc_distribution, amitk_data_set_SINT_0D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_SINT_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_SINT_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_FLOAT_0D_SCALING_calc_distribution, amitk_data_set_FLOAT_1D_SCALING_calc_distribution, amitk_data_set_FLOAT_2D_SCALING_calc_distribution, amitk_data_set_FLOAT_0D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_FLOAT_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_FLOAT_2D_SCALING_INTERCEPT_calc_distribution }, {amitk_data_set_DOUBLE_0D_SCALING_calc_distribution,amitk_data_set_DOUBLE_1D_SCALING_calc_distribution, amitk_data_set_DOUBLE_2D_SCALING_calc_distribution,amitk_data_set_DOUBLE_0D_SCALING_INTERCEPT_calc_distribution,amitk_data_set_DOUBLE_1D_SCALING_INTERCEPT_calc_distribution, amitk_data_set_DOUBLE_2D_SCALING_INTERCEPT_calc_distribution } }; /* generate the distribution array for a data set */ void amitk_data_set_calc_distribution(AmitkDataSet * ds, AmitkUpdateFunc update_func, gpointer update_data) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(ds->raw_data != NULL); /* check that the distribution is the right size. This may not be the case if we've changed AMITK_DATA_SET_DISTRIBUTION_SIZE, and we've loaded in an old file */ if (ds->distribution != NULL) if (AMITK_RAW_DATA_DIM_X(ds->distribution) != AMITK_DATA_SET_DISTRIBUTION_SIZE) { g_object_unref(ds->distribution); ds->distribution = NULL; } (*calc_distribution_func[ds->raw_data->format][ds->scaling_type])(ds, update_func, update_data); return; } /* this is the same as amitk_data_get_value, except only the internal scale factor is applied this is mainly useful for copying values from data sets into new data sets, where the new data set will copy the old data set's external scale factor information anyway */ amide_data_t amitk_data_set_get_internal_value(const AmitkDataSet * ds, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), EMPTY); if (!amitk_raw_data_includes_voxel(ds->raw_data, i)) return EMPTY; /* hand everything off to the data type specific function */ switch(ds->raw_data->format) { case AMITK_FORMAT_UBYTE: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_UBYTE_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_UBYTE_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_UBYTE_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_UBYTE_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_UBYTE_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_UBYTE_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_SBYTE: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_SBYTE_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_SBYTE_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_SBYTE_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_SBYTE_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_SBYTE_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_SBYTE_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_USHORT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_USHORT_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_USHORT_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_USHORT_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_USHORT_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_USHORT_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_USHORT_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_SSHORT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_SSHORT_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_SSHORT_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_SSHORT_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_SSHORT_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_SSHORT_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_SSHORT_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_UINT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_UINT_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_UINT_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_UINT_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_UINT_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_UINT_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_UINT_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_SINT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_SINT_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_SINT_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_SINT_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_SINT_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_SINT_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_SINT_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_FLOAT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_FLOAT_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_FLOAT_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_FLOAT_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_FLOAT_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_FLOAT_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_FLOAT_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_DOUBLE: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_DOUBLE_0D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_DOUBLE_1D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_DOUBLE_2D_SCALING_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_DOUBLE_0D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_DOUBLE_1D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_DOUBLE_2D_SCALING_INTERCEPT_INTERNAL_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } } amide_data_t amitk_data_set_get_value(const AmitkDataSet * ds, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), EMPTY); if (!amitk_raw_data_includes_voxel(ds->raw_data, i)) return EMPTY; /* hand everything off to the data type specific function */ switch(ds->raw_data->format) { case AMITK_FORMAT_UBYTE: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_UBYTE_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_UBYTE_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_UBYTE_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_UBYTE_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_UBYTE_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_UBYTE_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_SBYTE: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_SBYTE_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_SBYTE_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_SBYTE_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_SBYTE_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_SBYTE_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_SBYTE_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_USHORT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_USHORT_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_USHORT_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_USHORT_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_USHORT_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_USHORT_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_USHORT_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_SSHORT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_SSHORT_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_SSHORT_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_SSHORT_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_SSHORT_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_SSHORT_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_SSHORT_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_UINT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_UINT_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_UINT_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_UINT_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_UINT_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_UINT_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_UINT_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_SINT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_SINT_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_SINT_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_SINT_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_SINT_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_SINT_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_SINT_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_FLOAT: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_FLOAT_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_FLOAT_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_FLOAT_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_FLOAT_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_FLOAT_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_FLOAT_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; case AMITK_FORMAT_DOUBLE: switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: return AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D: return AMITK_DATA_SET_DOUBLE_1D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D: return AMITK_DATA_SET_DOUBLE_2D_SCALING_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return AMITK_DATA_SET_DOUBLE_0D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return AMITK_DATA_SET_DOUBLE_1D_SCALING_INTERCEPT_CONTENT(ds,i); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return AMITK_DATA_SET_DOUBLE_2D_SCALING_INTERCEPT_CONTENT(ds,i); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; break; } } amide_data_t amitk_data_set_get_internal_scaling_factor(const AmitkDataSet * ds, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), EMPTY); g_return_val_if_fail(ds->internal_scaling_factor->format == AMITK_FORMAT_DOUBLE, EMPTY); switch(ds->scaling_type) { case AMITK_SCALING_TYPE_2D: case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor,i); break; case AMITK_SCALING_TYPE_1D: case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->internal_scaling_factor,i); break; default: return *AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(ds->internal_scaling_factor,i); } } amide_data_t amitk_data_set_get_scaling_factor(const AmitkDataSet * ds, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), EMPTY); g_return_val_if_fail(ds->current_scaling_factor != NULL, EMPTY); g_return_val_if_fail(ds->current_scaling_factor->format == AMITK_FORMAT_DOUBLE, EMPTY); switch(ds->scaling_type) { case AMITK_SCALING_TYPE_2D: case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->current_scaling_factor,i); break; case AMITK_SCALING_TYPE_1D: case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->current_scaling_factor,i); break; default: return *AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(ds->current_scaling_factor,i); } } amide_data_t amitk_data_set_get_scaling_intercept(const AmitkDataSet * ds, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_DATA_SET(ds), EMPTY); if (ds->internal_scaling_intercept == NULL) return 0.0; g_return_val_if_fail(ds->internal_scaling_intercept->format == AMITK_FORMAT_DOUBLE, EMPTY); switch(ds->scaling_type) { case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept,i); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->internal_scaling_intercept,i); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: return *AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(ds->internal_scaling_intercept,i); break; default: return 0.0; } } /* sets the current voxel to the given value. If value/scaling is outside of the range of the data set type (i.e. negative for unsigned type), it will be truncated to lie at the limits of the range */ /* note, after using this function, you should recalculate the frame's max/min, along with the global max/min, and the distribution data */ void amitk_data_set_set_value(AmitkDataSet * ds, const AmitkVoxel i, const amide_data_t value, const gboolean signal_change) { amide_data_t unscaled_value; g_return_if_fail(AMITK_IS_DATA_SET(ds)); /* figure out what the value is unscaled */ switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: unscaled_value = value/ (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER((ds)->current_scaling_factor, (i))); break; case AMITK_SCALING_TYPE_1D: unscaled_value = value/ (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER((ds)->current_scaling_factor, (i))); break; case AMITK_SCALING_TYPE_2D: unscaled_value = value/ (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER((ds)->current_scaling_factor, (i))); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: unscaled_value = value/ (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER((ds)->current_scaling_factor, (i))) -(*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER((ds)->internal_scaling_intercept, (i))); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: unscaled_value = value/ (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER((ds)->current_scaling_factor, (i))) -(*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER((ds)->internal_scaling_intercept, (i))); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: unscaled_value = value/ (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER((ds)->current_scaling_factor, (i))) -(*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER((ds)->internal_scaling_intercept, (i))); break; default: unscaled_value=0.0; g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } /* truncated unscaled value to type limits */ if (unscaled_value < amitk_format_min[ds->raw_data->format]) unscaled_value = amitk_format_min[ds->raw_data->format]; else if (unscaled_value > amitk_format_max[ds->raw_data->format]) unscaled_value = amitk_format_max[ds->raw_data->format]; switch(ds->raw_data->format) { case AMITK_FORMAT_UBYTE: AMITK_RAW_DATA_UBYTE_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_SBYTE: AMITK_RAW_DATA_SBYTE_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_USHORT: AMITK_RAW_DATA_USHORT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_SSHORT: AMITK_RAW_DATA_SSHORT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_UINT: AMITK_RAW_DATA_UINT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_SINT: AMITK_RAW_DATA_SINT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_FLOAT: AMITK_RAW_DATA_FLOAT_SET_CONTENT((ds)->raw_data, (i)) = unscaled_value; break; case AMITK_FORMAT_DOUBLE: AMITK_RAW_DATA_DOUBLE_SET_CONTENT((ds)->raw_data, (i)) = unscaled_value; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } if (signal_change) { g_signal_emit (G_OBJECT (ds), data_set_signals[INVALIDATE_SLICE_CACHE], 0); g_signal_emit (G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } /* like amitk_data_set_set_value, but only takes into account the internal_scaling_factor, not the current_scaling_factor. Really only useful if you're copying data from one data set to the other, and you've just used amitk_data_set_get_internal_value */ void amitk_data_set_set_internal_value(AmitkDataSet * ds, const AmitkVoxel i, const amide_data_t internal_value, const gboolean signal_change) { amide_data_t unscaled_value; g_return_if_fail(AMITK_IS_DATA_SET(ds)); /* figure out what the value is unscaled */ switch(ds->scaling_type) { case AMITK_SCALING_TYPE_0D: unscaled_value = internal_value/ (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER((ds)->internal_scaling_factor, (i))); break; case AMITK_SCALING_TYPE_1D: unscaled_value = internal_value/ (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER((ds)->internal_scaling_factor, (i))); break; case AMITK_SCALING_TYPE_2D: unscaled_value = internal_value/ (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER((ds)->internal_scaling_factor, (i))); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: unscaled_value = internal_value/ (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER((ds)->internal_scaling_factor, (i))) -(*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER((ds)->internal_scaling_intercept, (i))); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: unscaled_value = internal_value/ (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER((ds)->internal_scaling_factor, (i))) -(*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER((ds)->internal_scaling_intercept, (i))); break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: unscaled_value = internal_value/ (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER((ds)->internal_scaling_factor, (i))) -(*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER((ds)->internal_scaling_intercept, (i))); break; default: unscaled_value=0.0; g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } /* truncated unscaled value to type limits */ if (unscaled_value < amitk_format_min[ds->raw_data->format]) unscaled_value = amitk_format_min[ds->raw_data->format]; else if (unscaled_value > amitk_format_max[ds->raw_data->format]) unscaled_value = amitk_format_max[ds->raw_data->format]; switch(ds->raw_data->format) { case AMITK_FORMAT_UBYTE: AMITK_RAW_DATA_UBYTE_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_SBYTE: AMITK_RAW_DATA_SBYTE_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_USHORT: AMITK_RAW_DATA_USHORT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_SSHORT: AMITK_RAW_DATA_SSHORT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_UINT: AMITK_RAW_DATA_UINT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_SINT: AMITK_RAW_DATA_SINT_SET_CONTENT((ds)->raw_data, (i)) = rint(unscaled_value); break; case AMITK_FORMAT_FLOAT: AMITK_RAW_DATA_FLOAT_SET_CONTENT((ds)->raw_data, (i)) = unscaled_value; break; case AMITK_FORMAT_DOUBLE: AMITK_RAW_DATA_DOUBLE_SET_CONTENT((ds)->raw_data, (i)) = unscaled_value; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } if (signal_change) { g_signal_emit (G_OBJECT (ds), data_set_signals[INVALIDATE_SLICE_CACHE], 0); g_signal_emit (G_OBJECT (ds), data_set_signals[DATA_SET_CHANGED], 0); } } static AmitkDataSet * (*get_slice_func[AMITK_FORMAT_NUM][AMITK_SCALING_TYPE_NUM])(AmitkDataSet *, const amide_time_t, const amide_time_t, const amide_intpoint_t, const AmitkCanvasPoint, const AmitkVolume *) = { {amitk_data_set_UBYTE_0D_SCALING_get_slice, amitk_data_set_UBYTE_1D_SCALING_get_slice, amitk_data_set_UBYTE_2D_SCALING_get_slice, amitk_data_set_UBYTE_0D_SCALING_INTERCEPT_get_slice, amitk_data_set_UBYTE_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_UBYTE_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_SBYTE_0D_SCALING_get_slice, amitk_data_set_SBYTE_1D_SCALING_get_slice, amitk_data_set_SBYTE_2D_SCALING_get_slice, amitk_data_set_SBYTE_0D_SCALING_INTERCEPT_get_slice, amitk_data_set_SBYTE_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_SBYTE_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_USHORT_0D_SCALING_get_slice,amitk_data_set_USHORT_1D_SCALING_get_slice, amitk_data_set_USHORT_2D_SCALING_get_slice,amitk_data_set_USHORT_0D_SCALING_INTERCEPT_get_slice,amitk_data_set_USHORT_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_USHORT_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_SSHORT_0D_SCALING_get_slice,amitk_data_set_SSHORT_1D_SCALING_get_slice, amitk_data_set_SSHORT_2D_SCALING_get_slice,amitk_data_set_SSHORT_0D_SCALING_INTERCEPT_get_slice,amitk_data_set_SSHORT_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_SSHORT_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_UINT_0D_SCALING_get_slice, amitk_data_set_UINT_1D_SCALING_get_slice, amitk_data_set_UINT_2D_SCALING_get_slice, amitk_data_set_UINT_0D_SCALING_INTERCEPT_get_slice, amitk_data_set_UINT_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_UINT_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_SINT_0D_SCALING_get_slice, amitk_data_set_SINT_1D_SCALING_get_slice, amitk_data_set_SINT_2D_SCALING_get_slice, amitk_data_set_SINT_0D_SCALING_INTERCEPT_get_slice, amitk_data_set_SINT_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_SINT_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_FLOAT_0D_SCALING_get_slice, amitk_data_set_FLOAT_1D_SCALING_get_slice, amitk_data_set_FLOAT_2D_SCALING_get_slice, amitk_data_set_FLOAT_0D_SCALING_INTERCEPT_get_slice, amitk_data_set_FLOAT_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_FLOAT_2D_SCALING_INTERCEPT_get_slice }, {amitk_data_set_DOUBLE_0D_SCALING_get_slice,amitk_data_set_DOUBLE_1D_SCALING_get_slice, amitk_data_set_DOUBLE_2D_SCALING_get_slice,amitk_data_set_DOUBLE_0D_SCALING_INTERCEPT_get_slice,amitk_data_set_DOUBLE_1D_SCALING_INTERCEPT_get_slice, amitk_data_set_DOUBLE_2D_SCALING_INTERCEPT_get_slice } }; /* returns a "2D" slice from a data set */ AmitkDataSet *amitk_data_set_get_slice(AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * slice_volume) { AmitkDataSet * slice; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), NULL); g_return_val_if_fail(ds->raw_data != NULL, NULL); /* hand everything off to the data type specific function */ slice = (*get_slice_func[ds->raw_data->format][ds->scaling_type])(ds, start, duration, gate, pixel_size, slice_volume); return slice; } /* start_point and end_point should be in the base coordinate frame */ void amitk_data_set_get_line_profile(AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration, const AmitkPoint base_start_point, const AmitkPoint base_end_point, GPtrArray ** preturn_data) { AmitkPoint start_point, end_point; AmitkPoint candidate_point, current_point; AmitkPoint step; AmitkPoint direction; AmitkVoxel current_voxel, last_voxel, candidate_voxel; amide_real_t min_size; amide_real_t length; amide_intpoint_t i_gate; gint start_frame, end_frame; amide_time_t used_start, used_end, used_duration; amide_time_t ds_start, ds_end; amide_data_t value, gate_value, time_weight; AmitkLineProfileDataElement * element; AmitkPoint voxel_point; gdouble m; g_return_if_fail(AMITK_IS_DATA_SET(ds)); *preturn_data = g_ptr_array_new(); g_return_if_fail(*preturn_data != NULL); /* figure out what frames of this data set to use */ used_start = start; start_frame = amitk_data_set_get_frame(ds, used_start); ds_start = amitk_data_set_get_start_time(ds, start_frame); used_end = start+duration; end_frame = amitk_data_set_get_frame(ds, used_end); ds_end = amitk_data_set_get_end_time(ds, end_frame); if (ds_end < used_end) used_end = ds_end; if (ds_start > used_start) used_start = ds_start; used_duration = used_end-used_start; /* translate the start and end into the data set's coordinate frame */ start_point = amitk_space_b2s(AMITK_SPACE(ds), base_start_point); end_point = amitk_space_b2s(AMITK_SPACE(ds), base_end_point); /* figure out the direction we want to go */ direction = point_sub(end_point, start_point); length = point_mag(direction); /* figure out what our "step" size will be (1/4 a voxel size) */ min_size = point_min_dim(AMITK_DATA_SET_VOXEL_SIZE(ds)); step = point_cmult((1.0/4.0)*min_size*(1.0/length), direction); /* initialize starting values */ current_point = start_point; POINT_TO_VOXEL(current_point, AMITK_DATA_SET_VOXEL_SIZE(ds), start_frame, AMITK_DATA_SET_VIEW_START_GATE(ds), current_voxel); while (point_mag(point_sub(current_point, start_point)) < length) { /* this next snippet of code advances us along the line so that we're at the point on the line closest to the center of the voxel */ VOXEL_TO_POINT(current_voxel, AMITK_DATA_SET_VOXEL_SIZE(ds), voxel_point); m = ((voxel_point.x-start_point.x)*direction.x + (voxel_point.y-start_point.y)*direction.y + (voxel_point.z-start_point.z)*direction.z) / (length*length); candidate_point = point_add(start_point, point_cmult(m, direction)); /* note, we may get a voxel out that's not the current voxel... we'll skip the voxel in that case */ POINT_TO_VOXEL(candidate_point, AMITK_DATA_SET_VOXEL_SIZE(ds), current_voxel.t, current_voxel.g,candidate_voxel); /* record the value if it's in the data set */ if ((amitk_raw_data_includes_voxel(AMITK_DATA_SET_RAW_DATA(ds), current_voxel)) && (VOXEL_EQUAL(candidate_voxel, current_voxel))) { /* need to average over frames */ value = 0; for (current_voxel.t=start_frame; current_voxel.t<=end_frame;current_voxel.t++) { if (start_frame == end_frame) time_weight = 1.0; else if (current_voxel.t == start_frame) time_weight = (amitk_data_set_get_end_time(ds, start_frame)-used_start)/used_duration; else if (current_voxel.t == end_frame) time_weight = (used_end-amitk_data_set_get_start_time(ds, end_frame))/used_duration; else time_weight = amitk_data_set_get_frame_duration(ds, current_voxel.t)/used_duration; /* need to average over gates */ gate_value = 0.0; for (i_gate=0; i_gate < AMITK_DATA_SET_NUM_VIEW_GATES(ds); i_gate++) { current_voxel.g = i_gate+AMITK_DATA_SET_VIEW_START_GATE(ds); if (current_voxel.g >= AMITK_DATA_SET_NUM_GATES(ds)) current_voxel.g -= AMITK_DATA_SET_NUM_GATES(ds); gate_value += amitk_data_set_get_value(ds, current_voxel); } value += time_weight*gate_value/((gdouble) AMITK_DATA_SET_NUM_VIEW_GATES(ds)); } /* record value in array */ element = g_malloc(sizeof(AmitkLineProfileDataElement)); g_return_if_fail(element != NULL); element->value = value; element->location = point_mag(point_sub(candidate_point, start_point)); g_ptr_array_add(*preturn_data, element); } current_voxel.t = start_frame; current_voxel.g = AMITK_DATA_SET_VIEW_START_GATE(ds); /* get next voxel */ last_voxel = current_voxel; /* this makes sure we move at least one voxel */ while (VOXEL_EQUAL(last_voxel, current_voxel)) { current_point = point_add(current_point, step); POINT_TO_VOXEL(current_point, AMITK_DATA_SET_VOXEL_SIZE(ds), current_voxel.t, current_voxel.g, current_voxel); } } return; } /* return the three planar projections of the data set */ /* projections should be an array of 3 pointers to data sets */ void amitk_data_set_get_projections(AmitkDataSet * ds, const guint frame, const guint gate, AmitkDataSet ** projections, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel dim, planar_dim, i; AmitkPoint voxel_size; amide_data_t normalizers[AMITK_VIEW_NUM]; div_t x; gint divider; gboolean continue_work=TRUE; gchar * temp_string; AmitkView i_view; amide_data_t value; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(ds->raw_data != NULL); g_return_if_fail(projections != NULL); dim = AMITK_DATA_SET_DIM(ds); voxel_size = AMITK_DATA_SET_VOXEL_SIZE(ds); /* setup the wait dialog */ if (update_func != NULL) { temp_string = g_strdup_printf(_("Generating projections of:\n %s"), AMITK_OBJECT_NAME(ds)); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } divider = ((dim.z/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (dim.z/AMITK_UPDATE_DIVIDER); /* initialize the 3 projections */ for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) { planar_dim.z = 1; planar_dim.g = 1; planar_dim.t = 1; switch(i_view) { case AMITK_VIEW_CORONAL: planar_dim.x = dim.x; planar_dim.y = dim.z; break; case AMITK_VIEW_SAGITTAL: planar_dim.x = dim.y; planar_dim.y = dim.z; break; case AMITK_VIEW_TRANSVERSE: default: planar_dim.x = dim.x; planar_dim.y = dim.y; break; } projections[i_view] = amitk_data_set_new_with_data(NULL, AMITK_DATA_SET_MODALITY(ds), AMITK_FORMAT_DOUBLE, planar_dim, AMITK_SCALING_TYPE_0D); if (projections[i_view] == NULL) { g_warning(_("couldn't allocate memory space for the projection, wanted %dx%dx%dx%dx%d elements"), planar_dim.x, planar_dim.y, planar_dim.z, planar_dim.g, planar_dim.t); return; } switch(i_view) { case AMITK_VIEW_CORONAL: projections[i_view]->voxel_size.x = voxel_size.x; projections[i_view]->voxel_size.y = voxel_size.z; projections[i_view]->voxel_size.z = AMITK_VOLUME_Y_CORNER(ds); normalizers[i_view] = voxel_size.y/projections[i_view]->voxel_size.z; break; case AMITK_VIEW_SAGITTAL: projections[i_view]->voxel_size.x = voxel_size.y; projections[i_view]->voxel_size.y = voxel_size.z; projections[i_view]->voxel_size.z = AMITK_VOLUME_X_CORNER(ds); normalizers[i_view] = voxel_size.x/projections[i_view]->voxel_size.z; break; case AMITK_VIEW_TRANSVERSE: default: projections[i_view]->voxel_size.x = voxel_size.x; projections[i_view]->voxel_size.y = voxel_size.y; projections[i_view]->voxel_size.z = AMITK_VOLUME_Z_CORNER(ds); normalizers[i_view] = voxel_size.z/projections[i_view]->voxel_size.z; break; } projections[i_view]->slice_parent = ds; g_object_add_weak_pointer(G_OBJECT(ds), (gpointer *) &(projections[i_view]->slice_parent)); amitk_space_copy_in_place(AMITK_SPACE(projections[i_view]), AMITK_SPACE(ds)); amitk_data_set_calc_far_corner(projections[i_view]); projections[i_view]->scan_start = amitk_data_set_get_start_time(ds, frame); amitk_data_set_set_thresholding(projections[i_view], AMITK_THRESHOLDING_GLOBAL); amitk_data_set_set_color_table(projections[i_view], AMITK_VIEW_MODE_SINGLE, AMITK_DATA_SET_COLOR_TABLE(ds, AMITK_VIEW_MODE_SINGLE)); amitk_data_set_set_gate_time(projections[i_view], 0, amitk_data_set_get_gate_time(ds, gate)); amitk_data_set_set_frame_duration(projections[i_view], 0, amitk_data_set_get_frame_duration(ds, frame)); /* initialize our projection */ amitk_raw_data_DOUBLE_initialize_data(projections[i_view]->raw_data, 0.0); } /* now iterate through the entire data set, adding up the 3 projections */ i.t = frame; i.g = gate; for (i.z = 0; (i.z < dim.z) && continue_work; i.z++) { if (update_func != NULL) { x = div(i.z,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, (gdouble) (i.z)/dim.z); } for (i.y = 0; i.y < dim.y; i.y++) { for (i.x = 0; i.x < dim.x; i.x++) { value = amitk_data_set_get_value(ds, i); AMITK_RAW_DATA_DOUBLE_2D_SET_CONTENT(projections[AMITK_VIEW_TRANSVERSE]->raw_data,i.y, i.x) += value; AMITK_RAW_DATA_DOUBLE_2D_SET_CONTENT(projections[AMITK_VIEW_CORONAL]->raw_data,dim.z-i.z-1, i.x) += value; AMITK_RAW_DATA_DOUBLE_2D_SET_CONTENT(projections[AMITK_VIEW_SAGITTAL]->raw_data,dim.z-i.z-1, i.y) += value; } } } if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); if (!continue_work) {/* we hit cancel */ for (i_view=0; i_viewraw_data,i.y, i.x) *= normalizers[i_view]; amitk_data_set_set_threshold_max(projections[i_view], 0, amitk_data_set_get_global_max(projections[i_view])); amitk_data_set_set_threshold_min(projections[i_view], 0, amitk_data_set_get_global_min(projections[i_view])); } return; } /* returns a cropped version of the given data set */ AmitkDataSet *amitk_data_set_get_cropped(const AmitkDataSet * ds, const AmitkVoxel start, const AmitkVoxel end, const AmitkFormat format, const AmitkScalingType scaling_type, AmitkUpdateFunc update_func, gpointer update_data) { AmitkDataSet * cropped; AmitkVoxel i, j; AmitkVoxel dim; AmitkVoxel scaling_dim; gchar * temp_string; AmitkPoint shift; AmitkPoint temp_pt; GList * children; gboolean same_format_and_scaling; gboolean unsigned_type; gboolean float_type; amide_data_t max, min, value; div_t x; gint divider; gint total_planes; gint total_progress; gint scaling_progress; gint i_progress; gboolean continue_work=TRUE; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), NULL); g_return_val_if_fail(ds->raw_data != NULL, NULL); /* are we converting format and/or scaling? */ if ((AMITK_DATA_SET_FORMAT(ds) == format) && (AMITK_DATA_SET_SCALING_TYPE(ds) == scaling_type)) same_format_and_scaling = TRUE; else same_format_and_scaling = FALSE; /* are we converting to an unsigned type? */ switch(format) { case AMITK_FORMAT_UBYTE: case AMITK_FORMAT_USHORT: case AMITK_FORMAT_UINT: unsigned_type = TRUE; float_type = FALSE; break; case AMITK_FORMAT_FLOAT: case AMITK_FORMAT_DOUBLE: unsigned_type = FALSE; float_type = TRUE; break; default: unsigned_type = FALSE; float_type = FALSE; break; } /* figure out the dimensions of the output data set and the scaling array */ dim = voxel_add(voxel_sub(end, start), one_voxel); scaling_dim = one_voxel; switch (scaling_type) { case AMITK_SCALING_TYPE_2D: case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: scaling_dim.t = dim.t; scaling_dim.g = dim.g; scaling_dim.z = dim.z; break; case AMITK_SCALING_TYPE_1D: case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: scaling_dim.g = dim.g; scaling_dim.t = dim.t; break; default: break; } /* multiply total_planes by two if we also need to iterate to find new scale factors */ total_planes = dim.t*dim.g*dim.z; if (!same_format_and_scaling) scaling_progress = total_planes; else scaling_progress = 0; total_progress = total_planes + scaling_progress; divider = ((total_progress/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_progress/AMITK_UPDATE_DIVIDER); cropped = AMITK_DATA_SET(amitk_object_copy(AMITK_OBJECT(ds))); /* start by unrefing the info that's only copied by reference by amitk_object_copy */ if (cropped->raw_data != NULL) { g_object_unref(cropped->raw_data); cropped->raw_data = NULL; } if (cropped->internal_scaling_factor != NULL) { g_object_unref(cropped->internal_scaling_factor); cropped->internal_scaling_factor = NULL; } if (cropped->internal_scaling_intercept != NULL) { g_object_unref(cropped->internal_scaling_intercept); cropped->internal_scaling_intercept = NULL; } if (cropped->distribution != NULL) { g_object_unref(cropped->distribution); cropped->distribution = NULL; } /* and unref anything that's obviously now incorrect */ if (cropped->current_scaling_factor != NULL) { g_object_unref(cropped->current_scaling_factor); cropped->current_scaling_factor = NULL; } if (cropped->gate_time != NULL) { g_free(cropped->gate_time); cropped->gate_time = NULL; } if (cropped->frame_duration != NULL) { g_free(cropped->frame_duration); cropped->frame_duration = NULL; } if (cropped->frame_max != NULL) { g_free(cropped->frame_max); cropped->frame_max = NULL; } if (cropped->frame_min != NULL) { g_free(cropped->frame_min); cropped->frame_min = NULL; } /* set a new name for this guy */ temp_string = g_strdup_printf(_("%s, cropped"), AMITK_OBJECT_NAME(ds)); amitk_object_set_name(AMITK_OBJECT(cropped), temp_string); g_free(temp_string); /* set the scale type */ cropped->scaling_type = scaling_type; /* setup the scale factors */ cropped->internal_scaling_factor = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE,scaling_dim); if (cropped->internal_scaling_factor == NULL) { g_warning(_("couldn't allocate memory space for the cropped internal scaling structure")); goto error; } if (AMITK_DATA_SET_SCALING_HAS_INTERCEPT(cropped)) { cropped->internal_scaling_intercept = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE,scaling_dim); if (cropped->internal_scaling_intercept == NULL) { g_warning(_("couldn't allocate memory space for the cropped internal scaling structure")); goto error; } } if (update_func != NULL) { temp_string = g_strdup_printf(_("Generating cropped version of:\n %s"), AMITK_OBJECT_NAME(ds)); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } /* now generate the scale factors */ if (same_format_and_scaling) { /* we'll just use the old scaling factors if applicable */ i = zero_voxel; j = start; switch(scaling_type) { case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) for (i.z=0, j.z=start.z; j.z <= end.z; i.z++, j.z++) { (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, j); (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept, j); } break; case AMITK_SCALING_TYPE_2D: for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) for (i.z=0, j.z=start.z; j.z <= end.z; i.z++, j.z++) (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, j); break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) { (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->internal_scaling_factor, j); (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->internal_scaling_intercept, j); } break; case AMITK_SCALING_TYPE_1D: for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->internal_scaling_factor, j); break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = *AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(ds->internal_scaling_factor, j); (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = *AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(ds->internal_scaling_intercept, j); break; case AMITK_SCALING_TYPE_0D: (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = *AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(ds->internal_scaling_factor, j); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } } else if (!float_type) { /* we're changing format/scaling type - generate new scaling factors */ max = min = 0.0; i_progress = 0; for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) { for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) { for (i.z=0, j.z=start.z; (j.z <= end.z) && continue_work; i.z++, j.z++, i_progress++) { if (update_func != NULL) { x = div(i_progress,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) i_progress)/((gdouble) total_progress)); } for (i.y=0, j.y=start.y; j.y <= end.y; i.y++, j.y++) { for (i.x=0, j.x=start.x; j.x <= end.x; i.x++, j.x++) { value = amitk_data_set_get_internal_value(ds, i); if (value > max) max = value; else if (value < min) min = value; } } if (scaling_type == AMITK_SCALING_TYPE_2D) { if (!unsigned_type) max = MAX(fabs(min), max); (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = max/amitk_format_max[format]; max = min = 0.0; } else if (scaling_type == AMITK_SCALING_TYPE_2D_WITH_INTERCEPT) { if (!unsigned_type) { max = MAX(fabs(min), max); min = 0.0; } (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = (max-min)/amitk_format_max[format]; (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = min; max = min = 0.0; } } if (scaling_type == AMITK_SCALING_TYPE_1D) { if (!unsigned_type) max = MAX(fabs(min), max); (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = max/amitk_format_max[format]; max = min = 0.0; } else if (scaling_type == AMITK_SCALING_TYPE_1D_WITH_INTERCEPT) { if (!unsigned_type) { max = MAX(fabs(min), max); min = 0.0; } (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = max/amitk_format_max[format]; (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = min; max = min = 0.0; } } } if (scaling_type == AMITK_SCALING_TYPE_0D) { if (!unsigned_type) max = MAX(fabs(min), max); (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = max/amitk_format_max[format]; max = min = 0.0; } else if (scaling_type == AMITK_SCALING_TYPE_0D_WITH_INTERCEPT) { if (!unsigned_type) { max = MAX(fabs(min), max); min = 0.0; } (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = max/amitk_format_max[format]; (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = min; max = min = 0.0; } } else { /* floating point type, just set scaling factors to 1 */ i = zero_voxel; switch(scaling_type) { case AMITK_SCALING_TYPE_2D: for (i.t=0; i.t < dim.t; i.t++) for (i.g=0; i.g < dim.g; i.g++) for (i.z=0; i.z < dim.z; i.z++) (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = 1.0; break; case AMITK_SCALING_TYPE_2D_WITH_INTERCEPT: for (i.t=0; i.t < dim.t; i.t++) for (i.g=0; i.g < dim.g; i.g++) for (i.z=0; i.z < dim.z; i.z++) { (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = 1.0; (*AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = 0.0; } break; case AMITK_SCALING_TYPE_1D: for (i.t=0; i.t < dim.t; i.t++) for (i.g=0; i.g < dim.g; i.g++) (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = 1.0; break; case AMITK_SCALING_TYPE_1D_WITH_INTERCEPT: for (i.t=0; i.t < dim.t; i.t++) for (i.g=0; i.g < dim.g; i.g++) { (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = 1.0; (*AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = 0.0; } break; case AMITK_SCALING_TYPE_0D: (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = 1.0; break; case AMITK_SCALING_TYPE_0D_WITH_INTERCEPT: (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_factor, i)) = 1.0; (*AMITK_RAW_DATA_DOUBLE_0D_SCALING_POINTER(cropped->internal_scaling_intercept, i)) = 0.0; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } } /* reset the current scaling array */ amitk_data_set_set_scale_factor(cropped, AMITK_DATA_SET_SCALE_FACTOR(ds)); /* and setup the data */ cropped->raw_data = amitk_raw_data_new_with_data(format, voxel_add(voxel_sub(end, start), one_voxel)); if (cropped->raw_data == NULL) { g_warning(_("couldn't allocate memory space for the cropped raw data set structure")); goto error; } /* copy the raw data on over */ i_progress = scaling_progress; for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) { for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) { for (i.z=0, j.z=start.z; (j.z <= end.z) && continue_work; i.z++, j.z++, i_progress++) { if (update_func != NULL) { x = div(i_progress,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) i_progress)/((gdouble) total_progress)); } for (i.y=0, j.y=start.y; j.y <= end.y; i.y++, j.y++) { if (same_format_and_scaling) { i.x = 0; j.x = start.x; memcpy(amitk_raw_data_get_pointer(cropped->raw_data, i), amitk_raw_data_get_pointer(ds->raw_data, j), amitk_format_sizes[format]*dim.x); } else { for (i.x=0, j.x=start.x; j.x <= end.x; i.x++, j.x++) { value = amitk_data_set_get_internal_value(ds, j); amitk_data_set_set_internal_value(cropped, i, value, FALSE); } } } } } } if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); if (!continue_work) goto error; /* reset the gates we're viewing as appropriate */ if (((AMITK_DATA_SET_VIEW_START_GATE(ds) - start.g) < AMITK_DATA_SET_NUM_GATES(cropped)) && ((AMITK_DATA_SET_VIEW_START_GATE(ds) - start.g) >= 0)) amitk_data_set_set_view_start_gate(cropped, AMITK_DATA_SET_VIEW_START_GATE(ds) - start.g); else amitk_data_set_set_view_start_gate(cropped, 0); /* put something reasonable */ if (((AMITK_DATA_SET_VIEW_END_GATE(ds) - start.g) < AMITK_DATA_SET_NUM_GATES(cropped)) && ((AMITK_DATA_SET_VIEW_END_GATE(ds) - start.g) >= 0)) amitk_data_set_set_view_end_gate(cropped, AMITK_DATA_SET_VIEW_END_GATE(ds) - start.g); else amitk_data_set_set_view_end_gate(cropped, AMITK_DATA_SET_VIEW_START_GATE(cropped)); /* put something reasonable */ /* setup the gate time array */ cropped->gate_time = amitk_data_set_get_gate_time_mem(ds); for (i.g=0, j.g=start.g; j.g <= end.g; i.g++, j.g++) amitk_data_set_set_gate_time(cropped, i.g, amitk_data_set_get_gate_time(ds, j.g)); /* setup the frame time array */ cropped->scan_start = amitk_data_set_get_start_time(ds, start.t); cropped->frame_duration = amitk_data_set_get_frame_duration_mem(ds); for (i.t=0, j.t=start.t; j.t <= end.t; i.t++, j.t++) amitk_data_set_set_frame_duration(cropped, i.t, amitk_data_set_get_frame_duration(ds, j.t)); /* recalc the temporary parameters */ amitk_data_set_calc_far_corner(cropped); amitk_data_set_calc_min_max(cropped, update_func, update_data); /* and shift the offset appropriately */ POINT_MULT(start, AMITK_DATA_SET_VOXEL_SIZE(cropped), temp_pt); temp_pt = amitk_space_s2b(AMITK_SPACE(ds), temp_pt); shift = point_sub(temp_pt, AMITK_SPACE_OFFSET(ds)); amitk_space_shift_offset(AMITK_SPACE(cropped), shift); /* and reshift the children, so they stay in the right spot */ shift = point_neg(shift); children = AMITK_OBJECT_CHILDREN(cropped); while (children != NULL) { amitk_space_shift_offset(AMITK_SPACE(children->data), shift); children = children->next; } /* see if we can drop the intercept (if present)/reducing scaling dimensionality */ data_set_drop_intercept(cropped); data_set_reduce_scaling_dimension(cropped); return cropped; error: amitk_object_unref(cropped); return NULL; } #ifdef AMIDE_LIBGSL_SUPPORT /* fills the data set "filtered_ds", with the results of the kernel convolved to data_set */ /* assumptions: 1- filtered_ds is of type FLOAT, 0D scaling 2- scale of filtered_ds is 1.0 3- kernel is of type DOUBLE, is in complex packed format, and has odd dimensions in x,y,z, and dimension 1 in t notes: 1. kernel is modified (FFT'd) 2. don't have a separate function for each data type, as getting the data_set data, is a tiny fraction of the computational time, use amitk_data_set_get_internal_value instead */ static gboolean filter_fir(const AmitkDataSet * data_set, AmitkDataSet * filtered_ds, AmitkRawData * kernel, AmitkVoxel kernel_size, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel subset_size; AmitkVoxel i_outer; AmitkVoxel i_inner; AmitkVoxel j_inner; AmitkVoxel half; AmitkVoxel ds_dim; AmitkRawData * subset=NULL; gsl_fft_complex_wavetable * wavetable=NULL; gsl_fft_complex_workspace * workspace = NULL; gchar * temp_string; gint image_num; gint total_planes; gboolean continue_work=TRUE; g_return_val_if_fail(kernel_size.t == 1, FALSE); g_return_val_if_fail(kernel_size.g == 1, FALSE); g_return_val_if_fail((kernel_size.z & 0x1), FALSE); /* needs to be odd */ g_return_val_if_fail((kernel_size.y & 0x1), FALSE); g_return_val_if_fail((kernel_size.x & 0x1), FALSE); g_return_val_if_fail(2*kernel_size.z < AMITK_FILTER_FFT_SIZE, FALSE); g_return_val_if_fail(2*kernel_size.y < AMITK_FILTER_FFT_SIZE, FALSE); g_return_val_if_fail(2*kernel_size.x < AMITK_FILTER_FFT_SIZE, FALSE); ds_dim = AMITK_DATA_SET_DIM(data_set); /* initialize gsl's FFT stuff */ wavetable = gsl_fft_complex_wavetable_alloc(AMITK_FILTER_FFT_SIZE); workspace = gsl_fft_complex_workspace_alloc (AMITK_FILTER_FFT_SIZE); if ((wavetable == NULL) || (workspace == NULL)) { g_warning(_("Filtering: Failed to allocate wavetable and workspace")); continue_work=FALSE; goto exit_strategy; } /* get space for our data subset*/ if ((subset = amitk_raw_data_new()) == NULL) { g_warning(_("couldn't allocate memory space for the subset structure")); continue_work=FALSE; goto exit_strategy; } subset->format = AMITK_FORMAT_DOUBLE; subset->dim.t = subset->dim.g = 1; subset->dim.z = subset->dim.y = AMITK_FILTER_FFT_SIZE; subset->dim.x = 2*AMITK_FILTER_FFT_SIZE; /* real and complex parts */ subset_size.t = subset_size.g = 1; subset_size.z = AMITK_FILTER_FFT_SIZE-kernel_size.z+1; subset_size.y = AMITK_FILTER_FFT_SIZE-kernel_size.y+1; subset_size.x = AMITK_FILTER_FFT_SIZE-kernel_size.x+1; half.t = half.g = 0; half.z = kernel_size.z>>1; half.y = kernel_size.y>>1; half.x = kernel_size.x>>1; if ((subset->data = amitk_raw_data_get_data_mem(subset)) == NULL) { g_warning(_("Couldn't allocate memory space for the subset data")); continue_work=FALSE; goto exit_strategy; } /* FFT the kernel */ amitk_filter_3D_FFT(kernel, wavetable, workspace); if (update_func != NULL) { temp_string = g_strdup_printf(_("Filtering Data Set: %s"), AMITK_OBJECT_NAME(data_set)); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = ds_dim.z*ds_dim.t*ds_dim.g; /* start the overlap and add FFT method */ i_outer.t = i_inner.t = j_inner.t = 0; i_outer.g = i_inner.g = j_inner.g = 0; for (i_outer.t = 0; (i_outer.t < ds_dim.t) && continue_work; i_outer.t++) { for (i_outer.g = 0; (i_outer.g < ds_dim.g) && continue_work; i_outer.g++) { #if AMIDE_DEBUG g_print("Filtering Frame %d/Gate %d\n", i_outer.t, i_outer.g); #endif for (i_outer.z = 0; (i_outer.z < ds_dim.z) && continue_work; i_outer.z+= subset_size.z) { if (update_func != NULL) { image_num = i_outer.z+i_outer.t*ds_dim.z+i_outer.g*ds_dim.z*ds_dim.t; continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } for (i_outer.y = 0; i_outer.y < ds_dim.y; i_outer.y+= subset_size.y) { for (i_outer.x = 0; i_outer.x < ds_dim.x; i_outer.x+= subset_size.x) { /* initialize the subset */ for (j_inner.z = 0; j_inner.z < subset->dim.z; j_inner.z++) for (j_inner.y = 0; j_inner.y < subset->dim.y; j_inner.y++) for (j_inner.x = 0; j_inner.x < subset->dim.x; j_inner.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(subset, j_inner) = 0.0; /* copy data over from the actual data set */ for (i_inner.z = 0, j_inner.z=0; ((i_inner.z < subset_size.z) && (i_inner.z+i_outer.z) < ds_dim.z); i_inner.z++, j_inner.z++) for (i_inner.y = 0, j_inner.y=0; ((i_inner.y < subset_size.y) && (i_inner.y+i_outer.y) < ds_dim.y); i_inner.y++, j_inner.y++) for (i_inner.x = 0, j_inner.x=0; ((i_inner.x < subset_size.x) && (i_inner.x+i_outer.x) < ds_dim.x); i_inner.x++, j_inner.x+=2) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(subset, j_inner) = amitk_data_set_get_internal_value(data_set, voxel_add(i_outer, i_inner)); /* should be zero for out of range */ /* FFT the data */ amitk_filter_3D_FFT(subset, wavetable, workspace); /* multiple the data by the filter */ amitk_filter_complex_mult(subset, kernel); /* and inverse FFT */ amitk_filter_inverse_3D_FFT(subset, wavetable, workspace); /* and add in, at the same time we're shifting the data set over by half the kernel size */ for (((i_inner.z = (i_outer.z == 0) ? 0 : -half.z), (j_inner.z = (i_outer.z == 0) ? half.z : 0)); ((j_inner.z < AMITK_FILTER_FFT_SIZE) && ((i_inner.z+i_outer.z) < AMITK_DATA_SET_DIM_Z(filtered_ds))); i_inner.z++, j_inner.z++) for (((i_inner.y = (i_outer.y == 0) ? 0 : -half.y), (j_inner.y = (i_outer.y == 0) ? half.y : 0)); ((j_inner.y < AMITK_FILTER_FFT_SIZE) && ((i_inner.y+i_outer.y) < AMITK_DATA_SET_DIM_Y(filtered_ds))); i_inner.y++, j_inner.y++) for (((i_inner.x = (i_outer.x == 0) ? 0 : -half.x), (j_inner.x = (i_outer.x == 0) ? 2*half.x : 0)); ((j_inner.x < 2*AMITK_FILTER_FFT_SIZE) && ((i_inner.x+i_outer.x) < AMITK_DATA_SET_DIM_X(filtered_ds))); i_inner.x++, j_inner.x+=2) AMITK_RAW_DATA_FLOAT_SET_CONTENT(filtered_ds->raw_data, voxel_add(i_outer,i_inner)) += AMITK_RAW_DATA_DOUBLE_CONTENT(subset, j_inner); } } } } } /* i_outer.t */ exit_strategy: if (wavetable != NULL) { gsl_fft_complex_wavetable_free(wavetable); wavetable = NULL; } if (workspace != NULL) { gsl_fft_complex_workspace_free(workspace); workspace = NULL; } if (subset != NULL) { g_object_unref(subset); subset = NULL; } if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); return continue_work; } #endif /* assumptions: 1- filtered_ds is of type FLOAT, 0D scaling 2- scale of filtered_ds is 1.0 3- kernel dimensions are odd notes: 1. don't have a separate function for each data type, as getting the data_set data, is a tiny fraction of the computational time, use amitk_data_set_get_internal_value instead 2. data set can be the same as filtered_ds */ static gboolean filter_median_3D(const AmitkDataSet * data_set, AmitkDataSet * filtered_ds, AmitkVoxel kernel_dim, AmitkUpdateFunc update_func, gpointer update_data) { amide_data_t * partial_sort_data; AmitkVoxel i,j, mid_dim, output_dim; gint loc, median_size; AmitkRawData * output_data; AmitkVoxel ds_dim; gchar * temp_string; gint image_num; gint total_planes; div_t x; gint divider; gboolean continue_work=TRUE; g_return_val_if_fail(AMITK_IS_DATA_SET(data_set), FALSE); g_return_val_if_fail(AMITK_IS_DATA_SET(filtered_ds), FALSE); g_return_val_if_fail(VOXEL_EQUAL(AMITK_DATA_SET_DIM(data_set), AMITK_DATA_SET_DIM(filtered_ds)), FALSE); g_return_val_if_fail(AMITK_RAW_DATA_FORMAT(AMITK_DATA_SET_RAW_DATA(filtered_ds)) == AMITK_FORMAT_FLOAT, FALSE); g_return_val_if_fail(REAL_EQUAL(AMITK_DATA_SET_SCALE_FACTOR(filtered_ds), 1.0), FALSE); g_return_val_if_fail(VOXEL_EQUAL(AMITK_RAW_DATA_DIM(filtered_ds->internal_scaling_factor), one_voxel), FALSE); g_return_val_if_fail(kernel_dim.t == 1, FALSE); /* haven't written support yet */ g_return_val_if_fail(kernel_dim.g == 1, FALSE); /* haven't written support yet */ /* check it's odd */ g_return_val_if_fail(kernel_dim.x & 0x1, FALSE); g_return_val_if_fail(kernel_dim.y & 0x1, FALSE); g_return_val_if_fail(kernel_dim.z & 0x1, FALSE); ds_dim = AMITK_DATA_SET_DIM(data_set); if (ds_dim.z < kernel_dim.z) { kernel_dim.z = 1; g_warning(_("data set z dimension to small for kernel, setting kernel dimension to 1")); } if (ds_dim.y < kernel_dim.y) { kernel_dim.y = 1; g_warning(_("data set y dimension to small for kernel, setting kernel dimension to 1")); } if (ds_dim.x < kernel_dim.x) { kernel_dim.x = 1; g_warning(_("data set x dimension to small for kernel, setting kernel dimension to 1")); } mid_dim.t = mid_dim.g = 0; mid_dim.z = kernel_dim.z >> 1; mid_dim.y = kernel_dim.y >> 1; mid_dim.x = kernel_dim.x >> 1; median_size = kernel_dim.z*kernel_dim.y*kernel_dim.x; output_dim = ds_dim; output_dim.t = output_dim.g = 1; if ((output_data = amitk_raw_data_new_with_data(AMITK_FORMAT_FLOAT, output_dim)) == NULL) { g_warning(_("couldn't allocate memory space for the internal raw data")); return FALSE; } amitk_raw_data_FLOAT_initialize_data(output_data, 0.0); partial_sort_data = g_try_new(amide_data_t, median_size); g_return_val_if_fail(partial_sort_data != NULL, FALSE); if (update_func != NULL) { temp_string = g_strdup_printf(_("Filtering Data Set: %s"), AMITK_OBJECT_NAME(data_set)); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = ds_dim.z*ds_dim.t*ds_dim.g; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); /* iterate over all the voxels in the data_set */ i.t = i.g = 0; for (j.t=0; (j.t < AMITK_DATA_SET_NUM_FRAMES(data_set)) && continue_work; j.t++) { for (j.g=0; (j.g < AMITK_DATA_SET_NUM_GATES(data_set)) && continue_work; j.g++) { for (i.z=0; (i.z < output_dim.z) && continue_work; i.z++) { if (update_func != NULL) { image_num = i.z+j.t*ds_dim.z+j.g*ds_dim.z*ds_dim.t; x = div(image_num,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } for (i.y=0; i.y < output_dim.y; i.y++) { for (i.x=0; i.x < output_dim.x; i.x++) { /* initialize the data for the iteration */ loc = 0; for (j.z = i.z-mid_dim.z; j.z <= i.z+mid_dim.z; j.z++) { if ((j.z < 0) || (j.z >= ds_dim.z)) { for (j.y=0; j.y < kernel_dim.y; j.y++) { for (j.x=0; j.x < kernel_dim.x; j.x++) { partial_sort_data[loc] = 0.0; loc++; } } } else { for (j.y = i.y-mid_dim.y; j.y <= i.y+mid_dim.y; j.y++) { if ((j.y < 0) || (j.y >= ds_dim.y)) { for (j.x=0; j.x < kernel_dim.x; j.x++) { partial_sort_data[loc] = 0.0; loc++; } } else { for (j.x = i.x-mid_dim.x; j.x <= i.x+mid_dim.x; j.x++) { if ((j.x < 0) || (j.x >= ds_dim.x)) { partial_sort_data[loc] = 0.0; loc++; } else { partial_sort_data[loc] = amitk_data_set_get_internal_value(data_set, j); loc++; } } } } } } /* end initializing data */ /* and store median value */ AMITK_RAW_DATA_FLOAT_SET_CONTENT(output_data, i) = amitk_filter_find_median_by_partial_sort(partial_sort_data, median_size); } /* i.x */ } /* i.y */ } /* i.z */ /* copy the output_data over into the filtered_ds */ for (i.z=0, j.z=0; i.z < output_dim.z; i.z++, j.z++) for (i.y=0, j.y=0; i.y < output_dim.y; i.y++, j.y++) for (i.x=0, j.x=0; i.x < output_dim.x; i.x++, j.x++) AMITK_RAW_DATA_FLOAT_SET_CONTENT(filtered_ds->raw_data, j) = AMITK_RAW_DATA_FLOAT_CONTENT(output_data, i); } /* j.g */ } /* j.t */ /* garbage collection */ g_object_unref(output_data); g_free(partial_sort_data); if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); return continue_work; } /* see notes for filter_median_3D */ static gboolean filter_median_linear(const AmitkDataSet * data_set, AmitkDataSet * filtered_ds, const gint kernel_size, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel kernel_dim; kernel_dim.x = kernel_size; kernel_dim.y = 1; kernel_dim.z = 1; kernel_dim.g = 1; kernel_dim.t = 1; if (!filter_median_3D(data_set, filtered_ds, kernel_dim, update_func, update_data)) return FALSE; kernel_dim.x = 1; kernel_dim.y = kernel_size; kernel_dim.z = 1; kernel_dim.g = 1; kernel_dim.t = 1; if (!filter_median_3D(filtered_ds,filtered_ds,kernel_dim, update_func, update_data)) return FALSE; kernel_dim.x = 1; kernel_dim.y = 1; kernel_dim.z = kernel_size; kernel_dim.g = 1; kernel_dim.t = 1; if (!filter_median_3D(filtered_ds,filtered_ds,kernel_dim, update_func, update_data)) return FALSE; return TRUE; } /* returns a filtered version of the given data set */ AmitkDataSet *amitk_data_set_get_filtered(const AmitkDataSet * ds, const AmitkFilter filter_type, const gint kernel_size, const amide_real_t fwhm, AmitkUpdateFunc update_func, gpointer update_data) { AmitkDataSet * filtered=NULL; gchar * temp_string; AmitkVoxel kernel_dim; gboolean good=TRUE; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), NULL); g_return_val_if_fail(ds->raw_data != NULL, NULL); filtered = AMITK_DATA_SET(amitk_object_copy(AMITK_OBJECT(ds))); /* start by unrefing the info that's only copied by reference by amitk_object_copy */ if (filtered->raw_data != NULL) { g_object_unref(filtered->raw_data); filtered->raw_data = NULL; } if (filtered->internal_scaling_factor != NULL) { g_object_unref(filtered->internal_scaling_factor); filtered->internal_scaling_factor = NULL; } if (filtered->internal_scaling_intercept != NULL) { g_object_unref(filtered->internal_scaling_intercept); filtered->internal_scaling_intercept = NULL; } if (filtered->distribution != NULL) { g_object_unref(filtered->distribution); filtered->distribution = NULL; } /* and unref anything that's obviously now incorrect */ if (filtered->current_scaling_factor != NULL) { g_object_unref(filtered->current_scaling_factor); filtered->current_scaling_factor = NULL; } if (filtered->frame_max != NULL) { g_free(filtered->frame_max); filtered->frame_max = NULL; } if (filtered->frame_min != NULL) { g_free(filtered->frame_min); filtered->frame_min = NULL; } /* set a new name for this guy */ temp_string = g_strdup_printf(_("%s, %s filtered"), AMITK_OBJECT_NAME(ds), amitk_filter_get_name(filter_type)); amitk_object_set_name(AMITK_OBJECT(filtered), temp_string); g_free(temp_string); /* start the new building process */ filtered->raw_data = amitk_raw_data_new_with_data(AMITK_FORMAT_FLOAT, AMITK_DATA_SET_DIM(ds)); if (filtered->raw_data == NULL) { g_warning(_("couldn't allocate memory space for the filtered raw data set structure")); goto error; } /* setup the scaling factor */ filtered->scaling_type = AMITK_SCALING_TYPE_0D; filtered->internal_scaling_factor = amitk_raw_data_DOUBLE_0D_SCALING_init(1.0); /* reset the current scaling array */ amitk_data_set_set_scale_factor(filtered, AMITK_DATA_SET_SCALE_FACTOR(ds)); switch(filter_type) { #ifdef AMIDE_LIBGSL_SUPPORT case AMITK_FILTER_GAUSSIAN: { AmitkRawData * kernel; AmitkVoxel kernel_size_3D; kernel_size_3D.t=kernel_size_3D.g=1; kernel_size_3D.z=kernel_size_3D.y=kernel_size_3D.x=kernel_size; kernel = amitk_filter_calculate_gaussian_kernel_complex(kernel_size_3D, AMITK_DATA_SET_VOXEL_SIZE(ds), fwhm); if (kernel == NULL) { g_warning(_("failed to calculate 3D gaussian kernel")); goto error; } good = filter_fir(ds, filtered, kernel, kernel_size_3D, update_func, update_data); g_object_unref(kernel); } break; #endif case AMITK_FILTER_MEDIAN_LINEAR: good = filter_median_linear(ds, filtered, kernel_size, update_func, update_data); break; case AMITK_FILTER_MEDIAN_3D: kernel_dim.t = kernel_dim.g = 1; kernel_dim.z = kernel_dim.y = kernel_dim.x = kernel_size; good = filter_median_3D(ds, filtered, kernel_dim, update_func, update_data); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); goto error; } if (!good) goto error; /* recalc the temporary parameters */ amitk_data_set_calc_min_max(filtered, update_func, update_data); return filtered; error: if (filtered != NULL) amitk_object_unref(filtered); return NULL; } gint amitk_data_sets_count(GList * objects, gboolean recurse) { gint count; if (objects == NULL) return 0; if (AMITK_IS_DATA_SET(objects->data)) count = 1; else count = 0; if (recurse) /* count data sets that are children */ count += amitk_data_sets_count(AMITK_OBJECT_CHILDREN(objects->data), recurse); /* add this count too the counts from the rest of the objects */ return count+amitk_data_sets_count(objects->next, recurse); } /* function to return the minimum frame duration from a list of objects */ amide_time_t amitk_data_sets_get_min_frame_duration(GList * objects) { amide_time_t min_duration, temp; if (objects == NULL) return -1.0; /* invalid */ /* first process the rest of the list */ min_duration = amitk_data_sets_get_min_frame_duration(objects->next); /* now process and compare to the children */ temp = amitk_data_sets_get_min_frame_duration(AMITK_OBJECT_CHILDREN(objects->data)); if (temp >= 0.0) { if (min_duration < 0.0) min_duration = temp; else if (temp < min_duration) min_duration = temp; } /* and process this guy */ if (AMITK_IS_DATA_SET(objects->data)) { temp = amitk_data_set_get_min_frame_duration(objects->data); if (min_duration < 0.0) min_duration = temp; else if (temp < min_duration) min_duration = temp; } return min_duration; } /* returns the minimum voxel dimensions of the list of data sets */ amide_real_t amitk_data_sets_get_min_voxel_size(GList * objects) { amide_real_t min_voxel_size, temp; if (objects == NULL) return -1.0; /* invalid */ /* first process the rest of the list */ min_voxel_size = amitk_data_sets_get_min_voxel_size(objects->next); /* now process and compare to the children */ temp = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(objects->data)); if (temp >= 0.0) { if (min_voxel_size < 0.0) min_voxel_size = temp; else if (temp < min_voxel_size) min_voxel_size = temp; } /* and process this guy */ if (AMITK_IS_DATA_SET(objects->data)) { temp = point_min_dim(AMITK_DATA_SET_VOXEL_SIZE(objects->data)); if (min_voxel_size < 0.0) min_voxel_size = temp; else if (temp < min_voxel_size) min_voxel_size = temp; } return min_voxel_size; } /* returns the minimum dimensional width of the data set with the largest voxel size */ /* figure out what our voxel size is going to be for our returned slices. I'm going to base this on the volume with the largest minimum voxel dimension, this way the user doesn't suddenly get a huge image when adding in a study with small voxels (i.e. a CT scan). The user can always increase the zoom later*/ amide_real_t amitk_data_sets_get_max_min_voxel_size(GList * objects) { amide_real_t min_voxel_size, temp; if (objects == NULL) return -1.0; /* invalid */ /* first process the rest of the list */ min_voxel_size = amitk_data_sets_get_max_min_voxel_size(objects->next); /* now process and compare to the children */ temp = amitk_data_sets_get_max_min_voxel_size(AMITK_OBJECT_CHILDREN(objects->data)); if (temp >= 0.0) { if (min_voxel_size < 0.0) min_voxel_size = temp; else if (temp > min_voxel_size) min_voxel_size = temp; } /* and process this guy */ if (AMITK_IS_DATA_SET(objects->data)) { temp = point_min_dim(AMITK_DATA_SET_VOXEL_SIZE(objects->data)); if (min_voxel_size < 0.0) min_voxel_size = temp; else if (temp > min_voxel_size) min_voxel_size = temp; } return min_voxel_size; } /* returns an unreferenced pointer to a slice in the list with the given parent */ AmitkDataSet * amitk_data_sets_find_with_slice_parent(GList * slices, const AmitkDataSet * slice_parent) { AmitkDataSet * slice=NULL; if (slice_parent == NULL) return NULL; if (slices == NULL) return NULL; if (AMITK_IS_DATA_SET(slices->data)) if (AMITK_DATA_SET(slices->data)->slice_parent == slice_parent) slice = AMITK_DATA_SET(slices->data); /* check children */ if (slice == NULL) slice = amitk_data_sets_find_with_slice_parent(AMITK_OBJECT_CHILDREN(slices->data), slice_parent); /* process the rest of the list */ if (slice == NULL) slice = amitk_data_sets_find_with_slice_parent(slices->next, slice_parent); return slice; } /* removes from slices the slice with the given slice_parent */ GList * amitk_data_sets_remove_with_slice_parent(GList * slices,const AmitkDataSet * slice_parent) { AmitkDataSet * slice; if (slice_parent == NULL) return NULL; if (slices == NULL) return NULL; slice = amitk_data_sets_find_with_slice_parent(slices, slice_parent); while (slice != NULL) { slices = g_list_remove(slices, slice); amitk_object_unref(slice); /* may be multiple slices with this parent */ slice = amitk_data_sets_find_with_slice_parent(slices, slice_parent); } return slices; } /* trim cache slice size down to max_size, removes from end */ GList * slice_cache_trim(GList * slice_cache, gint max_size) { GList * last; while (g_list_length(slice_cache) > max_size) { last = g_list_last(slice_cache); slice_cache = g_list_remove_link(slice_cache, last); amitk_objects_unref(last); } return slice_cache; } /* several things cause slice caches to get invalidated, so they don't need to be explicitly checked here 1. Scale factor changes 2. The parent data set's space changing 3. The parent data set's voxel size changing 4. Any change to the raw data */ static AmitkDataSet * slice_cache_find (GList * slice_cache, AmitkDataSet * parent_ds, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * view_volume) { AmitkDataSet * slice; AmitkVoxel dim; amide_intpoint_t start_gate, end_gate; if (slice_cache == NULL) { return NULL; } else { slice = slice_cache->data; if (AMITK_DATA_SET_SLICE_PARENT(slice) == parent_ds) if (amitk_space_equal(AMITK_SPACE(slice), AMITK_SPACE(view_volume))) if (REAL_EQUAL(slice->scan_start, start)) if (REAL_EQUAL(amitk_data_set_get_frame_duration(slice,0), duration)) { if (gate < 0) { start_gate = AMITK_DATA_SET_VIEW_START_GATE(AMITK_DATA_SET_SLICE_PARENT(slice)); end_gate = AMITK_DATA_SET_VIEW_END_GATE(AMITK_DATA_SET_SLICE_PARENT(slice)); } else { start_gate = gate; end_gate = gate; } if (AMITK_DATA_SET_VIEW_START_GATE(slice) == start_gate) if (AMITK_DATA_SET_VIEW_END_GATE(slice) == end_gate) if (REAL_EQUAL(slice->voxel_size.z,AMITK_VOLUME_Z_CORNER(view_volume))) { dim.x = ceil(fabs(AMITK_VOLUME_X_CORNER(view_volume))/pixel_size.x); dim.y = ceil(fabs(AMITK_VOLUME_Y_CORNER(view_volume))/pixel_size.y); dim.z = dim.t = dim.g = 1; if (VOXEL_EQUAL(dim, AMITK_DATA_SET_DIM(slice))) if (AMITK_DATA_SET_INTERPOLATION(slice) == AMITK_DATA_SET_INTERPOLATION(parent_ds)) if (AMITK_DATA_SET_RENDERING(slice) == AMITK_DATA_SET_RENDERING(parent_ds)) return slice; } } } /* this one's not it, keep looking */ return slice_cache_find(slice_cache->next, parent_ds, start, duration, gate, pixel_size, view_volume); } /* give a list of data_sets, returns a list of slices of equal size and orientation intersecting these data_sets. The slice_cache is a list of already generated slices, if an appropriate slice is found in there, it'll be used */ /* notes - in real practice, the parent data set's local cache is rarely used, as most slices, if there in the local cache, will also be in the passed in cache - the "gate" parameter should ordinarily by -1 (ignored). Only use it to override the the data set's view_start_gate/view_end_gate parameters */ GList * amitk_data_sets_get_slices(GList * objects, GList ** pslice_cache, const gint max_slice_cache_size, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * view_volume) { GList * slices=NULL; AmitkDataSet * local_slice; AmitkDataSet * canvas_slice=NULL; AmitkDataSet * slice; AmitkDataSet * parent_ds; gint num_data_sets=0; #ifdef SLICE_TIMING struct timeval tv1; struct timeval tv2; gdouble time1; gdouble time2; /* let's do some timing */ gettimeofday(&tv1, NULL); #endif g_return_val_if_fail(objects != NULL, NULL); /* and get the slices */ while (objects != NULL) { if (AMITK_IS_DATA_SET(objects->data)) { num_data_sets++; parent_ds = AMITK_DATA_SET(objects->data); /* try to find it in the caches first */ if (pslice_cache != NULL) canvas_slice = slice_cache_find(*pslice_cache, parent_ds, start, duration, gate, pixel_size, view_volume); local_slice = slice_cache_find(parent_ds->slice_cache, parent_ds, start, duration, gate, pixel_size, view_volume); if (canvas_slice != NULL) { slice = amitk_object_ref(canvas_slice); } else if (local_slice != NULL) { slice = amitk_object_ref(local_slice); } else {/* generate a new one */ slice = amitk_data_set_get_slice(parent_ds, start, duration, gate, pixel_size, view_volume); } g_return_val_if_fail(slice != NULL, slices); slices = g_list_prepend(slices, slice); if ((canvas_slice == NULL) && (pslice_cache != NULL)) *pslice_cache = g_list_prepend(*pslice_cache, amitk_object_ref(slice)); /* most recently used first */ if (local_slice == NULL) { parent_ds->slice_cache = g_list_prepend(parent_ds->slice_cache, amitk_object_ref(slice)); /* regulate the size of the local per dataset cache */ parent_ds->slice_cache = slice_cache_trim(parent_ds->slice_cache, 3 * MAX(AMITK_DATA_SET_NUM_FRAMES(parent_ds), AMITK_DATA_SET_NUM_GATES(parent_ds))); } } objects = objects->next; } /* regulate the size of the global cache */ if (pslice_cache != NULL) *pslice_cache = slice_cache_trim(*pslice_cache, max_slice_cache_size); #ifdef SLICE_TIMING /* and wrapup our timing */ gettimeofday(&tv2, NULL); time1 = ((double) tv1.tv_sec) + ((double) tv1.tv_usec)/1000000.0; time2 = ((double) tv2.tv_sec) + ((double) tv2.tv_usec)/1000000.0; g_print("######## Slice Generating Took %5.3f (s) #########\n",time2-time1); #endif return slices; } /* function to perform the given operation on a single data set parameter0 and parameter1 are used by some operations, for instance for the threshold operation, values below parameter0 are set to 0, values above parameter1 1, and parameters between are interpolated */ AmitkDataSet * amitk_data_sets_math_unary(AmitkDataSet * ds1, AmitkOperationUnary operation, amide_data_t parameter0, amide_data_t parameter1, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel i_dim; AmitkDataSet * output_ds; AmitkVoxel i_voxel; amide_data_t value; gchar * temp_string; AmitkViewMode i_view_mode; div_t x; gint divider, total_planes,image_num; gboolean continue_work=TRUE; AmitkFormat format; g_return_val_if_fail(AMITK_IS_DATA_SET(ds1), NULL); i_dim = AMITK_DATA_SET_DIM (ds1); switch(operation) { case AMITK_OPERATION_UNARY_RESCALE: if (parameter0 >= parameter1) format = AMITK_FORMAT_UBYTE; /* results will be 0 or 1 */ else format = AMITK_FORMAT_FLOAT; /* results will be between 0 and 1 */ break; case AMITK_OPERATION_UNARY_REMOVE_NEGATIVES: format = AMITK_FORMAT_FLOAT; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); goto error; } output_ds = amitk_data_set_new_with_data(NULL, AMITK_DATA_SET_MODALITY(ds1), format, i_dim, AMITK_SCALING_TYPE_0D); if (output_ds == NULL) { g_warning(_("couldn't allocate %d MB for the output_ds data set structure"), amitk_raw_format_calc_num_bytes(i_dim, format)/(1024*1024)); goto error; } /* Start setting up the new dataset */ amitk_space_copy_in_place( AMITK_SPACE(output_ds), AMITK_SPACE(ds1)); amitk_data_set_set_scale_factor(output_ds, 1.0); amitk_data_set_set_voxel_size(output_ds, AMITK_DATA_SET_VOXEL_SIZE(ds1)); amitk_data_set_calc_far_corner(output_ds); amitk_data_set_set_scan_start(output_ds, amitk_data_set_get_start_time(ds1, i_voxel.t)); for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table(output_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE(ds1, i_view_mode)); for (i_view_mode=AMITK_VIEW_MODE_LINKED_2WAY; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table_independent(output_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(ds1, i_view_mode)); /* set a new name for this guy */ switch(operation) { case AMITK_OPERATION_UNARY_RESCALE: if (parameter0 >= parameter1) temp_string = g_strdup_printf(_("Result: %s rescaled at %3.2g"), AMITK_OBJECT_NAME(ds1), parameter0); else temp_string = g_strdup_printf(_("Result: %s rescaled below %3.2g and above %3.2g"), AMITK_OBJECT_NAME(ds1), parameter0, parameter1); break; case AMITK_OPERATION_UNARY_REMOVE_NEGATIVES: temp_string = g_strdup_printf(_("Result: %s negative values removed"), AMITK_OBJECT_NAME(ds1)); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); goto error; } amitk_object_set_name(AMITK_OBJECT(output_ds), temp_string); g_free(temp_string); if (update_func != NULL) { temp_string = g_strdup_printf(_("Performing math operation")); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = i_dim.z*i_dim.t*i_dim.g; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); /* fill in output_ds by performing the operation on the data set */ for (i_voxel.g = 0; (i_voxel.g < i_dim.g) && continue_work; i_voxel.g++) { amitk_data_set_set_gate_time(output_ds, i_voxel.g, amitk_data_set_get_gate_time(ds1, i_voxel.g)); for (i_voxel.t = 0; (i_voxel.t < i_dim.t) && continue_work; i_voxel.t++) { amitk_data_set_set_frame_duration(output_ds, i_voxel.t, amitk_data_set_get_frame_duration(ds1, i_voxel.t)); for (i_voxel.z = 0; (i_voxel.z < i_dim.z) && continue_work; i_voxel.z++) { if (update_func != NULL) { image_num = i_voxel.z+i_voxel.t*i_dim.z+i_voxel.g*i_dim.z*i_dim.t; x = div(image_num,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } for (i_voxel.y = 0; i_voxel.y < i_dim.y; i_voxel.y++) { for (i_voxel.x = 0; i_voxel.x < i_dim.x; i_voxel.x++) { value = amitk_data_set_get_value(ds1, i_voxel); switch(operation) { case AMITK_OPERATION_UNARY_RESCALE: if (parameter0 > parameter1) { AMITK_RAW_DATA_UBYTE_SET_CONTENT(output_ds->raw_data, i_voxel) = (value >= parameter0); } else { if (value <= parameter0) AMITK_RAW_DATA_FLOAT_SET_CONTENT(output_ds->raw_data, i_voxel) = 0.0; else if (value >= parameter1) AMITK_RAW_DATA_FLOAT_SET_CONTENT(output_ds->raw_data, i_voxel) = 1.0; else AMITK_RAW_DATA_FLOAT_SET_CONTENT(output_ds->raw_data, i_voxel) = (value - parameter0)/(parameter1-parameter0); } case AMITK_OPERATION_UNARY_REMOVE_NEGATIVES: AMITK_RAW_DATA_FLOAT_SET_CONTENT(output_ds->raw_data, i_voxel) = (value < 0.0) ? 0.0 : value; break; default: goto error; } } } } } } if (!continue_work) goto error; /* recalc the temporary parameters */ amitk_data_set_calc_min_max(output_ds, NULL, NULL); /* set some sensible thresholds */ output_ds->threshold_max[0] = output_ds->threshold_max[1] = amitk_data_set_get_global_max(output_ds); output_ds->threshold_min[0] = output_ds->threshold_min[1] = amitk_data_set_get_global_min(output_ds); output_ds->threshold_ref_frame[1] = AMITK_DATA_SET_NUM_FRAMES(output_ds)-1; goto exit; error: if (output_ds != NULL) { amitk_object_unref(output_ds); output_ds = NULL; } exit: if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); return output_ds; } /* function to perform the given operation between two data sets DIVISION: parameter0 used a threshold for the divisor, below which output is set zero. T2STAR: parameter0 is the echo time of ds1 parameter1 is the echo time of ds2 */ AmitkDataSet * amitk_data_sets_math_binary(AmitkDataSet * ds1, AmitkDataSet * ds2, AmitkOperationBinary operation, amide_data_t parameter0, amide_data_t parameter1, gboolean by_frames, gboolean maintain_ds1_dim, AmitkUpdateFunc update_func, gpointer update_data) { GList * data_sets=NULL; AmitkCorners corner; AmitkVolume * volume=NULL; AmitkPoint voxel_size; AmitkCanvasPoint pixel_size; AmitkVoxel i_dim,j_dim; amide_time_t frame_start, frame_duration; AmitkDataSet * output_ds=NULL; AmitkVoxel i_voxel, j_voxel, k_voxel; AmitkPoint new_offset; AmitkDataSet * slice1=NULL; AmitkDataSet * slice2=NULL; amitk_format_FLOAT_t value0; amitk_format_FLOAT_t value1; gchar * temp_string; AmitkViewMode i_view_mode; div_t x; gint divider, total_planes,image_num; gboolean continue_work=TRUE; amide_data_t delta_echo=1.0; g_return_val_if_fail(AMITK_IS_DATA_SET(ds1), NULL); g_return_val_if_fail(AMITK_IS_DATA_SET(ds2), NULL); /* more error checking */ switch(operation) { case AMITK_OPERATION_BINARY_T2STAR: if ((parameter0 <= 0) || (parameter1 <= 0)) { g_warning("echo times need to be positive"); goto error; } if (parameter0 == parameter1) { g_warning("echo times cannot be equal"); goto error; } /* switch data set order so that ds1 has shorter echo time */ if (parameter0 > parameter1) { AmitkDataSet * temp_ds; amide_data_t temp_parameter; temp_ds = ds2; ds2 = ds1; ds1 = temp_ds; temp_parameter = parameter1; parameter1 = parameter0; parameter0 = temp_parameter; } delta_echo = parameter1 - parameter0; break; default: break; } /* Make a list out of datasets 1 and 2 */ data_sets = g_list_append(NULL, ds1); data_sets = g_list_append(data_sets, ds2); /* Set up the voxel dimensions for the output data set */ if (maintain_ds1_dim) { volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(ds1))); voxel_size = AMITK_DATA_SET_VOXEL_SIZE(ds1); pixel_size.x = voxel_size.x; pixel_size.y = voxel_size.y; } else { /* create a volume that's a superset of the volumes of the two data sets */ volume = amitk_volume_new(); amitk_volumes_get_enclosing_corners(data_sets, AMITK_SPACE(volume), corner); amitk_space_set_offset(AMITK_SPACE(volume), corner[0]); amitk_volume_set_corner(volume, amitk_space_b2s(AMITK_SPACE(volume), corner[1])); voxel_size.x = voxel_size.y = voxel_size.z = amitk_data_sets_get_min_voxel_size(data_sets); pixel_size.x = pixel_size.y = voxel_size.x; } i_dim.x = j_dim.x = ceil(fabs(AMITK_VOLUME_X_CORNER(volume) ) / voxel_size.x ); i_dim.y = j_dim.y = ceil(fabs(AMITK_VOLUME_Y_CORNER(volume) ) / voxel_size.y ); i_dim.z = j_dim.z = ceil(fabs(AMITK_VOLUME_Z_CORNER(volume) ) / voxel_size.z ); i_dim.t = j_dim.t = AMITK_DATA_SET_DIM_T(ds1); if (AMITK_DATA_SET_DIM_T(ds1) != AMITK_DATA_SET_DIM_T(ds2)) { if (by_frames) { g_warning(_("Can't handle 'by frame' operations with data sets with unequal frame numbers, will use all frames of \"%s\" and the first gate of \"%s\"."), AMITK_OBJECT_NAME(ds1), AMITK_OBJECT_NAME(ds2)); j_dim.t = 1; } else { g_warning(_("Output data set will have the same number of frames as %s"), AMITK_OBJECT_NAME(ds1)); } } /* figure out what muti-gate studies we can handle */ i_dim.g = j_dim.g = AMITK_DATA_SET_DIM_G(ds1); if (AMITK_DATA_SET_DIM_G(ds1) != AMITK_DATA_SET_DIM_G(ds2)) { g_warning(_("Can't handle studies with different numbers of gates, will use all gates of \"%s\" and the first gate of \"%s\"."), AMITK_OBJECT_NAME(ds1), AMITK_OBJECT_NAME(ds2)); j_dim.g = 1; } output_ds = amitk_data_set_new_with_data(NULL, AMITK_DATA_SET_MODALITY(ds1), AMITK_FORMAT_FLOAT, i_dim, AMITK_SCALING_TYPE_0D); if (output_ds == NULL) { g_warning(_("couldn't allocate %d MB for the output_ds data set structure"), amitk_raw_format_calc_num_bytes(i_dim, AMITK_FORMAT_FLOAT)/(1024*1024)); goto error; } /* Start setting up the new dataset */ amitk_space_copy_in_place( AMITK_SPACE(output_ds), AMITK_SPACE(volume)); amitk_data_set_set_scale_factor(output_ds, 1.0); amitk_data_set_set_voxel_size(output_ds, voxel_size); amitk_raw_data_FLOAT_initialize_data(AMITK_DATA_SET_RAW_DATA(output_ds),NAN); for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table(output_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE(ds1, i_view_mode)); for (i_view_mode=AMITK_VIEW_MODE_LINKED_2WAY; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table_independent(output_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(ds1, i_view_mode)); /* set a new name for this guy */ switch(operation) { case AMITK_OPERATION_BINARY_T2STAR: temp_string = g_strdup_printf(_("R2* (1/s) based on: %s %s"), AMITK_OBJECT_NAME(ds1), AMITK_OBJECT_NAME(ds2)); break; default: temp_string = g_strdup_printf(_("Result: %s %s %s"), AMITK_OBJECT_NAME(ds1), amitk_operation_binary_get_name(operation), AMITK_OBJECT_NAME(ds2)); break; } amitk_object_set_name(AMITK_OBJECT(output_ds), temp_string); g_free(temp_string); if (update_func != NULL) { temp_string = g_strdup_printf(_("Performing math operation")); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = i_dim.z*i_dim.t*i_dim.g; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); /* fill in output_ds by performing the operation on the data sets */ corner[0] = AMITK_VOLUME_CORNER(volume); corner[0].z = voxel_size.z; amitk_volume_set_corner(volume, corner[0]); /* set the z dim of the slices */ k_voxel = zero_voxel; new_offset = zero_point; for (i_voxel.t = 0; (i_voxel.t < i_dim.t) && continue_work; i_voxel.t++) { j_voxel.t = (i_voxel.t >= j_dim.t) ? 0 : i_voxel.t; /* only used if by_frames is true */ frame_start = amitk_data_set_get_start_time(ds1, i_voxel.t); frame_duration = amitk_data_set_get_frame_duration(ds1, i_voxel.t); if (i_voxel.t == 0) amitk_data_set_set_scan_start(output_ds, frame_start); amitk_data_set_set_frame_duration(output_ds, i_voxel.t, frame_duration); for (i_voxel.g = 0; (i_voxel.g < i_dim.g) && continue_work; i_voxel.g++) { j_voxel.g = (i_voxel.g >= j_dim.g) ? 0 : i_voxel.g; amitk_data_set_set_gate_time(output_ds, i_voxel.g, amitk_data_set_get_gate_time(ds1, i_voxel.g)); for (i_voxel.z = 0; (i_voxel.z < i_dim.z) && continue_work; i_voxel.z++) { j_voxel.z = i_voxel.z; new_offset.z = i_voxel.z * voxel_size.z; if (update_func != NULL) { image_num = i_voxel.z+i_voxel.t*i_dim.z+i_voxel.g*i_dim.z*i_dim.t; x = div(image_num,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } /* advance the requested slice volume */ amitk_space_set_offset( AMITK_SPACE(volume), amitk_space_s2b(AMITK_SPACE(output_ds), new_offset)); slice1 = amitk_data_set_get_slice(ds1, frame_start, frame_duration, i_voxel.g, pixel_size, volume); slice2 = amitk_data_set_get_slice(ds2, by_frames ? amitk_data_set_get_start_time(ds2, j_voxel.t) : frame_start, by_frames ? amitk_data_set_get_frame_duration(ds2, j_voxel.t) : frame_duration, j_voxel.g, pixel_size, volume); if ((slice1 == NULL) || (slice2 == NULL)) { g_warning(_("couldn't generate slices from the data set...")); goto error; } for (i_voxel.y = 0, k_voxel.y = 0; i_voxel.y < i_dim.y; i_voxel.y++, k_voxel.y++) { for (i_voxel.x = 0, k_voxel.x = 0; i_voxel.x < i_dim.x; i_voxel.x++, k_voxel.x++) { switch(operation) { case AMITK_OPERATION_BINARY_ADD: value0 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(slice1), k_voxel ) + AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT( AMITK_DATA_SET(slice2), k_voxel); break; case AMITK_OPERATION_BINARY_SUB: value0 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(slice1), k_voxel ) - AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT( AMITK_DATA_SET(slice2), k_voxel); break; case AMITK_OPERATION_BINARY_MULTIPLY: value0 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(slice1), k_voxel ) * AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT( AMITK_DATA_SET(slice2), k_voxel); break; case AMITK_OPERATION_BINARY_DIVISION: value0 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT( AMITK_DATA_SET(slice2), k_voxel); if (value0 > parameter0) value0 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(slice1), k_voxel ) / value0; else value0 = 0.0; break; case AMITK_OPERATION_BINARY_T2STAR: /* we actually compute the relaxation rate, that way we don't run into issues with infinity */ value0 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(slice1), k_voxel); value1 = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(AMITK_DATA_SET(slice2), k_voxel); if ((value0 <= 0) || (value1 <= 0)) value0 = 0; /* don't have signal, can't assess */ if (value0 <= value1) /* no decay between two time points */ value0 = 0; /* no relaxation */ else /* compute in units of 1/s */ value0 = 1000.0 * (log(value0)-log(value1)) / (delta_echo); break; default: goto error; } AMITK_RAW_DATA_FLOAT_SET_CONTENT(output_ds->raw_data, i_voxel) = value0; } } amitk_object_unref(slice1); slice1 = NULL; amitk_object_unref(slice2); slice2 = NULL; } } } if (!continue_work) goto error; /* recalc the temporary parameters */ amitk_data_set_calc_min_max(output_ds, NULL, NULL); /* set some sensible thresholds */ output_ds->threshold_max[0] = output_ds->threshold_max[1] = amitk_data_set_get_global_max(output_ds); output_ds->threshold_min[0] = output_ds->threshold_min[1] = amitk_data_set_get_global_min(output_ds); output_ds->threshold_ref_frame[1] = AMITK_DATA_SET_NUM_FRAMES(output_ds)-1; goto exit; error: if (output_ds != NULL) { amitk_object_unref(output_ds); output_ds = NULL; } exit: amitk_object_unref(volume); g_list_free(data_sets); if (slice1 != NULL) amitk_object_unref(slice1); if (slice2 != NULL) amitk_object_unref(slice2); if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); return output_ds; } const gchar * amitk_scaling_type_get_name(const AmitkScalingType scaling_type) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_SCALING_TYPE); enum_value = g_enum_get_value(enum_class, scaling_type); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_interpolation_get_name(const AmitkInterpolation interpolation) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_INTERPOLATION); enum_value = g_enum_get_value(enum_class, interpolation); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_rendering_get_name(const AmitkRendering rendering) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_RENDERING); enum_value = g_enum_get_value(enum_class, rendering); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_operation_unary_get_name(const AmitkOperationUnary operation) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_OPERATION_UNARY); enum_value = g_enum_get_value(enum_class, operation); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_operation_binary_get_name(const AmitkOperationBinary operation) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_OPERATION_BINARY); enum_value = g_enum_get_value(enum_class, operation); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_subject_orientation_get_name(const AmitkSubjectOrientation subject_orientation) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_SUBJECT_ORIENTATION); enum_value = g_enum_get_value(enum_class, subject_orientation); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_subject_sex_get_name(const AmitkSubjectSex subject_sex) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_SUBJECT_SEX); enum_value = g_enum_get_value(enum_class, subject_sex); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_thresholding_get_name(const AmitkThresholding thresholding) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_THRESHOLDING); enum_value = g_enum_get_value(enum_class, thresholding); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_threshold_style_get_name(const AmitkThresholdStyle threshold_style) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_THRESHOLD_STYLE); enum_value = g_enum_get_value(enum_class, threshold_style); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_conversion_get_name(const AmitkConversion conversion) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_CONVERSION); enum_value = g_enum_get_value(enum_class, conversion); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_weight_unit_get_name(const AmitkWeightUnit weight_unit) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_WEIGHT_UNIT); enum_value = g_enum_get_value(enum_class, weight_unit); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_dose_unit_get_name(const AmitkDoseUnit dose_unit) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_DOSE_UNIT); enum_value = g_enum_get_value(enum_class, dose_unit); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_cylinder_unit_get_name(const AmitkCylinderUnit cylinder_unit) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_CYLINDER_UNIT); enum_value = g_enum_get_value(enum_class, cylinder_unit); g_type_class_unref(enum_class); return enum_value->value_nick; } amide_data_t amitk_weight_unit_convert_to (const amide_data_t kg, const AmitkWeightUnit weight_unit) { switch(weight_unit) { case AMITK_WEIGHT_UNIT_KILOGRAM: return kg; break; case AMITK_WEIGHT_UNIT_GRAM: return kg*1000.0; break; case AMITK_WEIGHT_UNIT_POUND: return kg*2.2046226; break; case AMITK_WEIGHT_UNIT_OUNCE: return kg*35.273962; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return 0.0; } amide_data_t amitk_weight_unit_convert_from (const amide_data_t weight, const AmitkWeightUnit weight_unit) { switch(weight_unit) { case AMITK_WEIGHT_UNIT_KILOGRAM: return weight; break; case AMITK_WEIGHT_UNIT_GRAM: return weight/1000.0; break; case AMITK_WEIGHT_UNIT_POUND: return weight/2.2046226; break; case AMITK_WEIGHT_UNIT_OUNCE: return weight/35.273962; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return 0.0; } amide_data_t amitk_dose_unit_convert_to (const amide_data_t MBq, const AmitkDoseUnit dose_unit) { switch(dose_unit) { case AMITK_DOSE_UNIT_MEGABECQUEREL: return MBq; break; case AMITK_DOSE_UNIT_MILLICURIE: return MBq/37.0; break; case AMITK_DOSE_UNIT_MICROCURIE: return MBq/0.037; break; case AMITK_DOSE_UNIT_NANOCURIE: return MBq/0.000037; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return 0.0; } amide_data_t amitk_dose_unit_convert_from (const amide_data_t dose, const AmitkDoseUnit dose_unit) { switch(dose_unit) { case AMITK_DOSE_UNIT_MEGABECQUEREL: return dose; break; case AMITK_DOSE_UNIT_MILLICURIE: return dose*37.0; break; case AMITK_DOSE_UNIT_MICROCURIE: return dose*0.037; break; case AMITK_DOSE_UNIT_NANOCURIE: return dose*0.000037; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return 0.0; } amide_data_t amitk_cylinder_unit_convert_to (const amide_data_t MBq_cc_image_units, const AmitkCylinderUnit cylinder_unit) { switch(cylinder_unit) { case AMITK_CYLINDER_UNIT_MEGABECQUEREL_PER_CC_IMAGE_UNIT: return MBq_cc_image_units; break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MEGABECQUEREL: return 1.0/MBq_cc_image_units; case AMITK_CYLINDER_UNIT_MILLICURIE_PER_CC_IMAGE_UNIT: return amitk_dose_unit_convert_to(MBq_cc_image_units, AMITK_DOSE_UNIT_MILLICURIE); break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MILLICURIE: return 1.0/amitk_dose_unit_convert_to(MBq_cc_image_units, AMITK_DOSE_UNIT_MILLICURIE); break; case AMITK_CYLINDER_UNIT_MICROCURIE_PER_CC_IMAGE_UNIT: return amitk_dose_unit_convert_to(MBq_cc_image_units, AMITK_DOSE_UNIT_MICROCURIE); break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MICROCURIE: return 1.0/amitk_dose_unit_convert_to(MBq_cc_image_units, AMITK_DOSE_UNIT_MICROCURIE); break; case AMITK_CYLINDER_UNIT_NANOCURIE_PER_CC_IMAGE_UNIT: return amitk_dose_unit_convert_to(MBq_cc_image_units, AMITK_DOSE_UNIT_NANOCURIE); break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_NANOCURIE: return 1.0/amitk_dose_unit_convert_to(MBq_cc_image_units, AMITK_DOSE_UNIT_NANOCURIE); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return 0.0; } amide_data_t amitk_cylinder_unit_convert_from (const amide_data_t cylinder_factor, const AmitkCylinderUnit cylinder_unit) { switch(cylinder_unit) { case AMITK_CYLINDER_UNIT_MEGABECQUEREL_PER_CC_IMAGE_UNIT: return cylinder_factor; break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MEGABECQUEREL: return 1.0/cylinder_factor; break; case AMITK_CYLINDER_UNIT_MILLICURIE_PER_CC_IMAGE_UNIT: return amitk_dose_unit_convert_from(cylinder_factor, AMITK_DOSE_UNIT_MILLICURIE); break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MILLICURIE: return amitk_dose_unit_convert_from(1.0/cylinder_factor, AMITK_DOSE_UNIT_MILLICURIE); break; case AMITK_CYLINDER_UNIT_MICROCURIE_PER_CC_IMAGE_UNIT: return amitk_dose_unit_convert_from(cylinder_factor, AMITK_DOSE_UNIT_MICROCURIE); break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MICROCURIE: return amitk_dose_unit_convert_from(1.0/cylinder_factor, AMITK_DOSE_UNIT_MICROCURIE); break; case AMITK_CYLINDER_UNIT_NANOCURIE_PER_CC_IMAGE_UNIT: return amitk_dose_unit_convert_from(cylinder_factor, AMITK_DOSE_UNIT_NANOCURIE); break; case AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_NANOCURIE: return amitk_dose_unit_convert_from(1.0/cylinder_factor, AMITK_DOSE_UNIT_NANOCURIE); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } return 0.0; } amide-1.0.6/amide-current/src/amitk_data_set.h000066400000000000000000000752471423227705100212670ustar00rootroot00000000000000/* amitk_data_set.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_DATA_SET_H__ #define __AMITK_DATA_SET_H__ #include "amitk_volume.h" #include "amitk_raw_data.h" #include "amitk_color_table.h" #include "amitk_filter.h" #include "amitk_preferences.h" G_BEGIN_DECLS #define AMITK_TYPE_DATA_SET (amitk_data_set_get_type ()) #define AMITK_DATA_SET(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_DATA_SET, AmitkDataSet)) #define AMITK_DATA_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_DATA_SET, AmitkDataSetClass)) #define AMITK_IS_DATA_SET(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_DATA_SET)) #define AMITK_IS_DATA_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_DATA_SET)) #define AMITK_DATA_SET_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_DATA_SET, AmitkDataSetClass)) #define AMITK_DATA_SET_MODALITY(ds) (AMITK_DATA_SET(ds)->modality) #define AMITK_DATA_SET_VOXEL_SIZE(ds) (AMITK_DATA_SET(ds)->voxel_size) #define AMITK_DATA_SET_VOXEL_SIZE_X(ds) (AMITK_DATA_SET(ds)->voxel_size.x) #define AMITK_DATA_SET_VOXEL_SIZE_Y(ds) (AMITK_DATA_SET(ds)->voxel_size.y) #define AMITK_DATA_SET_VOXEL_SIZE_Z(ds) (AMITK_DATA_SET(ds)->voxel_size.z) #define AMITK_DATA_SET_VOXEL_VOLUME(ds) (AMITK_DATA_SET(ds)->voxel_size.z*AMITK_DATA_SET(ds)->voxel_size.y*AMITK_DATA_SET(ds)->voxel_size.x) #define AMITK_DATA_SET_RAW_DATA(ds) (AMITK_DATA_SET(ds)->raw_data) #define AMITK_DATA_SET_DIM(ds) (AMITK_RAW_DATA_DIM(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_DIM_X(ds) (AMITK_RAW_DATA_DIM_X(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_DIM_Y(ds) (AMITK_RAW_DATA_DIM_Y(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_DIM_Z(ds) (AMITK_RAW_DATA_DIM_Z(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_DIM_G(ds) (AMITK_RAW_DATA_DIM_G(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_DIM_T(ds) (AMITK_RAW_DATA_DIM_T(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_FORMAT(ds) (AMITK_RAW_DATA_FORMAT(AMITK_DATA_SET_RAW_DATA(ds))) #define AMITK_DATA_SET_NUM_GATES(ds) (AMITK_DATA_SET_DIM_G(ds)) #define AMITK_DATA_SET_NUM_FRAMES(ds) (AMITK_DATA_SET_DIM_T(ds)) #define AMITK_DATA_SET_TOTAL_PLANES(ds) (AMITK_DATA_SET_DIM_Z(ds)*AMITK_DATA_SET_DIM_G(ds)*AMITK_DATA_SET_DIM_T(ds)) #define AMITK_DATA_SET_DISTRIBUTION(ds) (AMITK_DATA_SET(ds)->distribution) #define AMITK_DATA_SET_COLOR_TABLE(ds, view_mode) (AMITK_DATA_SET(ds)->color_table[view_mode]) #define AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(ds, view_mode) (AMITK_DATA_SET(ds)->color_table_independent[view_mode]) #define AMITK_DATA_SET_INTERPOLATION(ds) (AMITK_DATA_SET(ds)->interpolation) #define AMITK_DATA_SET_RENDERING(ds) (AMITK_DATA_SET(ds)->rendering) #define AMITK_DATA_SET_DYNAMIC(ds) (AMITK_DATA_SET_NUM_FRAMES(ds) > 1) #define AMITK_DATA_SET_GATED(ds) (AMITK_DATA_SET_NUM_GATES(ds) > 1) #define AMITK_DATA_SET_THRESHOLDING(ds) (AMITK_DATA_SET(ds)->thresholding) #define AMITK_DATA_SET_THRESHOLD_STYLE(ds) (AMITK_DATA_SET(ds)->threshold_style) #define AMITK_DATA_SET_SLICE_PARENT(ds) (AMITK_DATA_SET(ds)->slice_parent) #define AMITK_DATA_SET_SCAN_DATE(ds) (AMITK_DATA_SET(ds)->scan_date) #define AMITK_DATA_SET_SUBJECT_NAME(ds) (AMITK_DATA_SET(ds)->subject_name) #define AMITK_DATA_SET_SUBJECT_ID(ds) (AMITK_DATA_SET(ds)->subject_id) #define AMITK_DATA_SET_SUBJECT_DOB(ds) (AMITK_DATA_SET(ds)->subject_dob) #define AMITK_DATA_SET_SERIES_NUMBER(ds) (AMITK_DATA_SET(ds)->series_number) #define AMITK_DATA_SET_DICOM_IMAGE_TYPE(ds) (AMITK_DATA_SET(ds)->dicom_image_type) #define AMITK_DATA_SET_SCAN_START(ds) (AMITK_DATA_SET(ds)->scan_start) #define AMITK_DATA_SET_THRESHOLD_REF_FRAME(ds,ref_frame) (AMITK_DATA_SET(ds)->threshold_ref_frame[ref_frame]) #define AMITK_DATA_SET_THRESHOLD_MAX(ds, ref_frame) (AMITK_DATA_SET(ds)->threshold_max[ref_frame]) #define AMITK_DATA_SET_THRESHOLD_MIN(ds, ref_frame) (AMITK_DATA_SET(ds)->threshold_min[ref_frame]) #define AMITK_DATA_SET_SCALING_TYPE(ds) (AMITK_DATA_SET(ds)->scaling_type) #define AMITK_DATA_SET_SCALING_HAS_INTERCEPT(ds) ((AMITK_DATA_SET(ds)->scaling_type == AMITK_SCALING_TYPE_0D_WITH_INTERCEPT) || (AMITK_DATA_SET(ds)->scaling_type == AMITK_SCALING_TYPE_1D_WITH_INTERCEPT) || (AMITK_DATA_SET(ds)->scaling_type == AMITK_SCALING_TYPE_2D_WITH_INTERCEPT)) #define AMITK_DATA_SET_SUBJECT_ORIENTATION(ds) (AMITK_DATA_SET(ds)->subject_orientation) #define AMITK_DATA_SET_SUBJECT_SEX(ds) (AMITK_DATA_SET(ds)->subject_sex) #define AMITK_DATA_SET_CONVERSION(ds) (AMITK_DATA_SET(ds)->conversion) #define AMITK_DATA_SET_SCALE_FACTOR(ds) (AMITK_DATA_SET(ds)->scale_factor) #define AMITK_DATA_SET_INJECTED_DOSE(ds) (AMITK_DATA_SET(ds)->injected_dose) #define AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(ds) (AMITK_DATA_SET(ds)->displayed_dose_unit) #define AMITK_DATA_SET_SUBJECT_WEIGHT(ds) (AMITK_DATA_SET(ds)->subject_weight) #define AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(ds) (AMITK_DATA_SET(ds)->displayed_weight_unit) #define AMITK_DATA_SET_CYLINDER_FACTOR(ds) (AMITK_DATA_SET(ds)->cylinder_factor) #define AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(ds) (AMITK_DATA_SET(ds)->displayed_cylinder_unit) #define AMITK_DATA_SET_INVERSION_TIME(ds) (AMITK_DATA_SET(ds)->inversion_time) #define AMITK_DATA_SET_ECHO_TIME(ds) (AMITK_DATA_SET(ds)->echo_time) #define AMITK_DATA_SET_DIFFUSION_B_VALUE(ds) (AMITK_DATA_SET(ds)->diffusion_b_value) #define AMITK_DATA_SET_DIFFUSION_DIRECTION(ds) (AMITK_DATA_SET(ds)->diffusion_direction) #define AMITK_DATA_SET_THRESHOLD_WINDOW(ds, i_win, limit) (AMITK_DATA_SET(ds)->threshold_window[i_win][limit]) #define AMITK_DATA_SET_VIEW_START_GATE(ds) (AMITK_DATA_SET(ds)->view_start_gate) #define AMITK_DATA_SET_VIEW_END_GATE(ds) (AMITK_DATA_SET(ds)->view_end_gate) #define AMITK_DATA_SET_NUM_VIEW_GATES(ds) (AMITK_DATA_SET(ds)->num_view_gates) #define AMITK_DATA_SET_DISTRIBUTION_SIZE 256 typedef enum { AMITK_OPERATION_UNARY_RESCALE, AMITK_OPERATION_UNARY_REMOVE_NEGATIVES, AMITK_OPERATION_UNARY_NUM } AmitkOperationUnary; typedef enum { AMITK_OPERATION_BINARY_ADD, AMITK_OPERATION_BINARY_SUB, AMITK_OPERATION_BINARY_MULTIPLY, AMITK_OPERATION_BINARY_DIVISION, AMITK_OPERATION_BINARY_T2STAR, AMITK_OPERATION_BINARY_NUM } AmitkOperationBinary; typedef enum { AMITK_INTERPOLATION_NEAREST_NEIGHBOR, AMITK_INTERPOLATION_TRILINEAR, AMITK_INTERPOLATION_NUM } AmitkInterpolation; typedef enum { AMITK_RENDERING_MPR, AMITK_RENDERING_MIP, AMITK_RENDERING_MINIP, AMITK_RENDERING_NUM } AmitkRendering; typedef enum { AMITK_THRESHOLDING_PER_SLICE, AMITK_THRESHOLDING_PER_FRAME, AMITK_THRESHOLDING_INTERPOLATE_FRAMES, AMITK_THRESHOLDING_GLOBAL, AMITK_THRESHOLDING_NUM } AmitkThresholding; /* 2D is per plane scaling */ /* 1D is per frame/gate scaling */ /* 0D is global scaling */ typedef enum { AMITK_SCALING_TYPE_0D, AMITK_SCALING_TYPE_1D, AMITK_SCALING_TYPE_2D, AMITK_SCALING_TYPE_0D_WITH_INTERCEPT, AMITK_SCALING_TYPE_1D_WITH_INTERCEPT, AMITK_SCALING_TYPE_2D_WITH_INTERCEPT, AMITK_SCALING_TYPE_NUM } AmitkScalingType; typedef enum { AMITK_CONVERSION_STRAIGHT, AMITK_CONVERSION_PERCENT_ID_PER_CC, AMITK_CONVERSION_SUV, AMITK_CONVERSION_NUM } AmitkConversion; typedef enum { AMITK_WEIGHT_UNIT_KILOGRAM, AMITK_WEIGHT_UNIT_GRAM, AMITK_WEIGHT_UNIT_POUND, AMITK_WEIGHT_UNIT_OUNCE, AMITK_WEIGHT_UNIT_NUM } AmitkWeightUnit; typedef enum { AMITK_DOSE_UNIT_MEGABECQUEREL, AMITK_DOSE_UNIT_MILLICURIE, AMITK_DOSE_UNIT_MICROCURIE, AMITK_DOSE_UNIT_NANOCURIE, AMITK_DOSE_UNIT_NUM } AmitkDoseUnit; typedef enum { AMITK_CYLINDER_UNIT_MEGABECQUEREL_PER_CC_IMAGE_UNIT, AMITK_CYLINDER_UNIT_MILLICURIE_PER_CC_IMAGE_UNIT, AMITK_CYLINDER_UNIT_MICROCURIE_PER_CC_IMAGE_UNIT, AMITK_CYLINDER_UNIT_NANOCURIE_PER_CC_IMAGE_UNIT, AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MEGABECQUEREL, AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MILLICURIE, AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_MICROCURIE, AMITK_CYLINDER_UNIT_IMAGE_UNIT_CC_PER_NANOCURIE, AMITK_CYLINDER_UNIT_NUM } AmitkCylinderUnit; typedef enum { AMITK_SUBJECT_ORIENTATION_UNKNOWN, AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST, AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST, AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST, AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST, AMITK_SUBJECT_ORIENTATION_NUM } AmitkSubjectOrientation; typedef enum { AMITK_SUBJECT_SEX_UNKNOWN, AMITK_SUBJECT_SEX_MALE, AMITK_SUBJECT_SEX_FEMALE, AMITK_SUBJECT_SEX_NUM } AmitkSubjectSex; /* the skip is for glib-mkenums, it doesn't know how to handle ifdef's */ typedef enum { /*< skip >*/ AMITK_IMPORT_METHOD_GUESS, AMITK_IMPORT_METHOD_RAW, #ifdef AMIDE_LIBDCMDATA_SUPPORT AMITK_IMPORT_METHOD_DCMTK, #endif #ifdef AMIDE_LIBECAT_SUPPORT AMITK_IMPORT_METHOD_LIBECAT, #endif #ifdef AMIDE_VISTAIO_SUPPORT AMITK_IMPORT_METHOD_VISTAIO, #endif #ifdef AMIDE_LIBMDC_SUPPORT AMITK_IMPORT_METHOD_LIBMDC, #endif AMITK_IMPORT_METHOD_NUM } AmitkImportMethod; /* the skip is for glib-mkenums, it doesn't know how to handle ifdef's */ typedef enum { /*< skip >*/ AMITK_EXPORT_METHOD_RAW, #ifdef AMIDE_LIBDCMDATA_SUPPORT AMITK_EXPORT_METHOD_DCMTK, #endif #ifdef AMIDE_LIBMDC_SUPPORT AMITK_EXPORT_METHOD_LIBMDC, #endif AMITK_EXPORT_METHOD_NUM } AmitkExportMethod; typedef struct _AmitkDataSetClass AmitkDataSetClass; typedef struct _AmitkDataSet AmitkDataSet; struct _AmitkDataSet { AmitkVolume parent; /* parameters that are saved */ gchar * scan_date; /* the time/day the image was acquired */ gchar * subject_name; /* name of the subject */ gchar * subject_id; /* id of the subject */ gchar * subject_dob; /* date of birth of the subject */ gint series_number; /* series number, used by dicom */ gchar * dicom_image_type; /* dicom specific image type designator */ AmitkModality modality; AmitkPoint voxel_size; /* in mm */ AmitkRawData * raw_data; AmitkScalingType scaling_type; /* dimensions of internal scaling */ AmitkRawData * internal_scaling_factor; /* internally (data set) supplied scaling factor */ AmitkRawData * internal_scaling_intercept; /* internally (data set) supplied scaling intercept */ amide_time_t * gate_time; /* array of the trigger times of each gate */ amide_time_t scan_start; amide_time_t * frame_duration; /* array of the duration of each frame */ AmitkColorTable color_table[AMITK_VIEW_MODE_NUM]; /* the color table to draw this volume in */ gboolean color_table_independent[AMITK_VIEW_MODE_NUM]; /* whether to use the independent color tables for 2-way or 3-way linked modes*/ AmitkInterpolation interpolation; AmitkRendering rendering; /* rendering mode - MPR/MIP/MINIP */ AmitkSubjectOrientation subject_orientation; /* orientation of subject in scanner */ AmitkSubjectSex subject_sex; amide_data_t scale_factor; /* user specified factor to multiply data set by */ AmitkConversion conversion; amide_data_t injected_dose; /* in MBq */ AmitkDoseUnit displayed_dose_unit; amide_data_t subject_weight; /* in KG */ AmitkWeightUnit displayed_weight_unit; amide_data_t cylinder_factor; /* (MBq/cc)/Image Unit */ AmitkCylinderUnit displayed_cylinder_unit; /* MRI parameters */ amide_time_t inversion_time; /* in milliseconds */ amide_time_t echo_time; /* in milliseconds */ gdouble diffusion_b_value; AmitkPoint diffusion_direction; /* Thresholding */ AmitkThresholding thresholding; /* what sort of thresholding we're using (per slice, global, etc.) */ AmitkThresholdStyle threshold_style; /* min/max or center/width */ amide_data_t threshold_max[2]; /* the thresholds to use for this volume */ amide_data_t threshold_min[2]; guint threshold_ref_frame[2]; amide_data_t threshold_window[AMITK_WINDOW_NUM][AMITK_LIMIT_NUM]; /* which gates we're showing */ amide_intpoint_t view_start_gate; amide_intpoint_t view_end_gate; /* parameters calculated as needed or on loading the object */ /* in theory, could be recalculated on the fly, but used enough we'll store... */ AmitkRawData * distribution; /* 1D array of data distribution, used in thresholding */ gboolean min_max_calculated; /* the min/max values can be calculated on demand */ amide_data_t global_max; amide_data_t global_min; amide_data_t * frame_max; amide_data_t * frame_min; AmitkRawData * current_scaling_factor; /* external_scaling * internal_scaling_factor[] */ amide_intpoint_t num_view_gates; GList * slice_cache; /* only used by derived data sets (slices and projections) */ /* this is a weak pointer, it should be NULL'ed automatically by gtk on the parent's destruction */ AmitkDataSet * slice_parent; /* misc data items - not saved in .xif file */ gint instance_number; /* used by dcmtk_interface.cc occasionally for sorting */ gint gate_num; /* used by dcmtk_interface.cc occasionally for sorting */ }; struct _AmitkDataSetClass { AmitkVolumeClass parent_class; void (* thresholding_changed) (AmitkDataSet * ds); void (* threshold_style_changed) (AmitkDataSet * ds); void (* thresholds_changed) (AmitkDataSet * ds); void (* windows_changed) (AmitkDataSet * ds); void (* color_table_changed) (AmitkDataSet * ds, AmitkViewMode * view_mode); void (* color_table_independent_changed)(AmitkDataSet * ds, AmitkViewMode * view_mode); void (* interpolation_changed) (AmitkDataSet * ds); void (* rendering_changed) (AmitkDataSet * ds); void (* subject_orientation_changed) (AmitkDataSet * ds); void (* subject_sex_changed) (AmitkDataSet * ds); void (* conversion_changed) (AmitkDataSet * ds); void (* scale_factor_changed) (AmitkDataSet * ds); void (* modality_changed) (AmitkDataSet * ds); void (* time_changed) (AmitkDataSet * ds); void (* voxel_size_changed) (AmitkDataSet * ds); void (* data_set_changed) (AmitkDataSet * ds); void (* invalidate_slice_cache) (AmitkDataSet * ds); void (* view_gates_changed) (AmitkDataSet * ds); }; /* Application-level methods */ GType amitk_data_set_get_type (void); AmitkDataSet * amitk_data_set_new (AmitkPreferences * preferences, const AmitkModality modality); AmitkDataSet * amitk_data_set_new_with_data (AmitkPreferences * preferences, const AmitkModality modality, const AmitkFormat format, const AmitkVoxel dim, const AmitkScalingType scaling_type); AmitkDataSet * amitk_data_set_import_raw_file (const gchar * file_name, const AmitkRawFormat raw_format, const AmitkVoxel data_dim, guint file_offset, AmitkPreferences * preferences, const AmitkModality modality, const gchar * data_set_name, const AmitkPoint voxel_size, const amide_data_t scale_factor, AmitkUpdateFunc update_func, gpointer update_data); GList * amitk_data_set_import_file (AmitkImportMethod method, int submethod, const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data); gboolean amitk_data_set_export_to_file (AmitkDataSet * ds, const AmitkExportMethod method, const int submethod, const gchar * filename, const gchar * studyname, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data); gboolean amitk_data_sets_export_to_file (GList * data_sets, const AmitkExportMethod method, const int submethod, const gchar * filename, const gchar * studyname, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data); amide_data_t amitk_data_set_get_global_max (AmitkDataSet * ds); amide_data_t amitk_data_set_get_global_min (AmitkDataSet * ds); amide_data_t amitk_data_set_get_frame_max (AmitkDataSet * ds, const guint frame); amide_data_t amitk_data_set_get_frame_min (AmitkDataSet * ds, const guint frame); AmitkColorTable amitk_data_set_get_color_table_to_use(AmitkDataSet * ds, const AmitkViewMode view_mode); void amitk_data_set_set_modality (AmitkDataSet * ds, const AmitkModality modality); void amitk_data_set_set_scan_start (AmitkDataSet * ds, const amide_time_t start); void amitk_data_set_set_frame_duration (AmitkDataSet * ds, const guint frame, amide_time_t duration); void amitk_data_set_set_voxel_size (AmitkDataSet * ds, const AmitkPoint voxel_size); void amitk_data_set_set_thresholding (AmitkDataSet * ds, const AmitkThresholding thresholding); void amitk_data_set_set_threshold_style(AmitkDataSet * ds, const AmitkThresholdStyle threshold_style); void amitk_data_set_set_threshold_max (AmitkDataSet * ds, guint which_reference, amide_data_t value); void amitk_data_set_set_threshold_min (AmitkDataSet * ds, guint which_reference, amide_data_t value); void amitk_data_set_set_threshold_ref_frame (AmitkDataSet * ds, guint which_reference, guint frame); void amitk_data_set_set_color_table (AmitkDataSet * ds, const AmitkViewMode view_mode, const AmitkColorTable new_color_table); void amitk_data_set_set_color_table_independent(AmitkDataSet * ds, const AmitkViewMode view_mode, const gboolean independent); void amitk_data_set_set_interpolation (AmitkDataSet * ds, const AmitkInterpolation new_interpolation); void amitk_data_set_set_rendering (AmitkDataSet * ds, const AmitkRendering new_rendering); void amitk_data_set_set_subject_orientation (AmitkDataSet * ds, const AmitkSubjectOrientation subject_orientation); void amitk_data_set_set_subject_sex (AmitkDataSet * ds, const AmitkSubjectSex subject_sex); void amitk_data_set_set_scan_date (AmitkDataSet * ds, const gchar * new_date); void amitk_data_set_set_subject_name (AmitkDataSet * ds, const gchar * new_name); void amitk_data_set_set_subject_id (AmitkDataSet * ds, const gchar * new_id); void amitk_data_set_set_subject_dob (AmitkDataSet * ds, const gchar * new_dob); void amitk_data_set_set_series_number (AmitkDataSet * ds, const gint new_series_number); void amitk_data_set_set_dicom_image_type(AmitkDataSet * ds, const gchar * image_type); void amitk_data_set_set_conversion (AmitkDataSet * ds, AmitkConversion new_conversion); void amitk_data_set_set_scale_factor (AmitkDataSet * ds, amide_data_t new_scale_factor); void amitk_data_set_set_injected_dose (AmitkDataSet * ds, amide_data_t new_injected_dose); void amitk_data_set_set_subject_weight (AmitkDataSet * ds, amide_data_t new_subject_weight); void amitk_data_set_set_cylinder_factor(AmitkDataSet * ds, amide_data_t new_cylinder_factor); void amitk_data_set_set_displayed_dose_unit (AmitkDataSet * ds, AmitkDoseUnit new_dose_unit); void amitk_data_set_set_displayed_weight_unit (AmitkDataSet * ds, AmitkWeightUnit new_weight_unit); void amitk_data_set_set_displayed_cylinder_unit(AmitkDataSet * ds, AmitkCylinderUnit new_cylinder_unit); void amitk_data_set_set_inversion_time (AmitkDataSet * ds, amide_time_t new_inversion_time); void amitk_data_set_set_echo_time (AmitkDataSet * ds, amide_time_t new_echo_time); void amitk_data_set_set_diffusion_b_value(AmitkDataSet * ds, gdouble b_value); void amitk_data_set_set_diffusion_direction(AmitkDataSet * ds, AmitkPoint direction); void amitk_data_set_set_threshold_window (AmitkDataSet * ds, const AmitkWindow window, const AmitkLimit limit, const amide_data_t value); void amitk_data_set_set_view_start_gate(AmitkDataSet * ds, amide_intpoint_t start_gate); void amitk_data_set_set_view_end_gate (AmitkDataSet * ds, amide_intpoint_t end_gate); void amitk_data_set_set_gate_time (AmitkDataSet * ds, const guint gate, amide_time_t time); amide_time_t amitk_data_set_get_gate_time (const AmitkDataSet * ds, const guint gate); amide_time_t amitk_data_set_get_start_time (const AmitkDataSet * ds, const guint frame); amide_time_t amitk_data_set_get_end_time (const AmitkDataSet * ds, const guint frame); amide_time_t amitk_data_set_get_midpt_time (const AmitkDataSet *ds, const guint frame); guint amitk_data_set_get_frame (const AmitkDataSet * ds, const amide_time_t time); amide_time_t amitk_data_set_get_frame_duration (const AmitkDataSet * ds, guint frame); amide_time_t amitk_data_set_get_min_frame_duration (const AmitkDataSet * ds); void amitk_data_set_calc_far_corner (AmitkDataSet * ds); /* note: calling any of the get_*_max or get_*_min functions will automatically call calc_min_max if needed. The main reason to call this function independently is if you know the min/max values will be needed later, and you'd like to put up a progress dialog. */ void amitk_data_set_calc_min_max (AmitkDataSet * ds, AmitkUpdateFunc update_func, gpointer update_data); void amitk_data_set_calc_min_max_if_needed(AmitkDataSet * ds, AmitkUpdateFunc update_func, gpointer update_data); void amitk_data_set_slice_calc_min_max (AmitkDataSet * ds, const amide_intpoint_t frame, const amide_intpoint_t gate, const amide_intpoint_t z, amitk_format_DOUBLE_t * pmin, amitk_format_DOUBLE_t * pmax); amide_data_t amitk_data_set_get_max (AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration); amide_data_t amitk_data_set_get_min (AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration); void amitk_data_set_get_thresholding_min_max(AmitkDataSet * ds, AmitkDataSet * slice, const amide_time_t start, const amide_time_t duration, amide_data_t * min, amide_data_t * max); void amitk_data_set_calc_distribution (AmitkDataSet * ds, AmitkUpdateFunc update_func, gpointer update_data); amide_data_t amitk_data_set_get_internal_value (const AmitkDataSet * ds, const AmitkVoxel i); amide_data_t amitk_data_set_get_value (const AmitkDataSet * ds, const AmitkVoxel i); amide_data_t amitk_data_set_get_internal_scaling_factor(const AmitkDataSet * ds, const AmitkVoxel i); amide_data_t amitk_data_set_get_scaling_factor (const AmitkDataSet * ds, const AmitkVoxel i); amide_data_t amitk_data_set_get_scaling_intercept(const AmitkDataSet * ds, const AmitkVoxel i); void amitk_data_set_set_value (AmitkDataSet *ds, const AmitkVoxel i, const amide_data_t value, const gboolean signal_change); void amitk_data_set_set_internal_value (AmitkDataSet *ds, const AmitkVoxel i, const amide_data_t internal_value, const gboolean signal_change); void amitk_data_set_get_projections (AmitkDataSet * ds, const guint frame, const guint gate, AmitkDataSet ** projections, AmitkUpdateFunc update_func, gpointer update_data); AmitkDataSet * amitk_data_set_get_cropped (const AmitkDataSet * ds, const AmitkVoxel start, const AmitkVoxel end, const AmitkFormat format, const AmitkScalingType scaling_type, AmitkUpdateFunc update_func, gpointer update_data); AmitkDataSet * amitk_data_set_get_filtered (const AmitkDataSet * ds, const AmitkFilter filter_type, const gint kernel_size, const amide_real_t fwhm, AmitkUpdateFunc update_func, gpointer update_data); AmitkDataSet * amitk_data_set_get_slice (AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * slice_volume); void amitk_data_set_get_line_profile (AmitkDataSet * ds, const amide_time_t start, const amide_time_t duration, const AmitkPoint start_point, const AmitkPoint end_point, GPtrArray ** preturn_data); gint amitk_data_sets_count (GList * objects, gboolean recurse); amide_time_t amitk_data_sets_get_min_frame_duration(GList * objects); amide_real_t amitk_data_sets_get_min_voxel_size (GList * objects); amide_real_t amitk_data_sets_get_max_min_voxel_size(GList * objects); GList * amitk_data_sets_get_slices (GList * objects, GList ** pslice_cache, const gint max_slice_cache_size, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * view_volume); AmitkDataSet * amitk_data_sets_find_with_slice_parent(GList * slices, const AmitkDataSet * slice_parent); GList * amitk_data_sets_remove_with_slice_parent(GList * slices, const AmitkDataSet * slice_parent); AmitkDataSet * amitk_data_sets_math_unary (AmitkDataSet * ds1, AmitkOperationUnary operation, amide_data_t parameter0, amide_data_t parameter1, AmitkUpdateFunc update_func, gpointer update_data); AmitkDataSet * amitk_data_sets_math_binary (AmitkDataSet * ds1, AmitkDataSet * ds2, AmitkOperationBinary operation, amide_data_t parameter0, amide_data_t parameter1, gboolean by_frame, gboolean maintain_ds1_dim, AmitkUpdateFunc update_func, gpointer update_data); /* -------- defines ----------- */ #define amitk_data_set_get_gate_time_mem(ds) (g_try_new0(amide_time_t,(ds)->raw_data->dim.g)) #define amitk_data_set_get_frame_duration_mem(ds) (g_try_new0(amide_time_t,(ds)->raw_data->dim.t)) #define amitk_data_set_get_frame_min_max_mem(ds) (g_try_new0(amide_data_t,(ds)->raw_data->dim.t)) const gchar * amitk_scaling_type_get_name (const AmitkScalingType scaling_type); const gchar * amitk_operation_unary_get_name (const AmitkOperationUnary operation); const gchar * amitk_operation_binary_get_name (const AmitkOperationBinary operation); const gchar * amitk_interpolation_get_name (const AmitkInterpolation interpolation); const gchar * amitk_rendering_get_name (const AmitkRendering rendering); const gchar * amitk_subject_orientation_get_name(const AmitkSubjectOrientation subject_orientation); const gchar * amitk_subject_sex_get_name (const AmitkSubjectSex subject_sex); const gchar * amitk_thresholding_get_name (const AmitkThresholding thresholding); const gchar * amitk_threshold_style_get_name (const AmitkThresholdStyle threshold_style); const gchar * amitk_conversion_get_name (const AmitkConversion conversion); const gchar * amitk_weight_unit_get_name (const AmitkWeightUnit weight_unit); const gchar * amitk_dose_unit_get_name (const AmitkDoseUnit dose_unit); const gchar * amitk_cylinder_unit_get_name (const AmitkCylinderUnit cylinder_unit); amide_data_t amitk_weight_unit_convert_to (const amide_data_t kg, const AmitkWeightUnit weight_unit); amide_data_t amitk_weight_unit_convert_from (const amide_data_t weight, const AmitkWeightUnit weight_unit); amide_data_t amitk_dose_unit_convert_to (const amide_data_t MBq, const AmitkDoseUnit dose_unit); amide_data_t amitk_dose_unit_convert_from (const amide_data_t dose, const AmitkDoseUnit dose_unit); amide_data_t amitk_cylinder_unit_convert_to (const amide_data_t MBq_cc_image_units, const AmitkCylinderUnit cylinder_unit); amide_data_t amitk_cylinder_unit_convert_from (const amide_data_t cylinder_factor, const AmitkCylinderUnit cylinder_unit); /* external variables */ extern AmitkColorTable amitk_modality_default_color_table[]; extern const gchar * amitk_interpolation_explanations[]; extern const gchar * amitk_rendering_explanation; extern const gchar * amitk_import_menu_names[]; extern const gchar * amitk_import_menu_explanations[]; extern const gchar * amitk_export_menu_names[]; extern const gchar * amitk_export_menu_explanations[]; extern const gchar * amitk_conversion_names[]; extern const gchar * amitk_dose_unit_names[]; extern const gchar * amitk_weight_unit_names[]; extern const gchar * amitk_cylinder_unit_names[]; extern const gchar * amitk_scaling_menu_names[]; extern amide_data_t amitk_window_default[AMITK_WINDOW_NUM][AMITK_LIMIT_NUM]; G_END_DECLS #endif /* __AMITK_DATA_SET_H__ */ amide-1.0.6/amide-current/src/amitk_data_set_variable_type.c000066400000000000000000000673411423227705100241640ustar00rootroot00000000000000/* amitk_data_set_variable_type.c - used to generate the different amitk_data_set_*.c files * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'.h" #include "amitk_data_set_FLOAT_0D_SCALING.h" #ifdef AMIDE_DEBUG #include #endif #define DIM_TYPE_`'m4_Scale_Dim`' #define DATA_TYPE_`'m4_Variable_Type`' /* function to calculate the max/min values of a slice within a data set */ void amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'calc_slice_min_max(AmitkDataSet * data_set, const amide_intpoint_t frame, const amide_intpoint_t gate, const amide_intpoint_t z, amitk_format_DOUBLE_t * pmin, amitk_format_DOUBLE_t * pmax) { AmitkVoxel i; amide_data_t max, min, temp; AmitkVoxel dim; dim = AMITK_DATA_SET_DIM(data_set); i.t = frame; i.g = gate; i.z = z; i.y = i.x = 0; temp = AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set, i); if (finite(temp)) max = min = temp; else max = min = 0.0; /* just throw in zero */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { temp = AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set, i); if (finite(temp)) { if (temp > max) max = temp; else if (temp < min) min = temp; } } if (pmin != NULL) *pmin = min; if (pmax != NULL) *pmax = max; return; } /* generate the distribution array for a data_set */ void amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'calc_distribution(AmitkDataSet * data_set, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel i,j; amide_data_t scale, diff; AmitkVoxel distribution_dim; AmitkVoxel data_set_dim; gchar * temp_string; div_t x; gint divider; gint total_planes; gint i_plane; gboolean continue_work=TRUE; AmitkRawData * distribution; if (data_set->distribution != NULL) return; data_set_dim = AMITK_DATA_SET_DIM(data_set); diff = amitk_data_set_get_global_max(data_set) - amitk_data_set_get_global_min(data_set); if (diff == 0.0) scale = 0.0; else scale = (AMITK_DATA_SET_DISTRIBUTION_SIZE-1)/diff; distribution_dim.x = AMITK_DATA_SET_DISTRIBUTION_SIZE; distribution_dim.y = distribution_dim.z = distribution_dim.g = distribution_dim.t = 1; distribution = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, distribution_dim); if (distribution == NULL) { g_warning(_("couldn't allocate memory space for the data set structure to hold distribution data")); return; } /* initialize the distribution array */ amitk_raw_data_DOUBLE_initialize_data(distribution, 0.0); if (update_func != NULL) { temp_string = g_strdup_printf(_("Generating distribution data for:\n %s"), AMITK_OBJECT_NAME(data_set)); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = AMITK_DATA_SET_TOTAL_PLANES(data_set); divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); /* now "bin" the data */ j = zero_voxel; i_plane=0; for (i.t = 0; (i.t < data_set_dim.t) && continue_work; i.t++) { for (i.g = 0; (i.g < data_set_dim.g) && continue_work; i.g++) { for ( i.z = 0; (i.z < data_set_dim.z) && continue_work; i.z++, i_plane++) { if (update_func != NULL) { x = div(i_plane,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) i_plane)/((gdouble) total_planes)); } for (i.y = 0; i.y < data_set_dim.y; i.y++) for (i.x = 0; i.x < data_set_dim.x; i.x++) { j.x = scale*(AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set,i)-amitk_data_set_get_global_min(data_set)); AMITK_RAW_DATA_DOUBLE_SET_CONTENT(distribution,j) += 1.0; } } } } if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); if (!continue_work) { /* if we quit, get out of here */ g_object_unref(distribution); return; } /* do some log scaling so the distribution is more meaningful, and doesn't get swamped by outlyers */ for (j.x = 0; j.x < distribution_dim.x ; j.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(distribution,j) = log10(AMITK_RAW_DATA_DOUBLE_CONTENT(distribution,j)+1.0); /* and store the distribution with the data set */ data_set->distribution = distribution; return; } /* returns a slice with the appropriate data from the data_set */ AmitkDataSet * amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'get_slice(AmitkDataSet * data_set, const amide_time_t start_time, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * slice_volume) { /* zp_start, where on the zp axis to start the slice, zp (z_prime) corresponds to the rotated axises, if negative, choose the midpoint */ AmitkDataSet * slice = NULL; AmitkVoxel i_voxel; amide_intpoint_t z; amide_real_t max_diff, voxel_length, z_steps; AmitkPoint alt; AmitkPoint stride[AMITK_AXIS_NUM], last[AMITK_AXIS_NUM]; AmitkAxis i_axis; guint k, l; amide_data_t weight; amide_data_t time_weight; amide_intpoint_t start_frame, end_frame; amide_intpoint_t i_gate; amide_time_t end_time; AmitkPoint box_point[8]; AmitkVoxel box_voxel[8]; AmitkVoxel start, end; amide_data_t box_value[8]; AmitkPoint slice_point, ds_point,start_point,diff, nearest_point; AmitkSpace * slice_space; AmitkSpace * data_set_space; #if AMIDE_DEBUG gchar * temp_string; AmitkPoint center_point; #endif AmitkVoxel ds_voxel; amide_data_t weight1, weight2; amide_data_t * weights=NULL; amide_data_t * intermediate_data=NULL; AmitkCorners intersection_corners; AmitkVoxel dim; gint num_gates; gboolean empties=FALSE; /* ----- figure out what frames of this data set to include ----*/ end_time = start_time+duration; start_frame = amitk_data_set_get_frame(data_set, start_time+EPSILON); end_frame = amitk_data_set_get_frame(data_set, end_time-EPSILON); /* the number of gates we'll be looking at */ if (gate < 0) num_gates = AMITK_DATA_SET_NUM_VIEW_GATES(data_set); else num_gates = 1; /* ------------------------- */ dim.x = ceil(fabs(AMITK_VOLUME_X_CORNER(slice_volume))/pixel_size.x); dim.y = ceil(fabs(AMITK_VOLUME_Y_CORNER(slice_volume))/pixel_size.y); dim.z = dim.g = dim.t = 1; /* if we need it, get the weighting matrix */ if (data_set->rendering == AMITK_RENDERING_MPR) { if ((weights = g_try_malloc0(sizeof(amide_data_t)*dim.x*dim.y)) == NULL) { g_warning(_("couldn't allocate memory space for the weights, wanted %dx%d elements"), dim.x, dim.y); goto error; } } /* get an intermediate data matrix to speed things up */ if ((intermediate_data = g_try_malloc0(sizeof(amide_data_t)*dim.x*dim.y)) == NULL) { g_warning(_("couldn't allocate memory space for the intermediate_data, wanted %dx%d elements"), dim.x, dim.y); goto error; } /* get the return slice */ slice = amitk_data_set_new_with_data(NULL, AMITK_DATA_SET_MODALITY(data_set), AMITK_FORMAT_DOUBLE, dim, AMITK_SCALING_TYPE_0D); if (slice == NULL) { g_warning(_("couldn't allocate memory space for the slice, wanted %dx%dx%d elements"), dim.x, dim.y, dim.z); goto error; } slice->slice_parent = data_set; g_object_add_weak_pointer(G_OBJECT(data_set), (gpointer *) &(slice->slice_parent)); slice->voxel_size.x = pixel_size.x; slice->voxel_size.y = pixel_size.y; slice->voxel_size.z = AMITK_VOLUME_Z_CORNER(slice_volume); amitk_space_copy_in_place(AMITK_SPACE(slice), AMITK_SPACE(slice_volume)); slice->scan_start = start_time; slice->thresholding = data_set->thresholding; slice->interpolation = AMITK_DATA_SET_INTERPOLATION(data_set); slice->rendering = AMITK_DATA_SET_RENDERING(data_set); if (gate < 0) { slice->view_start_gate = AMITK_DATA_SET_VIEW_START_GATE(data_set); slice->view_end_gate = AMITK_DATA_SET_VIEW_END_GATE(data_set); } else { slice->view_start_gate = gate; slice->view_end_gate = gate; } amitk_data_set_calc_far_corner(slice); amitk_data_set_set_frame_duration(slice, 0, duration); #if AMIDE_DEBUG center_point = amitk_volume_get_center(slice_volume); temp_string = g_strdup_printf("slice from data_set %s: @ x %5.3f y %5.3f z %5.3f", AMITK_OBJECT_NAME(data_set), center_point.x, center_point.y, center_point.z); amitk_object_set_name(AMITK_OBJECT(slice),temp_string); g_free(temp_string); #endif #ifdef AMIDE_DEBUG_COMMENT_OUT { AmitkCorners real_corner; /* convert to real space */ real_corner[0] = AMITK_SPACE_OFFSET(slice); real_corner[1] = amitk_space_s2b(AMITK_SPACE(slice), AMITK_VOLUME_CORNER(slice)); g_print("new slice from data_set %s\t---------------------\n",AMITK_OBJECT_NAME(data_set)); g_print("\tdim\t\tx %d\t\ty %d\t\tz %d\n", dim.x, dim.y, dim.z); g_print("\treal corner[0]\tx %5.4f\ty %5.4f\tz %5.4f\n", real_corner[0].x,real_corner[0].y,real_corner[0].z); g_print("\treal corner[1]\tx %5.4f\ty %5.4f\tz %5.4f\n", real_corner[1].x,real_corner[1].y,real_corner[1].z); g_print("\tdata set\t\tstart\t%5.4f\tend\t%5.3f\tframes %d to %d\n", start_time, end_time,start_frame,end_frame); } #endif /* get direct pointers to the slice's and data set's spaces for efficiency */ slice_space = AMITK_SPACE(slice); data_set_space = AMITK_SPACE(data_set); /* voxel_length is the length of a voxel given the coordinate frame of the slice. this is used to figure out how many iterations in the z direction we need to do */ alt.x = alt.y = 0.0; alt.z = 1.0; alt = amitk_space_s2s_dim(slice_space, data_set_space, alt); alt = point_mult(alt, data_set->voxel_size); voxel_length = POINT_MAGNITUDE(alt); z_steps = slice->voxel_size.z/voxel_length; /* non-integer */ /* figure out the intersection bounds between the data set and the requested slice volume */ if (amitk_volume_volume_intersection_corners(slice_volume, AMITK_VOLUME(data_set), intersection_corners)) { /* translate the intersection into voxel space */ POINT_TO_VOXEL(intersection_corners[0], slice->voxel_size, 0, 0, start); POINT_TO_VOXEL(intersection_corners[1], slice->voxel_size, 0, 0, end); } else { /* no intersection */ start = zero_voxel; end = zero_voxel; } /* make sure we only iterate over the slice we've already malloc'ed */ if (start.x < 0) start.x = 0; if (start.y < 0) start.y = 0; if (end.x >= dim.x) end.x = dim.x-1; if (end.y >= dim.y) end.y = dim.y-1; /* iterate over those voxels that we won't be covering, and mark them as NAN */ i_voxel.t = i_voxel.g = i_voxel.z = 0; for (i_voxel.y = 0; i_voxel.y < start.y; i_voxel.y++) for (i_voxel.x = 0; i_voxel.x < dim.x; i_voxel.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = NAN; for (i_voxel.y = end.y+1; i_voxel.y < dim.y; i_voxel.y++) for (i_voxel.x = 0; i_voxel.x < dim.x; i_voxel.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = NAN; for (i_voxel.x = 0; i_voxel.x < start.x; i_voxel.x++) for (i_voxel.y = 0; i_voxel.y < dim.y; i_voxel.y++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = NAN; for (i_voxel.x = end.x+1; i_voxel.x < dim.x; i_voxel.x++) for (i_voxel.y = 0; i_voxel.y < dim.y; i_voxel.y++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = NAN; switch(data_set->interpolation) { case AMITK_INTERPOLATION_TRILINEAR: /* iterate over the frames we'll be incorporating into this slice */ for (ds_voxel.t = start_frame; ds_voxel.t <= end_frame; ds_voxel.t++) { /* averaging over more then one frame */ if (end_frame-start_frame > 0) { if (ds_voxel.t == start_frame) time_weight = (amitk_data_set_get_end_time(data_set, start_frame)-start_time)/(duration*num_gates); else if (ds_voxel.t == end_frame) time_weight = (end_time-amitk_data_set_get_start_time(data_set, end_frame))/(duration*num_gates); else time_weight = amitk_data_set_get_frame_duration(data_set, ds_voxel.t)/(duration*num_gates); } else time_weight = 1.0/((gdouble) num_gates); for (i_gate=0; i_gate < num_gates; i_gate++) { if (gate < 0) ds_voxel.g = i_gate+AMITK_DATA_SET_VIEW_START_GATE(data_set); else ds_voxel.g = i_gate+gate; if (ds_voxel.g >= AMITK_DATA_SET_NUM_GATES(data_set)) ds_voxel.g -= AMITK_DATA_SET_NUM_GATES(data_set); /* initialize the .t/.g components of box_voxel */ for (l=0; l<8; l=l+1) { box_voxel[l].t = ds_voxel.t; box_voxel[l].g = ds_voxel.g; } /* iterate over the number of planes we'll be compressing into this slice */ for (z = 0; z < ceil(z_steps); z++) { /* the slices z_coordinate for this iteration's slice voxel */ if (ceil(z_steps) > 1.0) slice_point.z = (z+0.5)*voxel_length; else slice_point.z = (0.5)*slice->voxel_size.z; /* only one iteration in z */ /* weight is between 0 and 1, this is used to weight the last voxel in the slice's z direction */ if (floor(z_steps) > z) weight = time_weight/z_steps; else weight = time_weight*(z_steps-floor(z_steps)) / z_steps; /* iterate over the y dimension */ for (i_voxel.y = start.y,k=0; i_voxel.y <= end.y; i_voxel.y++) { /* the slice y_coordinate of the center of this iteration's slice voxel */ slice_point.y = (((amide_real_t) i_voxel.y)+0.5)*slice->voxel_size.y; /* the slice x coord of the center of the first slice voxel in this loop */ slice_point.x = (((amide_real_t) start.x)+0.5)*slice->voxel_size.x; /* iterate over the x dimension */ for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++,k++) { /* translate the current point in slice space into the data set's coordinate frame */ ds_point = amitk_space_s2s(slice_space, data_set_space, slice_point); /* get the nearest neighbor in the data set to this slice voxel */ POINT_TO_VOXEL_COORDS_ONLY(ds_point, data_set->voxel_size, ds_voxel); VOXEL_TO_POINT(ds_voxel, data_set->voxel_size, nearest_point); /* figure out which way to go to get the nearest voxels to our slice voxel*/ POINT_SUB(ds_point, nearest_point, diff); /* figure out which voxels to look at */ for (l=0; l<8; l=l+1) { if (diff.x < 0) box_voxel[l].x = (l & 0x1) ? ds_voxel.x-1 : ds_voxel.x; else /* diff.x >= 0 */ box_voxel[l].x = (l & 0x1) ? ds_voxel.x : ds_voxel.x+1; if (diff.y < 0) box_voxel[l].y = (l & 0x2) ? ds_voxel.y-1 : ds_voxel.y; else /* diff.y >= 0 */ box_voxel[l].y = (l & 0x2) ? ds_voxel.y : ds_voxel.y+1; if (diff.z < 0) box_voxel[l].z = (l & 0x4) ? ds_voxel.z-1 : ds_voxel.z; else /* diff.z >= 0 */ box_voxel[l].z = (l & 0x4) ? ds_voxel.z : ds_voxel.z+1; VOXEL_TO_POINT(box_voxel[l], data_set->voxel_size, box_point[l]); /* get the value of the point on the box */ if (amitk_raw_data_includes_voxel(data_set->raw_data, box_voxel[l])) box_value[l] = AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set, box_voxel[l]); else { box_value[l] = NAN; empties = TRUE; } } if (empties) { /* slow algorithm - checking for empties */ /* reset value */ empties = FALSE; /* do the x direction linear interpolation of the sets of two points */ for (l=0;l<8;l=l+2) { max_diff = box_point[l+1].x-box_point[l].x; weight1 = ((max_diff - (ds_point.x - box_point[l].x))/max_diff); weight2 = ((max_diff - (box_point[l+1].x - ds_point.x))/max_diff); if (isnan(box_value[l])) { if (weight2 >= weight1) box_value[l] = box_value[l+1]; /* else box_value[l] left as is (NAN/empty) */ } else if (isnan(box_value[l+1])) { if (weight1 < weight2) box_value[l] = NAN; /* else box_value[l] left as is */ } else box_value[l] = (box_value[l] * weight1) + (box_value[l+1] * weight2); } /* do the y direction linear interpolation of the sets of two points */ for (l=0;l<8;l=l+4) { max_diff = box_point[l+2].y-box_point[l].y; weight1 = ((max_diff - (ds_point.y - box_point[l].y))/max_diff); weight2 = ((max_diff - (box_point[l+2].y - ds_point.y))/max_diff); if (isnan(box_value[l])) { if (weight2 >= weight1) box_value[l] = box_value[l+2]; /* else box_value[l] left as is (NAN/empty) */ } else if (isnan(box_value[l+2])) { if (weight1 < weight2) box_value[l] = NAN; /* else box_value[l] left as is */ } else box_value[l] = (box_value[l] * weight1) + (box_value[l+2] * weight2); } /* do the z direction linear interpolation of the sets of two points */ for (l=0;l<8;l=l+8) { max_diff = box_point[l+4].z-box_point[l].z; weight1 = ((max_diff - (ds_point.z - box_point[l].z))/max_diff); weight2 = ((max_diff - (box_point[l+4].z - ds_point.z))/max_diff); if (isnan(box_value[l])) { if (weight2 >= weight1) box_value[l] = box_value[l+4]; /* else box_value[l] left as is (NAN/empty) */ } else if (isnan(box_value[l+4])) { if (weight1 < weight2) box_value[l] = NAN; /* else box_value[l] left as is */ } else box_value[l] = (box_value[l] * weight1) + (box_value[l+4] * weight2); } /* separate into MPR/MIP/minIP algorithms */ if (data_set->rendering == AMITK_RENDERING_MPR) { /* MPR */ if (!isnan(box_value[0])) { intermediate_data[k] += weight*box_value[0]; weights[k] += weight; } } else { /* MIP or MINIP */ if ((z == 0) && (ds_voxel.t == start_frame) && (i_gate == 0)) intermediate_data[k]=box_value[0]; else if (data_set->rendering == AMITK_RENDERING_MIP) /* MIP */ intermediate_data[k] = MAX(box_value[0], intermediate_data[k]); else /* MINIP */ intermediate_data[k] = MIN(box_value[0], intermediate_data[k]); } } else { /* faster */ /* do the x direction linear interpolation of the sets of two points */ for (l=0;l<8;l=l+2) { max_diff = box_point[l+1].x-box_point[l].x; weight1 = ((max_diff - (ds_point.x - box_point[l].x))/max_diff); weight2 = ((max_diff - (box_point[l+1].x - ds_point.x))/max_diff); box_value[l] = (box_value[l] * weight1) + (box_value[l+1] * weight2); } /* do the y direction linear interpolation of the sets of two points */ for (l=0;l<8;l=l+4) { max_diff = box_point[l+2].y-box_point[l].y; weight1 = ((max_diff - (ds_point.y - box_point[l].y))/max_diff); weight2 = ((max_diff - (box_point[l+2].y - ds_point.y))/max_diff); box_value[l] = (box_value[l] * weight1) + (box_value[l+2] * weight2); } /* do the z direction linear interpolation of the sets of two points */ for (l=0;l<8;l=l+8) { max_diff = box_point[l+4].z-box_point[l].z; weight1 = ((max_diff - (ds_point.z - box_point[l].z))/max_diff); weight2 = ((max_diff - (box_point[l+4].z - ds_point.z))/max_diff); box_value[l] = (box_value[l] * weight1) + (box_value[l+4] * weight2); } /* separate into MPR/MIP/minIP algorithms */ if (data_set->rendering == AMITK_RENDERING_MPR) { /* MPR */ intermediate_data[k] += weight*box_value[0]; weights[k] += weight; } else { /* MIP or MINIP */ if ((z == 0) && (ds_voxel.t == start_frame) && (i_gate == 0)) intermediate_data[k]=box_value[0]; else if (data_set->rendering == AMITK_RENDERING_MIP) /* MIP */ intermediate_data[k] = MAX(intermediate_data[k], box_value[0]); else /* MINIP */ intermediate_data[k] = MIN(intermediate_data[k], box_value[0]); } } /* slow (empties) vs fast algorithm */ slice_point.x += slice->voxel_size.x; } } } } } break; case AMITK_INTERPOLATION_NEAREST_NEIGHBOR: default: /* figure out what point in the data set we're going to start at */ start_point.x = ((amide_real_t) start.x+0.5) * slice->voxel_size.x; start_point.y = ((amide_real_t) start.y+0.5) * slice->voxel_size.y; if (ceil(z_steps) > 1.0) start_point.z = voxel_length/2.0; else start_point.z = slice->voxel_size.z/2.0; /* only one iteration in z */ start_point = amitk_space_s2s(slice_space, data_set_space, start_point); /* figure out what stepping one voxel in a given direction in our slice cooresponds to in our data set */ for (i_axis = 0; i_axis < AMITK_AXIS_NUM; i_axis++) { alt.x = (i_axis == AMITK_AXIS_X) ? slice->voxel_size.x : 0.0; alt.y = (i_axis == AMITK_AXIS_Y) ? slice->voxel_size.y : 0.0; alt.z = (i_axis == AMITK_AXIS_Z) ? voxel_length : 0.0; alt = point_add(point_sub(amitk_space_s2b(slice_space, alt), AMITK_SPACE_OFFSET(slice_space)), AMITK_SPACE_OFFSET(data_set_space)); stride[i_axis] = amitk_space_b2s(data_set_space, alt); } /* iterate over the number of frames we'll be incorporating into this slice */ for (ds_voxel.t = start_frame; ds_voxel.t <= end_frame; ds_voxel.t++) { /* averaging over more then one frame */ if (end_frame-start_frame > 0) { if (ds_voxel.t == start_frame) time_weight = (amitk_data_set_get_end_time(data_set, start_frame)-start_time)/(duration*num_gates); else if (ds_voxel.t == end_frame) time_weight = (end_time-amitk_data_set_get_start_time(data_set, end_frame))/(duration*num_gates); else time_weight = amitk_data_set_get_frame_duration(data_set, ds_voxel.t)/(duration*num_gates); } else time_weight = 1.0/((gdouble) num_gates); /* iterate over gates */ for (i_gate=0; i_gate < num_gates; i_gate++) { if (gate < 0) ds_voxel.g = i_gate+AMITK_DATA_SET_VIEW_START_GATE(data_set); else ds_voxel.g = i_gate+gate; if (ds_voxel.g >= AMITK_DATA_SET_NUM_GATES(data_set)) ds_voxel.g -= AMITK_DATA_SET_NUM_GATES(data_set); ds_point = start_point; /* separate into MPR and MIP/MINIP algorithms. A fair amount of code is duplicated within the algorithms. The reason they aren't combined is to keep the MPR vs MIP/MINIP branch point out of the loop and speed things up slightly for the most commonly used selection (MPR) */ switch(data_set->rendering) { case AMITK_RENDERING_MPR: /* iterate over the number of planes we'll be compressing into this slice */ for (z = 0; z < ceil(z_steps); z++) { last[AMITK_AXIS_Z] = ds_point; /* weight is between 0 and 1, this is used to weight the last voxel in the slice's z direction */ if (floor(z_steps) > z) weight = time_weight/z_steps; else weight = time_weight*(z_steps-floor(z_steps)) / z_steps; /* iterate over x and y */ for (i_voxel.y = start.y, k=0; i_voxel.y <= end.y; i_voxel.y++) { last[AMITK_AXIS_Y] = ds_point; for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++, k++) { POINT_TO_VOXEL_COORDS_ONLY(ds_point, data_set->voxel_size, ds_voxel); if (amitk_raw_data_includes_voxel(data_set->raw_data,ds_voxel)) { intermediate_data[k] += weight*AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set,ds_voxel); weights[k] += weight; } POINT_ADD(ds_point, stride[AMITK_AXIS_X], ds_point); } /* x */ POINT_ADD(last[AMITK_AXIS_Y], stride[AMITK_AXIS_Y], ds_point); } /* y */ POINT_ADD(last[AMITK_AXIS_Z], stride[AMITK_AXIS_Z], ds_point); } /* z */ break; case AMITK_RENDERING_MIP: case AMITK_RENDERING_MINIP: /* iterate over the number of planes we'll be compressing into this slice */ for (z = 0; z < ceil(z_steps); z++) { last[AMITK_AXIS_Z] = ds_point; /* need to initialize based on the first plane we encounter */ if ((z == 0) && (ds_voxel.t == start_frame) && (i_gate == 0)) { /* iterate over x and y */ for (i_voxel.y = start.y,k=0; i_voxel.y <= end.y; i_voxel.y++) { last[AMITK_AXIS_Y] = ds_point; for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++,k++) { POINT_TO_VOXEL_COORDS_ONLY(ds_point, data_set->voxel_size, ds_voxel); if (!amitk_raw_data_includes_voxel(data_set->raw_data,ds_voxel)) intermediate_data[k] = NAN; else intermediate_data[k] = AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set,ds_voxel); POINT_ADD(ds_point, stride[AMITK_AXIS_X], ds_point); } /* x */ POINT_ADD(last[AMITK_AXIS_Y], stride[AMITK_AXIS_Y], ds_point); } /* y */ } else { /* iterate over everything that's not the first plane */ if (data_set->rendering == AMITK_RENDERING_MIP) { /* iterate over x and y */ for (i_voxel.y = start.y,k=0; i_voxel.y <= end.y; i_voxel.y++) { last[AMITK_AXIS_Y] = ds_point; for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++,k++) { POINT_TO_VOXEL_COORDS_ONLY(ds_point, data_set->voxel_size, ds_voxel); if (amitk_raw_data_includes_voxel(data_set->raw_data,ds_voxel)) intermediate_data[k] = MAX(intermediate_data[k], AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set,ds_voxel)); POINT_ADD(ds_point, stride[AMITK_AXIS_X], ds_point); } /* x */ POINT_ADD(last[AMITK_AXIS_Y], stride[AMITK_AXIS_Y], ds_point); } /* y */ } else { /* AMITK_RENDERING_MINIP */ /* iterate over x and y */ for (i_voxel.y = start.y,k=0; i_voxel.y <= end.y; i_voxel.y++) { last[AMITK_AXIS_Y] = ds_point; for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++,k++) { POINT_TO_VOXEL_COORDS_ONLY(ds_point, data_set->voxel_size, ds_voxel); if (amitk_raw_data_includes_voxel(data_set->raw_data,ds_voxel)) intermediate_data[k] = MIN(intermediate_data[k], AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_`'m4_Intercept`'CONTENT(data_set,ds_voxel)); POINT_ADD(ds_point, stride[AMITK_AXIS_X], ds_point); } /* x */ POINT_ADD(last[AMITK_AXIS_Y], stride[AMITK_AXIS_Y], ds_point); } /* y */ } /* end else, MIP vs MINIP */ } /* end else */ POINT_ADD(last[AMITK_AXIS_Z], stride[AMITK_AXIS_Z], ds_point); } /* z */ break; default: break; } /* MIP vs NON-MIP */ } /* iterating over gates */ } /* iterating over frames */ break; } /* fill in data/normalize if needed */ i_voxel.t = i_voxel.g = i_voxel.z = 0; if (data_set->rendering == AMITK_RENDERING_MPR) { for (i_voxel.y = start.y,k=0; i_voxel.y <= end.y; i_voxel.y++) for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++,k++) if (weights[k] > 0) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = intermediate_data[k]/weights[k]; else AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = NAN; } else { /* MIP or MINIP */ for (i_voxel.y = start.y,k=0; i_voxel.y <= end.y; i_voxel.y++) for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++,k++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(slice->raw_data,i_voxel) = intermediate_data[k]; } error: if (weights != NULL) g_free(weights); if (intermediate_data != NULL) g_free(intermediate_data); return slice; } amide-1.0.6/amide-current/src/amitk_data_set_variable_type.h000066400000000000000000000132521423227705100241610ustar00rootroot00000000000000/* amitk_data_set_variable_type.h - used to generate the different amitk_data_set_*.h files * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'__ #define __AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'__ /* header files that are always needed with this file */ #include "amitk_data_set.h" /* defines */ /* translates to the contents of the voxel specified by voxelpoint i */ #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_CONTENT(data_set,i) \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->current_scaling_factor, (i))) * \ ((amide_data_t) (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER((data_set)->raw_data,(i)))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_CONTENT(data_set,i) \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->current_scaling_factor, (i))) * \ ((amide_data_t) (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER((data_set)->raw_data,(i)))) + \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_intercept, (i)))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERNAL_CONTENT(data_set,i) \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_factor, (i))) * \ ((amide_data_t) (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER((data_set)->raw_data,(i)))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_INTERNAL_CONTENT(data_set,i) \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_factor, (i))) * \ ((amide_data_t) (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER((data_set)->raw_data,(i)))) + \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_intercept, (i)))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_SET_CONTENT(data_set,i,value) \ (AMITK_RAW_DATA_`'m4_Variable_Type`'_SET_CONTENT((data_set)->raw_data, (i)) = value/ \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->current_scaling_factor, (i))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_SET_CONTENT(data_set,i,value) \ (AMITK_RAW_DATA_`'m4_Variable_Type`'_SET_CONTENT((data_set)->raw_data, (i)) = value/ \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->current_scaling_factor, (i)))) \ - (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_intercept, (i))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_SET_INTERNAL_CONTENT(data_set,i,value) \ (AMITK_RAW_DATA_`'m4_Variable_Type`'_SET_CONTENT((data_set)->raw_data, (i)) = value/ \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_factor, (i))))) #define AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_SET_INTERNAL_CONTENT(data_set,i,value) \ (AMITK_RAW_DATA_`'m4_Variable_Type`'_SET_CONTENT((data_set)->raw_data, (i)) = value/ \ (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_factor, (i)))) \ - (*(AMITK_RAW_DATA_DOUBLE_`'m4_Scale_Dim`'_POINTER((data_set)->internal_scaling_intercept, (i))))) /* function declarations */ void amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_calc_slice_min_max(AmitkDataSet * data_set, const amide_intpoint_t frame, const amide_intpoint_t gate, const amide_intpoint_t z, amitk_format_DOUBLE_t * pmin, amitk_format_DOUBLE_t * pmax); void amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_calc_slice_min_max(AmitkDataSet * data_set, const amide_intpoint_t frame, const amide_intpoint_t gate, const amide_intpoint_t z, amitk_format_DOUBLE_t * pmin, amitk_format_DOUBLE_t * pmax); void amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_calc_distribution(AmitkDataSet * data_set, AmitkUpdateFunc update_func, gpointer update_data); void amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_calc_distribution(AmitkDataSet * data_set, AmitkUpdateFunc update_func, gpointer update_data); AmitkDataSet * amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_get_slice(AmitkDataSet * data_set, const amide_time_t start_time, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * slice_volume); AmitkDataSet * amitk_data_set_`'m4_Variable_Type`'_`'m4_Scale_Dim`'_INTERCEPT_get_slice(AmitkDataSet * data_set, const amide_time_t start_time, const amide_time_t duration, const amide_intpoint_t gate, const AmitkCanvasPoint pixel_size, const AmitkVolume * slice_volume); #endif /* __AMITK_DATA_SET_`'m4_Variable_Type`'_`'m4_Scale_Dim`'__ */ amide-1.0.6/amide-current/src/amitk_dial.c000066400000000000000000000361701423227705100203770ustar00rootroot00000000000000/* amitk_dial.c, adapated from gtkdial.c */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include "amitk_dial.h" #define SCROLL_DELAY_LENGTH 300 #define DIAL_DEFAULT_SIZE 100 /* Forward declarations */ static void amitk_dial_class_init (AmitkDialClass *klass); static void amitk_dial_init (AmitkDial *dial); static void amitk_dial_destroy (GtkObject *object); static void amitk_dial_realize (GtkWidget *widget); static void amitk_dial_size_request (GtkWidget *widget, GtkRequisition *requisition); static void amitk_dial_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint amitk_dial_expose (GtkWidget *widget, GdkEventExpose *event); static gint amitk_dial_button_press (GtkWidget *widget, GdkEventButton *event); static gint amitk_dial_button_release (GtkWidget *widget, GdkEventButton *event); static gint amitk_dial_motion_notify (GtkWidget *widget, GdkEventMotion *event); static gint amitk_dial_timer (AmitkDial *dial); static void amitk_dial_update_mouse (AmitkDial *dial, gint x, gint y); static void amitk_dial_update (AmitkDial *dial); static void amitk_dial_adjustment_changed (GtkAdjustment *adjustment, gpointer data); static void amitk_dial_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data); /* Local data */ static GtkWidgetClass *parent_class = NULL; GType amitk_dial_get_type () { static GType dial_type = 0; if (!dial_type) { static const GTypeInfo dial_info = { sizeof (AmitkDialClass), NULL, NULL, (GClassInitFunc) amitk_dial_class_init, NULL, NULL, sizeof (AmitkDial), 0, (GInstanceInitFunc) amitk_dial_init, }; dial_type = g_type_register_static (GTK_TYPE_WIDGET, "AmitkDial", &dial_info, 0); } return dial_type; } static void amitk_dial_class_init (AmitkDialClass *class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; parent_class = g_type_class_peek_parent (class); object_class->destroy = amitk_dial_destroy; widget_class->realize = amitk_dial_realize; widget_class->expose_event = amitk_dial_expose; widget_class->size_request = amitk_dial_size_request; widget_class->size_allocate = amitk_dial_size_allocate; widget_class->button_press_event = amitk_dial_button_press; widget_class->button_release_event = amitk_dial_button_release; widget_class->motion_notify_event = amitk_dial_motion_notify; } static void amitk_dial_init (AmitkDial *dial) { dial->button = 0; dial->policy = GTK_UPDATE_CONTINUOUS; dial->timer = 0; dial->radius = 0; dial->pointer_width = 0; dial->angle = 0.0; dial->old_value = 0.0; dial->old_lower = 0.0; dial->old_upper = 0.0; dial->adjustment = NULL; } GtkWidget* amitk_dial_new (GtkAdjustment *adjustment) { AmitkDial *dial; dial = g_object_new (amitk_dial_get_type (), NULL); if (!adjustment) adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); amitk_dial_set_adjustment (dial, adjustment); return GTK_WIDGET (dial); } static void amitk_dial_destroy (GtkObject *object) { AmitkDial *dial; g_return_if_fail (object != NULL); g_return_if_fail (AMITK_IS_DIAL (object)); dial = AMITK_DIAL (object); if (dial->adjustment) { g_object_unref (G_OBJECT (dial->adjustment)); dial->adjustment = NULL; } (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } GtkAdjustment* amitk_dial_get_adjustment (AmitkDial *dial) { g_return_val_if_fail (dial != NULL, NULL); g_return_val_if_fail (AMITK_IS_DIAL (dial), NULL); return dial->adjustment; } void amitk_dial_set_update_policy (AmitkDial *dial, GtkUpdateType policy) { g_return_if_fail (dial != NULL); g_return_if_fail (AMITK_IS_DIAL (dial)); dial->policy = policy; } void amitk_dial_set_adjustment (AmitkDial *dial, GtkAdjustment *adjustment) { g_return_if_fail (dial != NULL); g_return_if_fail (AMITK_IS_DIAL (dial)); if (dial->adjustment) { g_signal_handlers_disconnect_by_func (G_OBJECT (dial->adjustment), NULL, (gpointer) dial); g_object_unref (G_OBJECT (dial->adjustment)); } dial->adjustment = adjustment; g_object_ref (G_OBJECT (dial->adjustment)); g_signal_connect (G_OBJECT (adjustment), "changed", G_CALLBACK (amitk_dial_adjustment_changed), (gpointer) dial); g_signal_connect (G_OBJECT (adjustment), "value_changed", G_CALLBACK (amitk_dial_adjustment_value_changed), (gpointer) dial); dial->old_value = adjustment->value; dial->old_lower = adjustment->lower; dial->old_upper = adjustment->upper; amitk_dial_update (dial); } static void amitk_dial_realize (GtkWidget *widget) { /* AmitkDial *dial; */ GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (AMITK_IS_DIAL (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); /* dial = AMITK_DIAL (widget); */ attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_user_data (widget->window, widget); gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); } static void amitk_dial_size_request (GtkWidget *widget, GtkRequisition *requisition) { requisition->width = DIAL_DEFAULT_SIZE; requisition->height = DIAL_DEFAULT_SIZE; } static void amitk_dial_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { AmitkDial *dial; g_return_if_fail (widget != NULL); g_return_if_fail (AMITK_IS_DIAL (widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; dial = AMITK_DIAL (widget); if (GTK_WIDGET_REALIZED (widget)) { gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); } dial->radius = MIN (allocation->width, allocation->height) * 0.45; dial->pointer_width = dial->radius / 2; } static gint amitk_dial_expose (GtkWidget *widget, GdkEventExpose *event) { AmitkDial *dial; GdkPoint points[6]; gdouble s,c; gint xc, yc; /* gint upper, lower; */ g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (AMITK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (event->count > 0) return FALSE; dial = AMITK_DIAL (widget); /* gdk_window_clear_area (widget->window, 0, 0, widget->allocation.width, widget->allocation.height); */ xc = widget->allocation.width / 2; yc = widget->allocation.height / 2; /* upper = dial->adjustment->upper; */ /* lower = dial->adjustment->lower; */ /* draw circle */ gdk_draw_arc(widget->window, widget->style->fg_gc[widget->state], FALSE, xc - dial->radius, yc - dial->radius, 2*dial->radius, 2*dial->radius, 0, 23040); /* draw circle */ gdk_draw_arc(widget->window, widget->style->fg_gc[widget->state], FALSE, xc - 0.90*dial->radius, yc - 0.90*dial->radius, 1.8*dial->radius, 1.8*dial->radius, 0, 23040); /* Draw pointer */ s = sin (dial->angle); c = cos (dial->angle); dial->last_angle = dial->angle; points[0].x = xc + 0.9*s*dial->pointer_width/2; points[0].y = yc + 0.9*c*dial->pointer_width/2; points[1].x = xc + 0.9*c*dial->radius; points[1].y = yc - 0.9*s*dial->radius; points[2].x = xc - 0.9*s*dial->pointer_width/2; points[2].y = yc - 0.9*c*dial->pointer_width/2; points[3].x = xc - 0.9*c*dial->radius/10; points[3].y = yc + 0.9*s*dial->radius/10; points[4].x = points[0].x; points[4].y = points[0].y; gtk_paint_polygon (widget->style, widget->window, GTK_STATE_ACTIVE, GTK_SHADOW_IN, NULL, widget, NULL, points, 5, TRUE); return FALSE; } static gint amitk_dial_button_press (GtkWidget *widget, GdkEventButton *event) { AmitkDial *dial; gint dx, dy; double s, c; double d_parallel; double d_perpendicular; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (AMITK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); dial = AMITK_DIAL (widget); /* Determine if button press was within pointer region - we do this by computing the parallel and perpendicular distance of the point where the mouse was pressed from the line passing through the pointer */ dx = event->x - widget->allocation.width / 2; dy = widget->allocation.height / 2 - event->y; s = sin (dial->angle); c = cos (dial->angle); d_parallel = s*dy + c*dx; d_perpendicular = fabs (s*dx - c*dy); if (!dial->button && (d_perpendicular < dial->pointer_width/2) && (d_parallel > - dial->pointer_width)) { gtk_grab_add (widget); dial->button = event->button; amitk_dial_update_mouse (dial, event->x, event->y); } return FALSE; } static gint amitk_dial_button_release (GtkWidget *widget, GdkEventButton *event) { AmitkDial *dial; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (AMITK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); dial = AMITK_DIAL (widget); if (dial->button == event->button) { gtk_grab_remove (widget); dial->button = 0; if (dial->policy == GTK_UPDATE_DELAYED) g_source_remove (dial->timer); if ((dial->policy != GTK_UPDATE_CONTINUOUS) && (dial->old_value != dial->adjustment->value)) g_signal_emit_by_name (G_OBJECT (dial->adjustment), "value_changed"); } return FALSE; } static gint amitk_dial_motion_notify (GtkWidget *widget, GdkEventMotion *event) { AmitkDial *dial; GdkModifierType mods; gint x, y, mask; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (AMITK_IS_DIAL (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); dial = AMITK_DIAL (widget); if (dial->button != 0) { x = event->x; y = event->y; if (event->is_hint || (event->window != widget->window)) gdk_window_get_pointer (widget->window, &x, &y, &mods); switch (dial->button) { case 1: mask = GDK_BUTTON1_MASK; break; case 2: mask = GDK_BUTTON2_MASK; break; case 3: mask = GDK_BUTTON3_MASK; break; default: mask = 0; break; } if (mods & mask) amitk_dial_update_mouse (dial, x,y); } return FALSE; } static gint amitk_dial_timer (AmitkDial *dial) { g_return_val_if_fail (dial != NULL, FALSE); g_return_val_if_fail (AMITK_IS_DIAL (dial), FALSE); if (dial->policy == GTK_UPDATE_DELAYED) g_signal_emit_by_name (G_OBJECT (dial->adjustment), "value_changed"); return FALSE; } static void amitk_dial_update_mouse (AmitkDial *dial, gint x, gint y) { gint xc, yc; gfloat old_value; g_return_if_fail (dial != NULL); g_return_if_fail (AMITK_IS_DIAL (dial)); xc = GTK_WIDGET(dial)->allocation.width / 2; yc = GTK_WIDGET(dial)->allocation.height / 2; old_value = dial->adjustment->value; dial->angle = atan2(yc-y, x-xc); if (dial->angle < M_PI/2.0) dial->angle += 2*M_PI; if (dial->angle > 4*M_PI/3.0) dial->angle -= 2*M_PI; dial->adjustment->value = dial->adjustment->upper - (dial->angle+M_PI/2.0)* (dial->adjustment->upper - dial->adjustment->lower) / (2*M_PI); if (dial->adjustment->value != old_value) { if (dial->policy == GTK_UPDATE_CONTINUOUS) { g_signal_emit_by_name (G_OBJECT (dial->adjustment), "value_changed"); } else { gtk_widget_queue_draw (GTK_WIDGET (dial)); if (dial->policy == GTK_UPDATE_DELAYED) { if (dial->timer) g_source_remove (dial->timer); dial->timer = g_timeout_add (SCROLL_DELAY_LENGTH, (GtkFunction) amitk_dial_timer, (gpointer) dial); } } } } static void amitk_dial_update (AmitkDial *dial) { gfloat new_value; g_return_if_fail (dial != NULL); g_return_if_fail (AMITK_IS_DIAL (dial)); new_value = dial->adjustment->value; if (new_value < dial->adjustment->lower) new_value = dial->adjustment->lower; if (new_value > dial->adjustment->upper) new_value = dial->adjustment->upper; if (new_value != dial->adjustment->value) { dial->adjustment->value = new_value; g_signal_emit_by_name (G_OBJECT (dial->adjustment), "value_changed"); } dial->angle = -M_PI/2.0 + 2.0*M_PI * (new_value - dial->adjustment->lower) / (dial->adjustment->upper - dial->adjustment->lower); gtk_widget_queue_draw (GTK_WIDGET (dial)); } static void amitk_dial_adjustment_changed (GtkAdjustment *adjustment, gpointer data) { AmitkDial *dial; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); dial = AMITK_DIAL (data); if ((dial->old_value != adjustment->value) || (dial->old_lower != adjustment->lower) || (dial->old_upper != adjustment->upper)) { amitk_dial_update (dial); dial->old_value = adjustment->value; dial->old_lower = adjustment->lower; dial->old_upper = adjustment->upper; } } static void amitk_dial_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) { AmitkDial *dial; g_return_if_fail (adjustment != NULL); g_return_if_fail (data != NULL); dial = AMITK_DIAL (data); if (dial->old_value != adjustment->value) { amitk_dial_update (dial); dial->old_value = adjustment->value; } } amide-1.0.6/amide-current/src/amitk_dial.h000066400000000000000000000047341423227705100204050ustar00rootroot00000000000000/* amitk_dial.h, adapted from gtkdial.h */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __AMITK_DIAL_H__ #define __AMITK_DIAL_H__ #include G_BEGIN_DECLS #define AMITK_DIAL(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, amitk_dial_get_type (), AmitkDial) #define AMITK_DIAL_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, amitk_dial_get_type (), AmitkDialClass) #define AMITK_IS_DIAL(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, amitk_dial_get_type ()) typedef struct _AmitkDial AmitkDial; typedef struct _AmitkDialClass AmitkDialClass; struct _AmitkDial { GtkWidget widget; /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */ guint policy : 2; /* Button currently pressed or 0 if none */ guint8 button; /* Dimensions of dial components */ gint radius; gint pointer_width; /* ID of update timer, or 0 if none */ guint32 timer; /* Current angle */ gfloat angle; gfloat last_angle; /* Old values from adjustment stored so we know when something changes */ gfloat old_value; gfloat old_lower; gfloat old_upper; /* The adjustment object that stores the data for this dial */ GtkAdjustment *adjustment; }; struct _AmitkDialClass { GtkWidgetClass parent_class; }; GtkWidget* amitk_dial_new (GtkAdjustment *adjustment); GType amitk_dial_get_type (void); GtkAdjustment* amitk_dial_get_adjustment (AmitkDial *dial); void amitk_dial_set_update_policy (AmitkDial *dial, GtkUpdateType policy); void amitk_dial_set_adjustment (AmitkDial *dial, GtkAdjustment *adjustment); G_END_DECLS #endif /* __AMITK_DIAL_H__ */ amide-1.0.6/amide-current/src/amitk_fiducial_mark.c000066400000000000000000000170441423227705100222570ustar00rootroot00000000000000/* amitk_fiducial_mark.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_fiducial_mark.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" enum { FIDUCIAL_MARK_CHANGED, LAST_SIGNAL }; static void fiducial_mark_class_init (AmitkFiducialMarkClass *klass); static void fiducial_mark_init (AmitkFiducialMark *fiducial_mark); static void fiducial_mark_finalize (GObject *object); static AmitkObject * fiducial_mark_copy (const AmitkObject *object); static void fiducial_mark_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); static void fiducial_mark_write_xml (const AmitkObject *object, xmlNodePtr nodes, FILE *study_file); static gchar * fiducial_mark_read_xml (AmitkObject *object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf); static AmitkObjectClass * parent_class; static guint fiducial_mark_signals[LAST_SIGNAL]; GType amitk_fiducial_mark_get_type(void) { static GType fiducial_mark_type = 0; if (!fiducial_mark_type) { static const GTypeInfo fiducial_mark_info = { sizeof (AmitkFiducialMarkClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) fiducial_mark_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkFiducialMark), 0, /* n_preallocs */ (GInstanceInitFunc) fiducial_mark_init, NULL /* value table */ }; fiducial_mark_type = g_type_register_static (AMITK_TYPE_OBJECT, "AmitkFiducialMark", &fiducial_mark_info, 0); } return fiducial_mark_type; } static void fiducial_mark_class_init (AmitkFiducialMarkClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); AmitkObjectClass * object_class = AMITK_OBJECT_CLASS(class); parent_class = g_type_class_peek_parent(class); object_class->object_copy = fiducial_mark_copy; object_class->object_copy_in_place = fiducial_mark_copy_in_place; object_class->object_write_xml = fiducial_mark_write_xml; object_class->object_read_xml = fiducial_mark_read_xml; gobject_class->finalize = fiducial_mark_finalize; fiducial_mark_signals[FIDUCIAL_MARK_CHANGED] = g_signal_new ("fiducial_mark_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkFiducialMarkClass, fiducial_mark_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); } static void fiducial_mark_init (AmitkFiducialMark * fiducial_mark) { fiducial_mark->specify_color = FALSE; fiducial_mark->color = amitk_color_table_uint32_to_rgba(AMITK_OBJECT_DEFAULT_COLOR); return; } static void fiducial_mark_finalize (GObject * object) { G_OBJECT_CLASS (parent_class)->finalize (object); } static AmitkObject * fiducial_mark_copy (const AmitkObject * object ) { AmitkFiducialMark * copy; g_return_val_if_fail(AMITK_IS_FIDUCIAL_MARK(object), NULL); copy = amitk_fiducial_mark_new(); amitk_object_copy_in_place(AMITK_OBJECT(copy), object); return AMITK_OBJECT(copy); } static void fiducial_mark_copy_in_place(AmitkObject * dest_object, const AmitkObject * src_object) { AmitkFiducialMark * src_fm; AmitkFiducialMark * dest_fm; g_return_if_fail(AMITK_IS_FIDUCIAL_MARK(src_object)); g_return_if_fail(AMITK_IS_FIDUCIAL_MARK(dest_object)); src_fm = AMITK_FIDUCIAL_MARK(src_object); dest_fm = AMITK_FIDUCIAL_MARK(dest_object); dest_fm->specify_color = AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(src_fm); dest_fm->color = AMITK_FIDUCIAL_MARK_COLOR(src_fm); AMITK_OBJECT_CLASS (parent_class)->object_copy_in_place (dest_object, src_object); } static void fiducial_mark_write_xml(const AmitkObject * object, xmlNodePtr nodes, FILE *study_file) { AmitkFiducialMark * fm; AMITK_OBJECT_CLASS(parent_class)->object_write_xml(object, nodes, study_file); fm = AMITK_FIDUCIAL_MARK(object); xml_save_boolean(nodes, "specify_color", AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(fm)); xml_save_uint(nodes, "color", amitk_color_table_rgba_to_uint32(AMITK_FIDUCIAL_MARK_COLOR(fm))); return; } static gchar * fiducial_mark_read_xml(AmitkObject * object, xmlNodePtr nodes, FILE * study_file, gchar * error_buf ) { AmitkFiducialMark * fm; AmitkPoint point; fm = AMITK_FIDUCIAL_MARK(object); error_buf = AMITK_OBJECT_CLASS(parent_class)->object_read_xml(object, nodes, study_file, error_buf); amitk_fiducial_mark_set_specify_color(fm, xml_get_boolean_with_default(nodes, "specify_color", AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(fm))); amitk_fiducial_mark_set_color(fm, amitk_color_table_uint32_to_rgba(xml_get_uint_with_default(nodes, "color", AMITK_OBJECT_DEFAULT_COLOR))); /* legacy cruft. the "point" option was eliminated in version 0.7.11, just using the space's offset instead */ if (xml_node_exists(nodes, "point")) { point = amitk_point_read_xml(nodes, "point", &error_buf); point = amitk_space_s2b(AMITK_SPACE(fm), point); amitk_space_set_offset(AMITK_SPACE(fm), point); } return error_buf; } AmitkFiducialMark * amitk_fiducial_mark_new (void) { AmitkFiducialMark * fiducial_mark; fiducial_mark = g_object_new(amitk_fiducial_mark_get_type(), NULL); return fiducial_mark; } /* new point should be in the base coordinate space */ void amitk_fiducial_mark_set(AmitkFiducialMark * fiducial_mark, AmitkPoint new_point) { g_return_if_fail(AMITK_IS_FIDUCIAL_MARK(fiducial_mark)); if (!POINT_EQUAL(AMITK_FIDUCIAL_MARK_GET(fiducial_mark), new_point)) { amitk_space_set_offset(AMITK_SPACE(fiducial_mark), new_point); } return; } /* whether we want to use the specified color or have the program choose a decent color */ void amitk_fiducial_mark_set_specify_color(AmitkFiducialMark * fiducial_mark, gboolean specify_color) { g_return_if_fail(AMITK_IS_FIDUCIAL_MARK(fiducial_mark)); if (specify_color != AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(fiducial_mark)) { fiducial_mark->specify_color = specify_color; g_signal_emit(G_OBJECT(fiducial_mark), fiducial_mark_signals[FIDUCIAL_MARK_CHANGED], 0); } return; } /* color to draw the fiducial_mark in, if we choose specify_color */ void amitk_fiducial_mark_set_color(AmitkFiducialMark * fiducial_mark, rgba_t new_color) { rgba_t old_color; g_return_if_fail(AMITK_IS_FIDUCIAL_MARK(fiducial_mark)); old_color = AMITK_FIDUCIAL_MARK_COLOR(fiducial_mark); if ((old_color.r != new_color.r) || (old_color.g != new_color.g) || (old_color.b != new_color.b) || (old_color.a != new_color.a)) { fiducial_mark->color = new_color; g_signal_emit(G_OBJECT(fiducial_mark), fiducial_mark_signals[FIDUCIAL_MARK_CHANGED], 0); } return; } amide-1.0.6/amide-current/src/amitk_fiducial_mark.h000066400000000000000000000057061423227705100222660ustar00rootroot00000000000000/* amitk_fiducial_mark.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_FIDUCIAL_MARK_H__ #define __AMITK_FIDUCIAL_MARK_H__ #include "amitk_object.h" #include "amitk_color_table.h" G_BEGIN_DECLS #define AMITK_TYPE_FIDUCIAL_MARK (amitk_fiducial_mark_get_type ()) #define AMITK_FIDUCIAL_MARK(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_FIDUCIAL_MARK, AmitkFiducialMark)) #define AMITK_FIDUCIAL_MARK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_FIDUCIAL_MARK, AmitkFiducialMarkClass)) #define AMITK_IS_FIDUCIAL_MARK(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_FIDUCIAL_MARK)) #define AMITK_IS_FIDUCIAL_MARK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_FIDUCIAL_MARK)) #define AMITK_FIDUCIAL_MARK_GET_CLASS(fiducial_mark) (G_TYPE_CHECK_GET_CLASS ((fiducial_mark), AMITK_TYPE_FIDUCIAL_MARK, AmitkFiducialMarkClass)) #define AMITK_FIDUCIAL_MARK_GET(mark) (AMITK_SPACE_OFFSET(mark)) #define AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(mark) (AMITK_FIDUCIAL_MARK(mark)->specify_color) #define AMITK_FIDUCIAL_MARK_COLOR(mark) (AMITK_FIDUCIAL_MARK(mark)->color) typedef struct _AmitkFiducialMarkClass AmitkFiducialMarkClass; typedef struct _AmitkFiducialMark AmitkFiducialMark; struct _AmitkFiducialMark { AmitkObject parent; gboolean specify_color; /* if false, program guesses a good color to use */ rgba_t color; }; struct _AmitkFiducialMarkClass { AmitkObjectClass parent_class; void (* fiducial_mark_changed) (AmitkFiducialMark * fiducial_mark); }; /* Application-level methods */ GType amitk_fiducial_mark_get_type (void); AmitkFiducialMark * amitk_fiducial_mark_new (void); void amitk_fiducial_mark_set (AmitkFiducialMark * fiducial_mark, AmitkPoint new_point); void amitk_fiducial_mark_set_specify_color (AmitkFiducialMark * fiducial_mark, gboolean specify_color); void amitk_fiducial_mark_set_color (AmitkFiducialMark * fiducial_mark, rgba_t color); G_END_DECLS #endif /* __AMITK_FIDUCIAL_MARK_H__ */ amide-1.0.6/amide-current/src/amitk_filter.c000066400000000000000000000271331423227705100207520ustar00rootroot00000000000000/* amitk_filter.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amitk_filter.h" #include "amitk_type_builtins.h" #ifdef AMIDE_LIBGSL_SUPPORT #include #endif static inline amide_real_t gaussian(amide_real_t x, amide_real_t sigma) { return exp(-(x*x)/(2.0*sigma*sigma))/(sigma*sqrt(2*M_PI)); } /* gaussian kernel is returned in a packad array (alternating real and imaginary parts since the filter is entirely real, all imaginary parts are zero */ AmitkRawData * amitk_filter_calculate_gaussian_kernel_complex(const AmitkVoxel kernel_size, const AmitkPoint voxel_size, const amide_real_t fwhm) { AmitkVoxel i_voxel; AmitkPoint location; amide_real_t sigma; AmitkVoxel half; AmitkRawData * kernel; amide_real_t total; amide_real_t gaussian_value; g_return_val_if_fail((kernel_size.t == 1), NULL); /* can't filter over time */ g_return_val_if_fail((kernel_size.g == 1), NULL); /* can't filter over gates */ g_return_val_if_fail((kernel_size.z & 0x1), NULL); /* needs to be odd */ g_return_val_if_fail((kernel_size.y & 0x1), NULL); g_return_val_if_fail((kernel_size.x & 0x1), NULL); if ((kernel = amitk_raw_data_new()) == NULL) { g_warning(_("couldn't allocate memory space for the kernel structure")); return NULL; } kernel->format = AMITK_FORMAT_DOUBLE; g_free(kernel->data); kernel->dim.t = kernel->dim.g = 1; kernel->dim.z = kernel->dim.y = AMITK_FILTER_FFT_SIZE; kernel->dim.x = 2*AMITK_FILTER_FFT_SIZE; /* real and complex */ /* get mem for the kernel, initialized to 0 */ if ((kernel->data = amitk_raw_data_get_data_mem0(kernel)) == NULL) { g_warning(_("Couldn't allocate memory space for the kernel data")); amitk_object_unref(kernel); return NULL; } sigma = fwhm/SIGMA_TO_FWHM; half.t = half.g = 0; half.z = kernel_size.z>>1; half.y = kernel_size.y>>1; half.x = kernel_size.x>>1; total = 0.0; i_voxel.t = i_voxel.g = 0; for (i_voxel.z = 0; i_voxel.z < kernel_size.z; i_voxel.z++) { location.z = voxel_size.z*(i_voxel.z-half.z); for (i_voxel.y = 0; i_voxel.y < kernel_size.y; i_voxel.y++) { location.y = voxel_size.y*(i_voxel.y-half.y); for (i_voxel.x = 0; i_voxel.x < 2*kernel_size.x; i_voxel.x+=2) { location.x = voxel_size.x*(i_voxel.x/2-half.x); gaussian_value = gaussian(point_mag(location), sigma); AMITK_RAW_DATA_DOUBLE_SET_CONTENT(kernel, i_voxel) = gaussian_value; total += gaussian_value; } } } /* renormalize, as the tails are cut, and we've discretized the gaussian */ for (i_voxel.z = 0; i_voxel.z < kernel_size.z; i_voxel.z++) for (i_voxel.y = 0; i_voxel.y < kernel_size.y; i_voxel.y++) for (i_voxel.x = 0; i_voxel.x < 2*kernel_size.x; i_voxel.x+=2) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(kernel, i_voxel) /= total; return kernel; } #ifdef AMIDE_LIBGSL_SUPPORT void amitk_filter_3D_FFT(AmitkRawData * data, gsl_fft_complex_wavetable * wavetable, gsl_fft_complex_workspace * workspace) { AmitkVoxel i_voxel; g_return_if_fail(AMITK_RAW_DATA_FORMAT(data) == AMITK_FORMAT_DOUBLE); g_return_if_fail(AMITK_RAW_DATA_DIM_T(data) == 1); g_return_if_fail(AMITK_RAW_DATA_DIM_G(data) == 1); g_return_if_fail(AMITK_RAW_DATA_DIM_Z(data) == AMITK_FILTER_FFT_SIZE); g_return_if_fail(AMITK_RAW_DATA_DIM_Y(data) == AMITK_FILTER_FFT_SIZE); g_return_if_fail(AMITK_RAW_DATA_DIM_X(data) == 2*AMITK_FILTER_FFT_SIZE); /* FFT in the X direction */ i_voxel.t = i_voxel.g = i_voxel.x = 0; for (i_voxel.z=0; i_voxel.z < AMITK_RAW_DATA_DIM_Z(data); i_voxel.z++) for (i_voxel.y=0; i_voxel.y < AMITK_RAW_DATA_DIM_Y(data); i_voxel.y++) gsl_fft_complex_forward(AMITK_RAW_DATA_DOUBLE_POINTER(data,i_voxel), 1, AMITK_FILTER_FFT_SIZE, wavetable, workspace); /* FFT in the Y direction */ i_voxel.t = i_voxel.g = i_voxel.y = 0; for (i_voxel.z=0; i_voxel.z < AMITK_RAW_DATA_DIM_Z(data); i_voxel.z++) for (i_voxel.x=0; i_voxel.x < AMITK_RAW_DATA_DIM_X(data); i_voxel.x+=2) gsl_fft_complex_forward(AMITK_RAW_DATA_DOUBLE_POINTER(data,i_voxel), AMITK_FILTER_FFT_SIZE, AMITK_FILTER_FFT_SIZE, wavetable, workspace); /* FFT in the Z direction */ i_voxel.t = i_voxel.g = i_voxel.z = 0; for (i_voxel.y=0; i_voxel.y < AMITK_RAW_DATA_DIM_Y(data); i_voxel.y++) for (i_voxel.x=0; i_voxel.x < AMITK_RAW_DATA_DIM_X(data); i_voxel.x+=2) gsl_fft_complex_forward(AMITK_RAW_DATA_DOUBLE_POINTER(data,i_voxel), AMITK_FILTER_FFT_SIZE*AMITK_FILTER_FFT_SIZE, AMITK_FILTER_FFT_SIZE, wavetable, workspace); return; } void amitk_filter_inverse_3D_FFT(AmitkRawData * data, gsl_fft_complex_wavetable * wavetable, gsl_fft_complex_workspace * workspace) { AmitkVoxel i_voxel; g_return_if_fail(AMITK_RAW_DATA_FORMAT(data) == AMITK_FORMAT_DOUBLE); g_return_if_fail(AMITK_RAW_DATA_DIM_T(data) == 1); g_return_if_fail(AMITK_RAW_DATA_DIM_G(data) == 1); g_return_if_fail(AMITK_RAW_DATA_DIM_Z(data) == AMITK_FILTER_FFT_SIZE); g_return_if_fail(AMITK_RAW_DATA_DIM_Y(data) == AMITK_FILTER_FFT_SIZE); g_return_if_fail(AMITK_RAW_DATA_DIM_X(data) == 2*AMITK_FILTER_FFT_SIZE); /* inverse FFT in the X direction */ i_voxel.t = i_voxel.g = i_voxel.x = 0; for (i_voxel.z=0; i_voxel.z < AMITK_RAW_DATA_DIM_Z(data); i_voxel.z++) for (i_voxel.y=0; i_voxel.y < AMITK_RAW_DATA_DIM_Y(data); i_voxel.y++) gsl_fft_complex_inverse(AMITK_RAW_DATA_DOUBLE_POINTER(data,i_voxel), 1, AMITK_FILTER_FFT_SIZE, wavetable, workspace); /* inverse FFT in the Y direction */ i_voxel.t = i_voxel.g = i_voxel.y = 0; for (i_voxel.z=0; i_voxel.z < AMITK_RAW_DATA_DIM_Z(data); i_voxel.z++) for (i_voxel.x=0; i_voxel.x < AMITK_RAW_DATA_DIM_X(data); i_voxel.x+=2) gsl_fft_complex_inverse(AMITK_RAW_DATA_DOUBLE_POINTER(data,i_voxel), AMITK_FILTER_FFT_SIZE, AMITK_FILTER_FFT_SIZE, wavetable, workspace); /* inverse FFT in the Z direction */ i_voxel.t = i_voxel.g = i_voxel.z = 0; for (i_voxel.y=0; i_voxel.y < AMITK_RAW_DATA_DIM_Y(data); i_voxel.y++) for (i_voxel.x=0; i_voxel.x < AMITK_RAW_DATA_DIM_X(data); i_voxel.x+=2) gsl_fft_complex_inverse(AMITK_RAW_DATA_DOUBLE_POINTER(data,i_voxel), AMITK_FILTER_FFT_SIZE*AMITK_FILTER_FFT_SIZE, AMITK_FILTER_FFT_SIZE, wavetable, workspace); return; } /* multiples the data by the kernel, both of which are in packed complex form */ void amitk_filter_complex_mult(AmitkRawData * data, AmitkRawData * kernel) { AmitkVoxel i_voxel; AmitkVoxel j_voxel; gsl_complex a,b; g_return_if_fail(AMITK_RAW_DATA_FORMAT(data) == AMITK_FORMAT_DOUBLE); g_return_if_fail(AMITK_RAW_DATA_FORMAT(kernel) == AMITK_FORMAT_DOUBLE); g_return_if_fail(AMITK_RAW_DATA_DIM_T(data) == AMITK_RAW_DATA_DIM_T(kernel)); g_return_if_fail(AMITK_RAW_DATA_DIM_Z(data) == AMITK_RAW_DATA_DIM_Z(kernel)); g_return_if_fail(AMITK_RAW_DATA_DIM_Y(data) == AMITK_RAW_DATA_DIM_Y(kernel)); g_return_if_fail(AMITK_RAW_DATA_DIM_X(data) == AMITK_RAW_DATA_DIM_X(kernel)); i_voxel.t = i_voxel.g = j_voxel.t = j_voxel.g = 0; for (i_voxel.z = 0, j_voxel.z=0; i_voxel.z < AMITK_RAW_DATA_DIM_Z(data); i_voxel.z++, j_voxel.z++) for (i_voxel.y = 0, j_voxel.y=0; i_voxel.y < AMITK_RAW_DATA_DIM_Y(data); i_voxel.y++, j_voxel.y++) for (i_voxel.x = 0, j_voxel.x=1; i_voxel.x < AMITK_RAW_DATA_DIM_X(data); i_voxel.x+=2, j_voxel.x+=2) { a.dat[0] = AMITK_RAW_DATA_DOUBLE_CONTENT(data, i_voxel); a.dat[1] = AMITK_RAW_DATA_DOUBLE_CONTENT(data, j_voxel); b.dat[0] = AMITK_RAW_DATA_DOUBLE_CONTENT(kernel, i_voxel); b.dat[1] = AMITK_RAW_DATA_DOUBLE_CONTENT(kernel, j_voxel); a = gsl_complex_mul(a,b); AMITK_RAW_DATA_DOUBLE_SET_CONTENT(data, i_voxel) = a.dat[0]; AMITK_RAW_DATA_DOUBLE_SET_CONTENT(data, j_voxel) = a.dat[1]; } return; } #endif /* do a (destructive) partial sort of the given data to find median */ /* adapted and modified from Numerical Receipes in C, (who got it from Knuth, Vol 3?) */ /* median size needs to be odd for this to be strictly correct from a statistical stand point*/ #define SWAP(leftv, rightv) temp=(leftv); (leftv)=(rightv); (rightv=temp) amide_data_t amitk_filter_find_median_by_partial_sort(amide_data_t * partial_sort_data, gint size) { gint left, right, mid; gint i_left, i_right; gint median_point; amide_data_t partition_value; amide_data_t temp; median_point = (size-1) >> 1; /* not strictly correct for case of even size */ left = 0; right = size-1; while (TRUE) if (right-left <= 2) { /* <= 3 elements left */ if (right-left == 1) {/* 2 elements left to sort*/ if (partial_sort_data[left] > partial_sort_data[right]) { SWAP(partial_sort_data[left], partial_sort_data[right]); } } else if (right-left == 2){ /* 3 elements left to sort */ if (partial_sort_data[left] > partial_sort_data[right]) { SWAP(partial_sort_data[left], partial_sort_data[right]); } if (partial_sort_data[left+1] > partial_sort_data[right]) { SWAP(partial_sort_data[left+1], partial_sort_data[right]); } if (partial_sort_data[left] > partial_sort_data[left+1]) { SWAP(partial_sort_data[left], partial_sort_data[left+1]); } } return partial_sort_data[median_point]; } else { mid = (left+right) >> 1; /* do a three way median with the leftmost, rightmost, and mid elements to get a decent guess for a partitioning element. This partioning element ends up in left+1*/ SWAP(partial_sort_data[mid], partial_sort_data[left+1]); if (partial_sort_data[left] > partial_sort_data[right]) { SWAP(partial_sort_data[left], partial_sort_data[right]); } if (partial_sort_data[left+1] > partial_sort_data[right]) { SWAP(partial_sort_data[left+1], partial_sort_data[right]); } if (partial_sort_data[left] > partial_sort_data[left+1]) { SWAP(partial_sort_data[left], partial_sort_data[left+1]); } partition_value = partial_sort_data[left+1]; i_left=left+1; i_right = right; while (TRUE) { /* find an element > partition_value */ do i_left++; while (partial_sort_data[i_left] < partition_value); /* find an element < partition value */ do i_right--; while (partial_sort_data[i_right] > partition_value); if (i_right < i_left) break; /* pointers crossed */ SWAP(partial_sort_data[i_left], partial_sort_data[i_right]); } partial_sort_data[left+1] = partial_sort_data[i_right]; partial_sort_data[i_right] = partition_value; if (i_right >= median_point) right = i_right-1; if (i_right <= median_point) left = i_left; } } const gchar * amitk_filter_get_name(const AmitkFilter filter) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_FILTER); enum_value = g_enum_get_value(enum_class, filter); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_filter.h000066400000000000000000000040671423227705100207600ustar00rootroot00000000000000/* amitk_filter.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_FILTER_H__ #define __AMITK_FILTER_H__ #include #ifndef _GNU_SOURCE #define _GNU_SOURCE /* use GNU extensions, i.e. NaN */ #endif #include #include "amitk_raw_data.h" #ifdef AMIDE_LIBGSL_SUPPORT #include #endif G_BEGIN_DECLS typedef enum { AMITK_FILTER_GAUSSIAN, AMITK_FILTER_MEDIAN_LINEAR, AMITK_FILTER_MEDIAN_3D, AMITK_FILTER_NUM } AmitkFilter; #define AMITK_FILTER_FFT_SIZE 64 AmitkRawData * amitk_filter_calculate_gaussian_kernel_complex(const AmitkVoxel kernel_size, const AmitkPoint voxel_size, const amide_real_t fwhm); #ifdef AMIDE_LIBGSL_SUPPORT void amitk_filter_3D_FFT(AmitkRawData * data, gsl_fft_complex_wavetable * wavetable, gsl_fft_complex_workspace * workspace); void amitk_filter_inverse_3D_FFT(AmitkRawData * data, gsl_fft_complex_wavetable * wavetable, gsl_fft_complex_workspace * workspace); void amitk_filter_complex_mult(AmitkRawData * data, AmitkRawData * kernel); #endif amide_data_t amitk_filter_find_median_by_partial_sort(amide_data_t * partial_sort_data, gint size); const gchar * amitk_filter_get_name(const AmitkFilter filter); G_END_DECLS #endif /* __AMITK_FILTER_H__ */ amide-1.0.6/amide-current/src/amitk_line_profile.c000066400000000000000000000126211423227705100221300ustar00rootroot00000000000000/* amitk_line_profile.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_line_profile.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" enum { LINE_PROFILE_CHANGED, LAST_SIGNAL }; static void line_profile_class_init (AmitkLineProfileClass *klass); static void line_profile_init (AmitkLineProfile *object); static void line_profile_finalize (GObject *object); static GObjectClass * parent_class; static guint line_profile_signals[LAST_SIGNAL]; GType amitk_line_profile_get_type(void) { static GType line_profile_type = 0; if (!line_profile_type) { static const GTypeInfo line_profile_info = { sizeof (AmitkLineProfileClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) line_profile_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkLineProfile), 0, /* n_preallocs */ (GInstanceInitFunc) line_profile_init, NULL /* value table */ }; line_profile_type = g_type_register_static (G_TYPE_OBJECT, "AmitkLineProfile", &line_profile_info, 0); } return line_profile_type; } static void line_profile_class_init (AmitkLineProfileClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent(class); gobject_class->finalize = line_profile_finalize; line_profile_signals[LINE_PROFILE_CHANGED] = g_signal_new ("line_profile_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkLineProfileClass, line_profile_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); } static void line_profile_init (AmitkLineProfile * line_profile) { line_profile->view = AMITK_VIEW_TRANSVERSE; line_profile->angle=0.0; line_profile->visible=FALSE; line_profile->start_point = zero_point; line_profile->end_point = zero_point; return; } static void line_profile_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } AmitkLineProfile * amitk_line_profile_new (void) { AmitkLineProfile * line_profile; line_profile = g_object_new(amitk_line_profile_get_type(), NULL); return line_profile; } void amitk_line_profile_copy_in_place(AmitkLineProfile * dest_profile, const AmitkLineProfile * src_profile) { g_return_if_fail(AMITK_IS_LINE_PROFILE(src_profile)); g_return_if_fail(AMITK_IS_LINE_PROFILE(dest_profile)); dest_profile->view = AMITK_LINE_PROFILE_VIEW(src_profile); dest_profile->angle = AMITK_LINE_PROFILE_ANGLE(src_profile); dest_profile->visible = AMITK_LINE_PROFILE_VISIBLE(src_profile); return; } void amitk_line_profile_set_view(AmitkLineProfile * line_profile, AmitkView view) { g_return_if_fail(AMITK_IS_LINE_PROFILE(line_profile)); g_return_if_fail(view >= 0); g_return_if_fail(view < AMITK_VIEW_NUM); if (AMITK_LINE_PROFILE_VIEW(line_profile) != view) { line_profile->view = view; g_signal_emit(G_OBJECT(line_profile), line_profile_signals[LINE_PROFILE_CHANGED], 0); } return; } void amitk_line_profile_set_angle(AmitkLineProfile * line_profile, amide_real_t angle) { g_return_if_fail(AMITK_IS_LINE_PROFILE(line_profile)); if (angle > M_PI) angle-=2.0*M_PI; if (angle < -M_PI) angle+=2.0*M_PI; if (!REAL_EQUAL(AMITK_LINE_PROFILE_ANGLE(line_profile), angle)) { line_profile->angle = angle; g_signal_emit(G_OBJECT(line_profile), line_profile_signals[LINE_PROFILE_CHANGED], 0); } return; } void amitk_line_profile_set_visible(AmitkLineProfile * line_profile, gboolean visible) { g_return_if_fail(AMITK_IS_LINE_PROFILE(line_profile)); if (AMITK_LINE_PROFILE_VISIBLE(line_profile) != visible) { line_profile->visible = visible; g_signal_emit(G_OBJECT(line_profile), line_profile_signals[LINE_PROFILE_CHANGED], 0); } return; } void amitk_line_profile_set_start_point(AmitkLineProfile * line_profile, const AmitkPoint start_point) { g_return_if_fail(AMITK_IS_LINE_PROFILE(line_profile)); if (!POINT_EQUAL(AMITK_LINE_PROFILE_START_POINT(line_profile), start_point)) { line_profile->start_point = start_point; g_signal_emit(G_OBJECT(line_profile), line_profile_signals[LINE_PROFILE_CHANGED], 0); } return; } void amitk_line_profile_set_end_point(AmitkLineProfile * line_profile, const AmitkPoint end_point) { g_return_if_fail(AMITK_IS_LINE_PROFILE(line_profile)); if (!POINT_EQUAL(AMITK_LINE_PROFILE_END_POINT(line_profile), end_point)) { line_profile->end_point = end_point; g_signal_emit(G_OBJECT(line_profile), line_profile_signals[LINE_PROFILE_CHANGED], 0); } return; } amide-1.0.6/amide-current/src/amitk_line_profile.h000066400000000000000000000073611423227705100221420ustar00rootroot00000000000000/* amitk_line_profile.h * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_LINE_PROFILE_H__ #define __AMITK_LINE_PROFILE_H__ /* header files that are always needed with this file */ #include #include "amitk_object.h" G_BEGIN_DECLS #define AMITK_TYPE_LINE_PROFILE (amitk_line_profile_get_type ()) #define AMITK_LINE_PROFILE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_LINE_PROFILE, AmitkLineProfile)) #define AMITK_LINE_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_LINE_PROFILE, AmitkLineProfileClass)) #define AMITK_IS_LINE_PROFILE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_LINE_PROFILE)) #define AMITK_IS_LINE_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_LINE_PROFILE)) #define AMITK_LINE_PROFILE_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_LINE_PROFILE, AmitkLineProfileClass)) #define AMITK_LINE_PROFILE_VIEW(linep) (AMITK_LINE_PROFILE(linep)->view) #define AMITK_LINE_PROFILE_ANGLE(linep) (AMITK_LINE_PROFILE(linep)->angle) #define AMITK_LINE_PROFILE_VISIBLE(linep) (AMITK_LINE_PROFILE(linep)->visible) #define AMITK_LINE_PROFILE_START_POINT(linep) (AMITK_LINE_PROFILE(linep)->start_point) #define AMITK_LINE_PROFILE_END_POINT(linep) (AMITK_LINE_PROFILE(linep)->end_point) typedef struct _AmitkLineProfileClass AmitkLineProfileClass; typedef struct _AmitkLineProfile AmitkLineProfile; struct _AmitkLineProfile { GObject parent; AmitkView view; amide_real_t angle; /* in radians */ gboolean visible; /* in base coordinate frame. These are updated by the canvas */ AmitkPoint start_point; AmitkPoint end_point; }; struct _AmitkLineProfileClass { GObjectClass parent_class; void (* line_profile_changed) (AmitkLineProfile * line_profile); }; typedef struct _AmitkLineProfileDataElement AmitkLineProfileDataElement; struct _AmitkLineProfileDataElement { amide_real_t value; amide_real_t location; }; /* ------------ external functions ---------- */ GType amitk_line_profile_get_type (void); AmitkLineProfile* amitk_line_profile_new (void); void amitk_line_profile_copy_in_place (AmitkLineProfile * dest_profile, const AmitkLineProfile * src_profile); void amitk_line_profile_set_view (AmitkLineProfile * line_profile, const AmitkView view); void amitk_line_profile_set_angle (AmitkLineProfile * line_profile, const amide_real_t angle); void amitk_line_profile_set_visible (AmitkLineProfile * line_profile, const gboolean visible); void amitk_line_profile_set_start_point(AmitkLineProfile * line_profile, const AmitkPoint start_point); void amitk_line_profile_set_end_point (AmitkLineProfile * line_profile, const AmitkPoint end_point); G_END_DECLS #endif /* __AMITK_LINE_PROFILE_H__ */ amide-1.0.6/amide-current/src/amitk_marshal.list000066400000000000000000000006461423227705100216450ustar00rootroot00000000000000OBJECT:OBJECT OBJECT:VOID VOID:POINTER VOID:POINTER,POINTER VOID:VOID VOID:BOXED VOID:BOXED,BOXED VOID:BOXED,DOUBLE VOID:BOXED,DOUBLE,BOXED VOID:ENUM VOID:ENUM,BOXED VOID:ENUM,BOXED,DOUBLE VOID:ENUM,POINTER,DOUBLE VOID:OBJECT VOID:OBJECT,BOOLEAN VOID:OBJECT,BOXED VOID:OBJECT,ENUM VOID:OBJECT,ENUM, BOXED VOID:OBJECT,ENUM, ENUM VOID:UINT, UINT STRING:POINTER,STRING POINTER:POINTER,POINTER POINTER:POINTER,POINTER,POINTER amide-1.0.6/amide-current/src/amitk_object.c000066400000000000000000001113751423227705100207350ustar00rootroot00000000000000/* amitk_object.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include "amitk_object.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "amitk_study.h" enum { OBJECT_NAME_CHANGED, OBJECT_SELECTION_CHANGED, OBJECT_CHILD_SELECTION_CHANGED, OBJECT_COPY, OBJECT_COPY_IN_PLACE, OBJECT_WRITE_XML, OBJECT_READ_XML, OBJECT_ADD_CHILD, OBJECT_REMOVE_CHILD, LAST_SIGNAL }; static void object_class_init (AmitkObjectClass *klass); static void object_init (AmitkObject *object); static void object_finalize (GObject *object); static void object_rotate_on_vector (AmitkSpace *space, AmitkPoint *vector, gdouble theta, AmitkPoint *rotation_point); static void object_invert_axis (AmitkSpace *space, AmitkAxis which_axis, AmitkPoint *center_of_inversion); static void object_shift_offset (AmitkSpace *space, AmitkPoint *shift); static void object_transform (AmitkSpace *space, AmitkSpace *transform_space); static void object_transform_axes (AmitkSpace *space, AmitkAxes transform_axes, AmitkPoint * center_of_rotation); static void object_scale (AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling); static void object_child_selection_changed(AmitkObject * object); static AmitkObject * object_copy (const AmitkObject * object); static void object_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); static void object_write_xml (const AmitkObject * object, xmlNodePtr nodes, FILE *study_file); static gchar * object_read_xml (AmitkObject *object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf); static void object_add_child (AmitkObject * object, AmitkObject * child); static void object_remove_child (AmitkObject * object, AmitkObject * child); static AmitkSpaceClass * parent_class; static guint object_signals[LAST_SIGNAL]; GType amitk_object_get_type(void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (AmitkObjectClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) object_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkObject), 0, /* n_preallocs */ (GInstanceInitFunc) object_init, NULL /* value table */ }; object_type = g_type_register_static (AMITK_TYPE_SPACE, "AmitkObject", &object_info, 0); } return object_type; } static void object_class_init (AmitkObjectClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); AmitkSpaceClass * space_class = AMITK_SPACE_CLASS(class); parent_class = g_type_class_peek_parent(class); gobject_class->finalize = object_finalize; space_class->space_shift = object_shift_offset; space_class->space_rotate = object_rotate_on_vector; space_class->space_invert = object_invert_axis; space_class->space_transform = object_transform; space_class->space_transform_axes = object_transform_axes; space_class->space_scale = object_scale; class->object_name_changed = NULL; class->object_selection_changed = NULL; class->object_child_selection_changed = object_child_selection_changed; class->object_copy = object_copy; class->object_copy_in_place = object_copy_in_place; class->object_write_xml = object_write_xml; class->object_read_xml = object_read_xml; class->object_add_child = object_add_child; class->object_remove_child = object_remove_child; object_signals[OBJECT_NAME_CHANGED] = g_signal_new ("object_name_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_name_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); object_signals[OBJECT_SELECTION_CHANGED] = g_signal_new ("object_selection_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_selection_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); object_signals[OBJECT_CHILD_SELECTION_CHANGED] = g_signal_new ("object_child_selection_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_child_selection_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); object_signals[OBJECT_COPY] = g_signal_new ("object_copy", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_copy), NULL, NULL, amitk_marshal_OBJECT__VOID, AMITK_TYPE_OBJECT,0); object_signals[OBJECT_COPY_IN_PLACE] = g_signal_new ("object_copy_in_place", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_copy_in_place), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, AMITK_TYPE_OBJECT); object_signals[OBJECT_WRITE_XML] = g_signal_new ("object_write_xml", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_write_xml), NULL, NULL, amitk_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); object_signals[OBJECT_READ_XML] = g_signal_new ("object_read_xml", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkObjectClass, object_read_xml), NULL, NULL, amitk_marshal_POINTER__POINTER_POINTER_POINTER, G_TYPE_POINTER, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER); /* for some reason, G_TYPE_STRING is a no no */ object_signals[OBJECT_ADD_CHILD] = g_signal_new ("object_add_child", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(AmitkObjectClass, object_add_child), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, AMITK_TYPE_OBJECT); object_signals[OBJECT_REMOVE_CHILD] = g_signal_new ("object_remove_child", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(AmitkObjectClass, object_remove_child), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, AMITK_TYPE_OBJECT); } static void object_init (AmitkObject * object) { AmitkSelection i_selection; object->name = NULL; object->parent = NULL; object->children = NULL; object->dialog = NULL; for (i_selection = 0; i_selection < AMITK_SELECTION_NUM; i_selection++) object->selected[i_selection] = FALSE; } static void object_finalize (GObject *object) { AmitkObject * amitk_object = AMITK_OBJECT(object); AmitkObject * child; /* propogate signal to children */ /* can't call amitk_object_remove_children, as this leads to a g_signal_emit, which we can't do on amitk_object as ref count is now zero */ while (amitk_object->children != NULL) { child = amitk_object->children->data; child->parent = NULL; amitk_object->children = g_list_remove(amitk_object->children, child); amitk_object_unref(child); } amitk_object_set_parent(amitk_object, NULL); if (amitk_object->name != NULL) { #ifdef AMIDE_DEBUG if (!AMITK_IS_DATA_SET(amitk_object)) g_print("\tfreeing %s\n", AMITK_OBJECT_NAME(amitk_object)); #endif g_free(amitk_object->name); amitk_object->name = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static void object_rotate_on_vector(AmitkSpace * space, AmitkPoint * vector, gdouble theta, AmitkPoint * rotation_point) { AmitkObject * object; GList * children; g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); /* rotate children */ children = object->children; while (children != NULL) { amitk_space_rotate_on_vector(children->data, *vector, theta, *rotation_point); children = children->next; } AMITK_SPACE_CLASS(parent_class)->space_rotate (space, vector, theta, rotation_point); return; } static void object_invert_axis (AmitkSpace * space, AmitkAxis which_axis, AmitkPoint * center_of_inversion) { AmitkObject * object; GList * children; g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); /* invert children */ children = object->children; while (children != NULL) { amitk_space_invert_axis(children->data, which_axis, *center_of_inversion); children = children->next; } AMITK_SPACE_CLASS(parent_class)->space_invert (space, which_axis, center_of_inversion); } static void object_shift_offset(AmitkSpace * space, AmitkPoint * shift) { AmitkObject * object; GList * children; g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); children = object->children; while (children != NULL) { amitk_space_shift_offset(children->data, *shift); children = children->next; } AMITK_SPACE_CLASS(parent_class)->space_shift (space, shift); } static void object_transform(AmitkSpace * space, AmitkSpace * transform_space) { AmitkObject * object; GList * children; AmitkPoint shift, new_offset; AmitkSpace * new_space; AmitkSpace * child_transform_space; g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); children = object->children; if (children != NULL) { /* figure out what the parent's space is going to look like */ new_space = amitk_space_copy(space); amitk_space_transform(new_space, transform_space); while (children != NULL) { /* need to compensate, as the children shoould rotate around the parent's origin, not their own */ new_offset = amitk_space_b2s(AMITK_SPACE(space), AMITK_SPACE_OFFSET(children->data)); /* child offset wrt the parent space */ new_offset = amitk_space_s2b(AMITK_SPACE(new_space), new_offset); /* child offset post transformation */ shift = point_sub(new_offset, AMITK_SPACE_OFFSET(children->data)); /* the required shift */ /* setup the new transform space */ child_transform_space = amitk_space_copy(transform_space); amitk_space_set_offset(child_transform_space, shift); /* and apply */ amitk_space_transform(children->data, child_transform_space); g_object_unref(child_transform_space); children = children->next; } g_object_unref(new_space); } /* and finally do the transformation on the actually object */ AMITK_SPACE_CLASS(parent_class)->space_transform (space, transform_space); } static void object_transform_axes(AmitkSpace * space, AmitkAxes transform_axes, AmitkPoint * center_of_rotation) { AmitkObject * object; GList * children; g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); children = object->children; while (children != NULL) { amitk_space_transform_axes(children->data, transform_axes, *center_of_rotation); children = children->next; } AMITK_SPACE_CLASS(parent_class)->space_transform_axes (space, transform_axes, center_of_rotation); } static void object_scale(AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling) { AmitkObject * object; GList * children; g_return_if_fail(AMITK_IS_OBJECT(space)); object = AMITK_OBJECT(space); children = object->children; while (children != NULL) { amitk_space_scale(children->data, *ref_point, *scaling); children = children->next; } AMITK_SPACE_CLASS(parent_class)->space_scale (space, ref_point, scaling); } static void object_child_selection_changed(AmitkObject * object) { /* propogate the signal up the tree */ if (AMITK_OBJECT_PARENT(object) != NULL) g_signal_emit(G_OBJECT(AMITK_OBJECT_PARENT(object)), object_signals[OBJECT_CHILD_SELECTION_CHANGED], 0); return; } static AmitkObject * object_copy (const AmitkObject * object) { AmitkObject * copy; copy = amitk_object_new(); amitk_object_copy_in_place(copy, object); return copy; } void object_copy_in_place(AmitkObject * dest_object, const AmitkObject * src_object) { AmitkSelection i_selection; GList * children; AmitkObject * child; amitk_space_copy_in_place(AMITK_SPACE(dest_object), AMITK_SPACE(src_object)); amitk_object_set_name(dest_object, AMITK_OBJECT_NAME(src_object)); for (i_selection=0; i_selectiondialog, as that's the dialog for modifying the old object */ /* delete the old children */ // I need to do the below... but doesn't currently play nice with canvas... // amitk_object_remove_children(dest_object, dest_object->children); /* and recurse to copy in the new children */ children = src_object->children; while (children != NULL) { child = amitk_object_copy(children->data); #if AMIDE_DEBUG g_print("copying %s\n", AMITK_OBJECT_NAME(child)); #endif amitk_object_add_child(dest_object, child); amitk_object_unref(child); children = children->next; } return; } static void object_write_xml (const AmitkObject * object, xmlNodePtr nodes, FILE * study_file) { xmlNodePtr children_nodes; AmitkSelection i_selection; amitk_space_write_xml(nodes, "coordinate_space", AMITK_SPACE(object)); children_nodes = xmlNewChild(nodes, NULL, (xmlChar*) "children", NULL); amitk_objects_write_xml(AMITK_OBJECT_CHILDREN(object), children_nodes, study_file); for (i_selection = 0; i_selection < AMITK_SELECTION_NUM; i_selection++) xml_save_boolean(nodes, amitk_selection_get_name(i_selection), object->selected[i_selection]); return; } static gchar * object_read_xml (AmitkObject * object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf) { AmitkSpace * space; xmlNodePtr children_nodes; GList * children; AmitkSelection i_selection; space = amitk_space_read_xml(nodes, "coordinate_space", &error_buf); amitk_space_copy_in_place(AMITK_SPACE(object), space); g_object_unref(space); children_nodes = xml_get_node(nodes, "children"); children = amitk_objects_read_xml(children_nodes->children, study_file, &error_buf); amitk_object_add_children(object, children); children = amitk_objects_unref(children); for (i_selection = 0; i_selection < AMITK_SELECTION_NUM; i_selection++) object->selected[i_selection] = xml_get_boolean(nodes, amitk_selection_get_name(i_selection), &error_buf); return error_buf; } static void object_add_child(AmitkObject * object, AmitkObject * child) { amitk_object_ref(child); object->children = g_list_append(object->children, child); child->parent = object; return; } static void object_remove_child(AmitkObject * object, AmitkObject * child) { child->parent = NULL; object->children = g_list_remove(object->children, child); amitk_object_unref(child); return; } AmitkObject * amitk_object_new (void) { AmitkObject * object; object = g_object_new(amitk_object_get_type(), NULL); return object; } /* amide_data_file_xml_start_tag and amide_data_file_end_tag are used by amitk_study_recover_xml as it searches through the file looking for xml objects to load in */ gchar * amide_data_file_version_str = "amide_data_file_version"; gchar * amide_data_file_xml_tag = ""; gchar * amide_data_file_xml_start_tag = ""; gchar * amide_data_file_xml_end_tag = ""; /* if study_file is NULL, we're saving as a directory, and output_filename will be set (if not NULL), otherwise location will be set */ void amitk_object_write_xml(AmitkObject * object, FILE * study_file, gchar ** output_filename, guint64 * plocation, guint64 *psize) { gchar * xml_filename=NULL; const gchar * object_name; guint count; struct stat file_info; xmlDocPtr doc; xmlNodePtr nodes; g_return_if_fail(AMITK_IS_OBJECT(object)); if (AMITK_IS_DATA_SET(object)) object_name = amitk_object_type_get_name(AMITK_OBJECT_TYPE_DATA_SET); else if (AMITK_IS_STUDY(object)) object_name = amitk_object_type_get_name(AMITK_OBJECT_TYPE_STUDY); else if (AMITK_IS_FIDUCIAL_MARK(object)) object_name = amitk_object_type_get_name(AMITK_OBJECT_TYPE_FIDUCIAL_MARK); else if (AMITK_IS_ROI(object)) object_name = amitk_object_type_get_name(AMITK_OBJECT_TYPE_ROI); else if (AMITK_IS_VOLUME(object)) object_name = amitk_object_type_get_name(AMITK_OBJECT_TYPE_VOLUME); else g_return_if_reached(); if (study_file == NULL) { /* if we're saving in directory format, come up with a filename for this object */ count = 1; xml_filename = g_strdup_printf("%s_%s.xml", object_name, AMITK_OBJECT_NAME(object)); /* see if this file already exists */ while (stat(xml_filename, &file_info) == 0) { g_free(xml_filename); count++; xml_filename = g_strdup_printf("%s_%s_%d.xml", object_name, AMITK_OBJECT_NAME(object), count); } /* and we now have a unique filename */ #ifdef AMIDE_DEBUG g_print("\t- saving object %s in %s\n",AMITK_OBJECT_NAME(object), xml_filename); #endif } else { #ifdef AMIDE_DEBUG g_print("\t- saving object %s\n",AMITK_OBJECT_NAME(object)); #endif } /* write the xml file */ doc = xmlNewDoc((xmlChar *) "1.0"); doc->children = xmlNewDocNode(doc, NULL, (xmlChar *) amide_data_file_version_str, AMITK_FILE_VERSION); nodes = xmlNewChild(doc->children, NULL, (xmlChar *) object_name, (xmlChar *) AMITK_OBJECT_NAME(object)); g_signal_emit(G_OBJECT(object), object_signals[OBJECT_WRITE_XML], 0, nodes, study_file); /* and save */ if (study_file == NULL) { /* save as directory */ xmlSaveFile(xml_filename, doc); if (output_filename != NULL) *output_filename = xml_filename; else g_free(xml_filename); } else { *plocation = ftell(study_file); xmlDocDump(study_file, doc); *psize = ftell(study_file)-*plocation; } /* and we're done */ xmlFreeDoc(doc); return; } AmitkObject * amitk_object_read_xml(gchar * xml_filename, FILE * study_file, guint64 location, guint64 size, gchar ** perror_buf) { AmitkObject * new_object; xmlDocPtr doc; xmlNodePtr doc_nodes; xmlNodePtr type_node; xmlNodePtr version_node; xmlNodePtr object_node; gchar * version; gchar * name; AmitkObjectType i_type, type; if ((doc = xml_open_doc(xml_filename, study_file, location, size, perror_buf))==NULL) return NULL; /* error message appended by function */ /* get the root of our document */ if ((doc_nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf, _("AMIDE xml file doesn't appear to have a root.")); return NULL; } version_node = doc_nodes->children; /* look at the file version */ version = xml_get_string(version_node, "text"); g_return_val_if_fail(version != NULL, NULL); /* figure out what type of object is in here */ i_type = 0; type = AMITK_OBJECT_TYPE_NUM; while ((type == AMITK_OBJECT_TYPE_NUM) && (i_type < AMITK_OBJECT_TYPE_NUM)) { type_node = xml_get_node(version_node, amitk_object_type_get_name(i_type)); if (type_node != NULL) type = i_type; i_type++; } switch(type) { case AMITK_OBJECT_TYPE_STUDY: new_object = AMITK_OBJECT(amitk_study_new(NULL)); break; case AMITK_OBJECT_TYPE_FIDUCIAL_MARK: new_object = AMITK_OBJECT(amitk_fiducial_mark_new()); break; case AMITK_OBJECT_TYPE_DATA_SET: new_object = AMITK_OBJECT(amitk_data_set_new(NULL, -1)); break; case AMITK_OBJECT_TYPE_ROI: new_object = AMITK_OBJECT(amitk_roi_new(0)); break; case AMITK_OBJECT_TYPE_VOLUME: new_object = AMITK_OBJECT(amitk_volume_new()); break; default: g_return_val_if_reached(NULL); break; } object_node = type_node->children; name = xml_get_string(object_node, "text"); amitk_object_set_name(new_object, name); g_free(name); #ifdef AMIDE_DEBUG g_print("\treading: %s\ttype: %s\tfile version: %s\n", AMITK_OBJECT_NAME(new_object), amitk_object_type_get_name(type), version); #endif g_signal_emit(G_OBJECT(new_object), object_signals[OBJECT_READ_XML], 0, object_node, study_file, *perror_buf, perror_buf); g_free(version); xmlFreeDoc(doc); return new_object; } AmitkObject * amitk_object_copy(const AmitkObject * object) { AmitkObject * new_object; g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); g_signal_emit(G_OBJECT(object), object_signals[OBJECT_COPY],0, &new_object); return new_object; } void amitk_object_copy_in_place(AmitkObject * dest_object, const AmitkObject * src_object) { g_return_if_fail(AMITK_IS_OBJECT(src_object)); g_return_if_fail(AMITK_IS_OBJECT(dest_object)); g_signal_emit(G_OBJECT(dest_object), object_signals[OBJECT_COPY_IN_PLACE],0, src_object); return; } void amitk_object_set_name(AmitkObject * object, const gchar * new_name) { g_return_if_fail(AMITK_IS_OBJECT(object)); if (object->name != NULL) g_free(object->name); object->name = g_strdup(new_name); g_signal_emit(G_OBJECT(object), object_signals[OBJECT_NAME_CHANGED],0); return; } /* note, AMITK_SELECTION_ANY means any selections */ gboolean amitk_object_get_selected(const AmitkObject * object, const AmitkSelection which_selection) { AmitkSelection i_selection; gboolean return_val = FALSE; g_return_val_if_fail(AMITK_IS_OBJECT(object), FALSE); g_return_val_if_fail(which_selection >= 0, FALSE); g_return_val_if_fail(which_selection <= AMITK_SELECTION_ANY, FALSE); g_return_val_if_fail(which_selection != AMITK_SELECTION_NUM, FALSE); if (which_selection == AMITK_SELECTION_ANY) { for (i_selection=0; i_selection < AMITK_SELECTION_NUM; i_selection++) return_val = object->selected[i_selection] || return_val; } else return_val = object->selected[which_selection]; return return_val; } /* note, AMITK_SELECTION_ALL means all selections */ void amitk_object_set_selected(AmitkObject * object, const gboolean selection, const AmitkSelection which_selection) { AmitkSelection i_selection; GList * children; gboolean changed=FALSE; g_return_if_fail(AMITK_IS_OBJECT(object)); g_return_if_fail(which_selection >= 0); g_return_if_fail((which_selection < AMITK_SELECTION_NUM) || (which_selection == AMITK_SELECTION_ALL)); if (which_selection == AMITK_SELECTION_ALL) { for (i_selection=0; i_selection < AMITK_SELECTION_NUM; i_selection++) { if (object->selected[i_selection] != selection) { object->selected[i_selection] = selection; changed = TRUE; } } } else { if (object->selected[which_selection] != selection) { object->selected[which_selection] = selection; changed = TRUE; } } if (selection == FALSE) { /* propagate unselect to children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { amitk_object_set_selected(children->data, selection, which_selection); children = children->next; } } if (changed) { g_signal_emit(G_OBJECT(object), object_signals[OBJECT_SELECTION_CHANGED], 0); if (AMITK_OBJECT_PARENT(object) != NULL) { g_signal_emit(G_OBJECT(AMITK_OBJECT_PARENT(object)), object_signals[OBJECT_CHILD_SELECTION_CHANGED], 0); } } return; } void amitk_object_set_parent(AmitkObject * object,AmitkObject * parent) { gboolean ref_added = FALSE; g_return_if_fail(AMITK_IS_OBJECT(object)); g_return_if_fail(AMITK_IS_OBJECT(parent) || (parent == NULL)); if (object->parent != NULL) { amitk_object_ref(object); ref_added = TRUE; amitk_object_remove_child(object->parent, object); } if (parent != NULL) { amitk_object_add_child(parent, object); } if (ref_added == TRUE) amitk_object_unref(object); return; } void amitk_object_add_child(AmitkObject * object, AmitkObject * child) { g_return_if_fail(AMITK_IS_OBJECT(object)); g_return_if_fail(AMITK_IS_OBJECT(child)); /* check that it's not already in the list */ g_return_if_fail(g_list_find(object->children, child) == NULL); /* check that it doesn't already have a parent */ g_return_if_fail(AMITK_OBJECT_PARENT(child) == NULL); g_signal_emit(G_OBJECT(object), object_signals[OBJECT_ADD_CHILD], 0, child); return; } void amitk_object_add_children(AmitkObject * object, GList * children) { if (children == NULL) return; amitk_object_add_child(object, AMITK_OBJECT(children->data)); amitk_object_add_children(object, children->next); return; } gboolean amitk_object_remove_child(AmitkObject * object, AmitkObject * child) { g_return_val_if_fail(AMITK_IS_OBJECT(object), FALSE); g_return_val_if_fail(AMITK_IS_OBJECT(child), FALSE); /* check if it's not in the list */ g_return_val_if_fail(g_list_find(object->children, child) != NULL, FALSE); g_signal_emit(G_OBJECT(object), object_signals[OBJECT_REMOVE_CHILD], 0, child); return TRUE; } gboolean amitk_object_remove_children(AmitkObject * object, GList * children) { gboolean valid; g_return_val_if_fail(AMITK_IS_OBJECT(object), FALSE); if (children == NULL) return TRUE; valid = amitk_object_remove_children(object, children->next); valid = valid && amitk_object_remove_child(object, AMITK_OBJECT(children->data)); return valid; } /* returns the type of the given object */ gboolean amitk_object_compare_object_type(AmitkObject * object, AmitkObjectType type) { switch(type) { case AMITK_OBJECT_TYPE_STUDY: return AMITK_IS_STUDY(object); break; case AMITK_OBJECT_TYPE_FIDUCIAL_MARK: return AMITK_IS_FIDUCIAL_MARK(object); break; case AMITK_OBJECT_TYPE_DATA_SET: return AMITK_IS_DATA_SET(object); break; case AMITK_OBJECT_TYPE_ROI: return AMITK_IS_ROI(object); break; case AMITK_OBJECT_TYPE_VOLUME: return AMITK_IS_VOLUME(object); break; default: g_return_val_if_reached(FALSE); break; } } /* returns an unreferenced pointer goes up the tree from the given object, finding the first parent of type "type" returns NULL if no appropriate parent found */ AmitkObject * amitk_object_get_parent_of_type(AmitkObject * object, const AmitkObjectType type) { g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); if (AMITK_OBJECT_PARENT(object) == NULL) /* top node */ return NULL; else if (amitk_object_compare_object_type(AMITK_OBJECT_PARENT(object),type)) return AMITK_OBJECT_PARENT(object); else return amitk_object_get_parent_of_type(AMITK_OBJECT_PARENT(object), type); /* recurse */ } /* returns a referenced list of children of the given object which are of the given type. Will recurse if specified */ GList * amitk_object_get_children_of_type(AmitkObject * object, const AmitkObjectType type, const gboolean recurse) { GList * children; GList * return_objects=NULL; GList * children_objects; AmitkObject * child; g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); children = AMITK_OBJECT_CHILDREN(object); while(children != NULL) { child = AMITK_OBJECT(children->data); if (amitk_object_compare_object_type(child,type)) return_objects = g_list_append(return_objects, amitk_object_ref(child)); if (recurse) { /* get child's objects */ children_objects = amitk_object_get_children_of_type(AMITK_OBJECT(child), type, recurse); return_objects = g_list_concat(return_objects, children_objects); } children = children->next; } return return_objects; } /* indicates if any children of the given node has been selected */ gboolean amitk_object_selected_children(AmitkObject * object, const AmitkSelection which_selection, gboolean recurse) { GList * children; AmitkObject * child; g_return_val_if_fail(AMITK_IS_OBJECT(object), FALSE); children = AMITK_OBJECT_CHILDREN(object); while(children != NULL) { child = AMITK_OBJECT(children->data); if (amitk_object_get_selected(child, which_selection)) return TRUE; if (recurse) { /* check child's objects */ if (amitk_object_selected_children(AMITK_OBJECT(child), which_selection, recurse)) return TRUE; } children = children->next; } return FALSE; } /* returns a referenced list of selected objects that are children of the given node (usually the study object). Will recurse if specified*/ GList * amitk_object_get_selected_children(AmitkObject * object, const AmitkSelection which_selection, gboolean recurse) { GList * children; GList * return_objects=NULL; GList * children_objects; AmitkObject * child; g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); children = AMITK_OBJECT_CHILDREN(object); while(children != NULL) { child = AMITK_OBJECT(children->data); if (amitk_object_get_selected(child, which_selection)) return_objects = g_list_append(return_objects, amitk_object_ref(child)); if (recurse) { /* get child's objects */ children_objects = amitk_object_get_selected_children(AMITK_OBJECT(child), which_selection, recurse); return_objects = g_list_concat(return_objects, children_objects); } children = children->next; } return return_objects; } /* returns a referenced list of selected objects of type "type" that are children of the given node (usually the study object). Will recurse if specified*/ GList * amitk_object_get_selected_children_of_type(AmitkObject * object, const AmitkObjectType type, const AmitkSelection which_selection, gboolean recurse) { GList * children; GList * return_objects=NULL; GList * children_objects; AmitkObject * child; g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); children = AMITK_OBJECT_CHILDREN(object); while(children != NULL) { child = AMITK_OBJECT(children->data); if ((amitk_object_compare_object_type(child,type)) && (amitk_object_get_selected(child, which_selection))) return_objects = g_list_append(return_objects, amitk_object_ref(child)); if (recurse) { /* get child's objects */ children_objects = amitk_object_get_selected_children_of_type(AMITK_OBJECT(child), type, which_selection, recurse); return_objects = g_list_concat(return_objects, children_objects); } children = children->next; } return return_objects; } /* this function is used mainly so that I can debug referencing within amide */ gpointer amitk_object_ref(gpointer object) { g_return_val_if_fail(object != NULL, NULL); g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); return g_object_ref(object); } gpointer amitk_object_unref(gpointer object) { g_return_val_if_fail(object != NULL, NULL); g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); g_object_unref(object); return NULL; } /* returns a copy of a list of objects, with a reference added for each copy */ GList * amitk_objects_ref(GList * objects) { GList * return_list; if (objects == NULL) return NULL; return_list = amitk_objects_ref(objects->next); /* recurse */ amitk_object_ref(G_OBJECT(objects->data)); /* add ref to this item */ return_list = g_list_prepend(return_list, objects->data); return return_list; } /* unrefs the objects in the given list and frees the list */ GList * amitk_objects_unref(GList * objects) { AmitkObject * object; if (objects == NULL) return NULL; objects->next = amitk_objects_unref(objects->next); /* recurse */ g_return_val_if_fail(AMITK_IS_OBJECT(objects->data), NULL); object = objects->data; objects = g_list_remove(objects, object); /* should return NULL */ amitk_object_unref(object); return NULL; } gint amitk_objects_count(GList * objects) { gint count; if (objects == NULL) return 0; if (AMITK_IS_OBJECT(objects->data)) count = 1; else count = 0; /* count data sets that are children */ count += amitk_objects_count(AMITK_OBJECT_CHILDREN(objects->data)); /* add this count too the counts from the rest of the objects */ return count+amitk_objects_count(objects->next); } /* return a pointer (unreferenced) to the first amitk_object in the list with the given name */ AmitkObject * amitk_objects_find_object_by_name(GList * objects, const gchar * name) { AmitkObject * object; if (objects == NULL) return NULL; object = objects->data; if (AMITK_IS_OBJECT(object)) if (strcmp(AMITK_OBJECT_NAME(object), name) == 0) return object; return amitk_objects_find_object_by_name(objects->next, name); } /* goes through the two pairs of lists, and counts the number of names in list 1 that match a name in list 2 */ gint amitk_objects_count_pairs_by_name(GList * objects1, GList * objects2) { gint count=0; g_return_val_if_fail(objects1 != NULL, 0); g_return_val_if_fail(objects2 != NULL, 0); while (objects1 != NULL) { if (AMITK_IS_OBJECT(objects1->data)) if (amitk_objects_find_object_by_name(objects2, AMITK_OBJECT_NAME(objects1->data))) count++; objects1 = objects1->next; } return count; } /* returns a referenced list of objects of type "type" from the given list, will recurse if specified */ GList * amitk_objects_get_of_type(GList * objects, const AmitkObjectType type, const gboolean recurse) { GList * return_objects; GList * children_objects; if (objects == NULL) return NULL; /* recurse first */ return_objects = amitk_objects_get_of_type(objects->next, type, recurse); g_return_val_if_fail(AMITK_IS_OBJECT(objects->data), return_objects); if (amitk_object_compare_object_type(objects->data, type)) return_objects = g_list_append(return_objects, amitk_object_ref(objects->data)); if (recurse) { children_objects = amitk_objects_get_of_type(AMITK_OBJECT_CHILDREN(objects->data), type, recurse); return_objects = g_list_concat(return_objects, children_objects); } return return_objects; } gboolean amitk_objects_has_type(GList * objects, const AmitkObjectType type, const gboolean recurse) { GList * return_objects; return_objects = amitk_objects_get_of_type(objects, type, recurse); if (return_objects == NULL) return FALSE; amitk_objects_unref(return_objects); return TRUE; } void amitk_objects_write_xml(GList * objects, xmlNodePtr node_list, FILE * study_file) { gchar * object_filename=NULL;; guint64 location; guint64 size; if (objects == NULL) return; amitk_object_write_xml(objects->data, study_file, &object_filename, &location, &size); if (study_file == NULL) xmlNewChild(node_list, NULL, (xmlChar*) "object_file", (xmlChar *) object_filename); else xml_save_location_and_size(node_list, "object_location_and_size", location, size); if (object_filename != NULL) g_free(object_filename); /* and recurse */ amitk_objects_write_xml(objects->next, node_list, study_file); return; } GList * amitk_objects_read_xml(xmlNodePtr node_list, FILE * study_file, gchar **perror_buf) { GList * objects; AmitkObject * object; gchar * filename=NULL; guint64 location; guint64 size; if (node_list == NULL) return NULL; /* recurse */ objects = amitk_objects_read_xml(node_list->next, study_file, perror_buf); /* and add this node */ if (study_file == NULL) filename = xml_get_string(node_list, "object_file"); else xml_get_location_and_size(node_list, "object_location_and_size", &location, &size, perror_buf); object = amitk_object_read_xml(filename, study_file, location, size, perror_buf); if (object != NULL) objects = g_list_prepend(objects, object); if (filename != NULL) g_free(filename); return objects; } const gchar * amitk_object_type_get_name(const AmitkObjectType type) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_OBJECT_TYPE); enum_value = g_enum_get_value(enum_class, type); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_selection_get_name(const AmitkSelection type) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_SELECTION); enum_value = g_enum_get_value(enum_class, type); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_object.h000066400000000000000000000170031423227705100207330ustar00rootroot00000000000000/* amitk_object.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_OBJECT_H__ #define __AMITK_OBJECT_H__ #include "amitk_space.h" G_BEGIN_DECLS #define AMITK_TYPE_OBJECT (amitk_object_get_type ()) #define AMITK_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_OBJECT, AmitkObject)) #define AMITK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_OBJECT, AmitkObjectClass)) #define AMITK_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_OBJECT)) #define AMITK_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_OBJECT)) #define AMITK_OBJECT_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_OBJECT, AmitkObjectClass)) #define AMITK_OBJECT_CHILDREN(object) (AMITK_OBJECT(object)->children) #define AMITK_OBJECT_PARENT(object) (AMITK_OBJECT(object)->parent) #define AMITK_OBJECT_NAME(object) ((const gchar *) (AMITK_OBJECT(object)->name)) typedef struct _AmitkObjectClass AmitkObjectClass; typedef struct _AmitkObject AmitkObject; typedef enum { AMITK_OBJECT_TYPE_STUDY, AMITK_OBJECT_TYPE_DATA_SET, AMITK_OBJECT_TYPE_FIDUCIAL_MARK, AMITK_OBJECT_TYPE_ROI, AMITK_OBJECT_TYPE_VOLUME, AMITK_OBJECT_TYPE_NUM } AmitkObjectType; /* note that the numbered entries need to correspond to the enteries in AmitkViewMode */ typedef enum { AMITK_SELECTION_SELECTED_0, AMITK_SELECTION_SELECTED_1, AMITK_SELECTION_SELECTED_2, AMITK_SELECTION_NUM, AMITK_SELECTION_ANY, AMITK_SELECTION_ALL, } AmitkSelection; struct _AmitkObject { AmitkSpace space; gchar * name; gboolean selected[AMITK_SELECTION_NUM]; AmitkObject * parent; GList * children; GObject * dialog; }; struct _AmitkObjectClass { AmitkSpaceClass space_class; void (* object_name_changed) (AmitkObject * object); void (* object_selection_changed) (AmitkObject * object); void (* object_child_selection_changed) (AmitkObject * object); AmitkObject * (* object_copy) (const AmitkObject * object); void (* object_copy_in_place) (AmitkObject * dest_object, const AmitkObject * src_object); void (* object_write_xml) (const AmitkObject * object, xmlNodePtr nodes, FILE * study_file); gchar * (* object_read_xml) (AmitkObject * object, xmlNodePtr nodes, FILE * study_file, gchar * error_buf); void (* object_add_child) (AmitkObject * object, AmitkObject * child); void (* object_remove_child) (AmitkObject * object, AmitkObject * child); }; /* Application-level methods */ GType amitk_object_get_type (void); AmitkObject * amitk_object_new (void); void amitk_object_write_xml (AmitkObject * object, FILE * study_file, gchar ** output_filename, guint64 * location, guint64 * size); AmitkObject * amitk_object_read_xml (gchar * xml_filename, FILE * study_file, guint64 location, guint64 size, gchar ** perror_buf); AmitkObject * amitk_object_copy (const AmitkObject * object); void amitk_object_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); void amitk_object_set_name (AmitkObject * object, const gchar * new_name); gboolean amitk_object_get_selected (const AmitkObject * object, const AmitkSelection which_selection); void amitk_object_set_selected (AmitkObject * object, const gboolean selection, const AmitkSelection which_selection); #define amitk_object_select(obj, which) (amitk_object_set_selected((obj), (TRUE), (which))) #define amitk_object_unselect(obj, which) (amitk_object_set_selected((obj), (FALSE), (which))) void amitk_object_set_parent (AmitkObject * object, AmitkObject * parent); void amitk_object_add_child (AmitkObject * object, AmitkObject * child); void amitk_object_add_children (AmitkObject * object, GList * children); gboolean amitk_object_remove_child (AmitkObject * object, AmitkObject * child); gboolean amitk_object_remove_children (AmitkObject * object, GList * children); gboolean amitk_object_compare_object_type (AmitkObject * object, AmitkObjectType type); AmitkObject * amitk_object_get_parent_of_type (AmitkObject * object, const AmitkObjectType type); GList * amitk_object_get_children_of_type (AmitkObject * object, const AmitkObjectType type, const gboolean recurse); gboolean amitk_object_selected_children (AmitkObject * object, const AmitkSelection which_selection, gboolean recurse); GList * amitk_object_get_selected_children (AmitkObject * object, const AmitkSelection which_selection, const gboolean recurse); GList * amitk_object_get_selected_children_of_type (AmitkObject * object, const AmitkObjectType type, const AmitkSelection which_selection, const gboolean recurse); gpointer amitk_object_ref (gpointer object); gpointer amitk_object_unref (gpointer object); GList * amitk_objects_ref (GList * objects); GList * amitk_objects_unref (GList * objects); gint amitk_objects_count (GList * objects); AmitkObject * amitk_objects_find_object_by_name (GList * objects, const gchar * name); gint amitk_objects_count_pairs_by_name (GList * objects1, GList * objects2); GList * amitk_objects_get_of_type (GList * objects, const AmitkObjectType type, const gboolean recurse); gboolean amitk_objects_has_type (GList * objects, const AmitkObjectType type, const gboolean recurse); void amitk_objects_write_xml (GList * objects, xmlNodePtr node_list, FILE * study_file); GList * amitk_objects_read_xml (xmlNodePtr node_list, FILE * study_file, gchar **perror_buf); const gchar * amitk_object_type_get_name (const AmitkObjectType type); const gchar * amitk_selection_get_name (const AmitkSelection type); extern gchar * amide_data_file_xml_tag; extern gchar * amide_data_file_xml_start_tag; extern gchar * amide_data_file_xml_end_tag; G_END_DECLS #endif /* __AMITK_OBJECT_H__ */ amide-1.0.6/amide-current/src/amitk_object_dialog.c000066400000000000000000003221401423227705100222460ustar00rootroot00000000000000/* amitk_object_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapted from gtkcolorsel.c */ #include "amide_config.h" #include "amide.h" #include "amitk_marshal.h" #include "amitk_object_dialog.h" #include "amitk_study.h" #include "amitk_space_edit.h" #include "amitk_threshold.h" #include "amitk_window_edit.h" #include "amitk_common.h" #include "ui_common.h" #define AMITK_RESPONSE_REVERT 2 #define DIMENSION_STEP 0.2 static void object_dialog_class_init (AmitkObjectDialogClass *class); static void object_dialog_init (AmitkObjectDialog *object_dialog); static void object_dialog_destroy (GtkObject * object); static void object_dialog_construct(AmitkObjectDialog * dialog, AmitkObject * object, AmitkLayout layout); static void dialog_update_entries (AmitkObjectDialog * dialog); static void dialog_update_interpolation(AmitkObjectDialog * dialog); static void dialog_update_rendering(AmitkObjectDialog * dialog); static void dialog_update_conversion(AmitkObjectDialog * dialog); static void dialog_update_roi_sample_item(AmitkObjectDialog * dialog); static void dialog_response_cb (GtkDialog * dialog, gint response_id, gpointer data); static void dialog_change_interpolation_cb (GtkWidget * widget, gpointer data); static void dialog_change_rendering_cb (GtkWidget * widget, gpointer data); static void dialog_conversion_cb (GtkWidget * widget, gpointer data); static void dialog_set_view_center_to_origin_cb(GtkWidget * widget, gpointer data); static void dialog_aspect_ratio_cb (GtkWidget * widget, gpointer data); static void dialog_change_name_cb (GtkWidget * widget, gpointer data); static void dialog_change_creation_date_cb (GtkWidget * widget, gpointer data); static void dialog_change_scan_date_cb (GtkWidget * widget, gpointer data); static void dialog_change_subject_name_cb (GtkWidget * widget, gpointer data); static void dialog_change_subject_id_cb (GtkWidget * widget, gpointer data); static void dialog_change_subject_dob_cb (GtkWidget * widget, gpointer data); static void dialog_change_center_cb (GtkWidget * widget, gpointer data); static void dialog_change_dim_cb (GtkWidget * widget, gpointer data); static void dialog_change_voxel_size_cb (GtkWidget * widget, gpointer data); static void dialog_change_scale_factor_cb (GtkWidget * widget, gpointer data); static void dialog_change_dose_cb (GtkWidget * widget, gpointer data); static void dialog_change_weight_cb (GtkWidget * widget, gpointer data); static void dialog_change_cylinder_cb (GtkWidget * widget, gpointer data); static void dialog_change_scan_start_cb (GtkWidget * widget, gpointer data); static void dialog_change_frame_duration_cb (GtkWidget * widget, gpointer data); static void dialog_change_gate_time_cb (GtkWidget * widget, gpointer data); static void dialog_change_roi_type_cb (GtkWidget * widget, gpointer data); static void dialog_change_modality_cb (GtkWidget * widget, gpointer data); static void dialog_change_subject_orientation_cb(GtkWidget * widget, gpointer data); static void dialog_change_subject_sex_cb (GtkWidget * widget, gpointer data); static void dialog_change_dose_unit_cb (GtkWidget * widget, gpointer data); static void dialog_change_weight_unit_cb (GtkWidget * widget, gpointer data); static void dialog_change_cylinder_unit_cb (GtkWidget * widget, gpointer data); static void dialog_change_roi_width_cb (GtkWidget * widget, gpointer data); #ifdef AMIDE_LIBGNOMECANVAS_AA static void dialog_change_roi_transparency_cb (GtkWidget * widget, gpointer data); #else static void dialog_change_line_style_cb (GtkWidget * widget, gpointer data); static void dialog_change_fill_roi_cb (GtkWidget * widget, gpointer data); #endif static void dialog_change_layout_cb (GtkWidget * widget, gpointer data); static void dialog_change_panel_layout_cb (GtkWidget * widget, gpointer data); static void dialog_change_maintain_size_cb (GtkWidget * widget, gpointer data); static void dialog_change_target_empty_area_cb (GtkWidget * widget, gpointer data); static void dialog_specify_color_cb (GtkWidget * widget, gpointer data); static void dialog_change_color_cb (GtkWidget * widget, gpointer data); static GtkDialogClass *object_dialog_parent_class; GType amitk_object_dialog_get_type (void) { static GType object_dialog_type = 0; if (!object_dialog_type) { GTypeInfo object_dialog_info = { sizeof (AmitkObjectDialogClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) object_dialog_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkObjectDialog), 0, /* # preallocs */ (GInstanceInitFunc) object_dialog_init, NULL /* value table */ }; object_dialog_type = g_type_register_static(GTK_TYPE_DIALOG, "AmitkObjectDialog", &object_dialog_info, 0); } return object_dialog_type; } static void object_dialog_class_init (AmitkObjectDialogClass *klass) { GtkObjectClass *gtkobject_class; gtkobject_class = (GtkObjectClass*) klass; object_dialog_parent_class = g_type_class_peek_parent(klass); gtkobject_class->destroy = object_dialog_destroy; } static void object_dialog_destroy (GtkObject * object) { AmitkObjectDialog * dialog; g_return_if_fail (object != NULL); g_return_if_fail (AMITK_IS_OBJECT_DIALOG (object)); dialog = AMITK_OBJECT_DIALOG(object); if (dialog->object != NULL) { g_signal_handlers_disconnect_by_func(G_OBJECT(dialog->object), dialog_update_entries, dialog); g_signal_handlers_disconnect_by_func(G_OBJECT(dialog->object), dialog_update_interpolation, dialog); g_signal_handlers_disconnect_by_func(G_OBJECT(dialog->object), dialog_update_rendering, dialog); g_signal_handlers_disconnect_by_func(G_OBJECT(dialog->object), dialog_update_conversion, dialog); dialog->object->dialog = NULL; dialog->object = amitk_object_unref(dialog->object); } if (dialog->original_object != NULL) { #if AMIDE_DEBUG { gchar * temp_string; temp_string = g_strdup_printf(_("Copy of %s"), AMITK_OBJECT_NAME(dialog->original_object)); amitk_object_set_name(dialog->original_object,temp_string); g_free(temp_string); } #endif dialog->original_object = amitk_object_unref(dialog->original_object); } if (dialog->duration_spins != NULL) { g_free(dialog->duration_spins); dialog->duration_spins = NULL; } if (GTK_OBJECT_CLASS (object_dialog_parent_class)->destroy) (* GTK_OBJECT_CLASS (object_dialog_parent_class)->destroy) (object); } static void object_dialog_init (AmitkObjectDialog * dialog) { dialog->object = NULL; dialog->original_object = NULL; dialog->aspect_ratio = TRUE; dialog->duration_spins = NULL; return; } static void object_dialog_construct(AmitkObjectDialog * dialog, AmitkObject * object, AmitkLayout layout) { gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * label; GtkWidget * hseparator; GtkWidget * vseparator; GtkWidget * axis_indicator; GtkWidget * check_button; GtkWidget * notebook; GtkWidget * space_edit; GtkWidget * hbox; GtkWidget * image; GtkWidget * button; gint table_row; gint inner_table_row; gint table_column; AmitkAxis i_axis; guint i; gboolean immutables; gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_REVERT_TO_SAVED, AMITK_RESPONSE_REVERT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); /* create the temp object which will store the old info if we want revert */ dialog->original_object = amitk_object_copy(object); dialog->object = amitk_object_ref(object); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(dialog_response_cb), NULL); notebook = gtk_notebook_new(); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), notebook); gtk_widget_show(notebook); /* --------------------------- Basic info page --------------------------- */ /* start making the widgets for this dialog box */ packing_table = gtk_table_new(14,4,FALSE); label = gtk_label_new(_("Basic Info")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); gtk_widget_show(packing_table); /* widgets to change the object's name */ if (AMITK_IS_DATA_SET(object) ) label = gtk_label_new(_("Data Set Name:")); else label = gtk_label_new(_("Name:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->name_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->name_entry), TRUE); g_signal_connect(G_OBJECT(dialog->name_entry), "changed", G_CALLBACK(dialog_change_name_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table),dialog->name_entry,1,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->name_entry); table_row++; if (AMITK_IS_ROI(object)) { AmitkRoiType i_roi_type; AmitkRoiType type_start, type_end; /* widgets to change the object's type */ label = gtk_label_new(_("Type:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->roi_type_menu = gtk_combo_box_new_text(); switch(AMITK_ROI_TYPE(object)) { case AMITK_ROI_TYPE_ELLIPSOID: case AMITK_ROI_TYPE_CYLINDER: case AMITK_ROI_TYPE_BOX: type_start = 0; type_end = AMITK_ROI_TYPE_BOX; break; case AMITK_ROI_TYPE_ISOCONTOUR_2D: case AMITK_ROI_TYPE_ISOCONTOUR_3D: case AMITK_ROI_TYPE_FREEHAND_2D: case AMITK_ROI_TYPE_FREEHAND_3D: type_start = type_end = AMITK_ROI_TYPE(object); break; default: type_start = type_end = 0; g_error("unexpected case in %s at line %d\n", __FILE__, __LINE__); break; } for (i_roi_type=type_start; i_roi_type<=type_end; i_roi_type++) gtk_combo_box_append_text(GTK_COMBO_BOX(dialog->roi_type_menu), amitk_roi_type_get_name(i_roi_type)); if (type_start != type_end) g_signal_connect(G_OBJECT(dialog->roi_type_menu), "changed", G_CALLBACK(dialog_change_roi_type_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->roi_type_menu, 1,2, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->roi_type_menu); table_row++; gtk_widget_show(packing_table); } else if (AMITK_IS_DATA_SET(object)) { AmitkInterpolation i_interpolation; AmitkRendering i_rendering; AmitkConversion i_conversion; AmitkModality i_modality; AmitkDoseUnit i_dose_unit; AmitkWeightUnit i_weight_unit; AmitkCylinderUnit i_cylinder_unit; AmitkSubjectOrientation i_subject_orientation; AmitkSubjectSex i_subject_sex; /* widgets to change the date of the scan name */ label = gtk_label_new(_("Scan Date:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->scan_date_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->scan_date_entry), TRUE); g_signal_connect(G_OBJECT(dialog->scan_date_entry), "changed", G_CALLBACK(dialog_change_scan_date_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->scan_date_entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->scan_date_entry); /* widgets to change the object's modality */ label = gtk_label_new(_("Modality:")); gtk_table_attach(GTK_TABLE(packing_table), label, 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->modality_menu = gtk_combo_box_new_text(); for (i_modality=0; i_modalitymodality_menu), amitk_modality_get_name(i_modality)); g_signal_connect(G_OBJECT(dialog->modality_menu), "changed", G_CALLBACK(dialog_change_modality_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->modality_menu, 3,4, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->modality_menu); table_row++; /* widget to change the interpolation */ label = gtk_label_new(_("Interpolation Type:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(packing_table), hbox,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); for (i_interpolation = 0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) { if (i_interpolation == 0) dialog->interpolation_button[0] = gtk_radio_button_new(NULL); else dialog->interpolation_button[i_interpolation] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(dialog->interpolation_button[0])); switch (i_interpolation) { case AMITK_INTERPOLATION_NEAREST_NEIGHBOR: image = gtk_image_new_from_stock("amide_icon_interpolation_nearest_neighbor",GTK_ICON_SIZE_LARGE_TOOLBAR); break; case AMITK_INTERPOLATION_TRILINEAR: image = gtk_image_new_from_stock("amide_icon_interpolation_trilinear",GTK_ICON_SIZE_LARGE_TOOLBAR); break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } gtk_button_set_image(GTK_BUTTON(dialog->interpolation_button[i_interpolation]), image); gtk_box_pack_start(GTK_BOX(hbox), dialog->interpolation_button[i_interpolation], FALSE, FALSE, 3); gtk_widget_show(dialog->interpolation_button[i_interpolation]); gtk_widget_set_tooltip_text(dialog->interpolation_button[i_interpolation], amitk_interpolation_explanations[i_interpolation]); g_object_set_data(G_OBJECT(dialog->interpolation_button[i_interpolation]), "interpolation", GINT_TO_POINTER(i_interpolation)); g_signal_connect(G_OBJECT(dialog->interpolation_button[i_interpolation]), "clicked", G_CALLBACK(dialog_change_interpolation_cb), dialog); } /* widget to change the rendering */ label = gtk_label_new(_("Rendering Type:")); gtk_table_attach(GTK_TABLE(packing_table), label, 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->rendering_menu = gtk_combo_box_new_text(); /* gtk_widget_set_tooltip_text(dialog->rendering_menu, _(amitk_rendering_explanation)); combo box's (as of 2.24 at least, don't have functioning tool tips */ for (i_rendering = 0; i_rendering < AMITK_RENDERING_NUM; i_rendering++) gtk_combo_box_append_text(GTK_COMBO_BOX(dialog->rendering_menu), amitk_rendering_get_name(i_rendering)); g_signal_connect(G_OBJECT(dialog->rendering_menu), "changed", G_CALLBACK(dialog_change_rendering_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->rendering_menu, 3,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->rendering_menu); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; table_column=0; /* widgets to change the subject name associated with the data */ label = gtk_label_new(_("Subject Name:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->subject_name_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->subject_name_entry), TRUE); g_signal_connect(G_OBJECT(dialog->subject_name_entry), "changed", G_CALLBACK(dialog_change_subject_name_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->subject_name_entry,1,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->subject_name_entry); table_row++; /* widgets to change the id associated with the data */ label = gtk_label_new(_("Subject ID:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->subject_id_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->subject_id_entry), TRUE); g_signal_connect(G_OBJECT(dialog->subject_id_entry), "changed", G_CALLBACK(dialog_change_subject_id_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->subject_id_entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->subject_id_entry); /* widgets to change the subject's date of birth */ label = gtk_label_new(_("Subject DOB:")); gtk_table_attach(GTK_TABLE(packing_table), label, 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->subject_dob_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->subject_dob_entry), TRUE); g_signal_connect(G_OBJECT(dialog->subject_dob_entry), "changed", G_CALLBACK(dialog_change_subject_dob_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->subject_dob_entry,3,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->subject_dob_entry); table_row++; /* widgets to change the subject's orientation */ label = gtk_label_new(_("Subject Orientation:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->subject_orientation_menu = gtk_combo_box_new_text(); for (i_subject_orientation=0; i_subject_orientationsubject_orientation_menu), amitk_subject_orientation_get_name(i_subject_orientation)); g_signal_connect(G_OBJECT(dialog->subject_orientation_menu), "changed", G_CALLBACK(dialog_change_subject_orientation_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->subject_orientation_menu, 1,2, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->subject_orientation_menu); /* widgets to change the subject's sex (much easier in the virtual world than in real life) */ label = gtk_label_new(_("Subject Sex:")); gtk_table_attach(GTK_TABLE(packing_table), label, 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->subject_sex_menu = gtk_combo_box_new_text(); for (i_subject_sex=0; i_subject_sexsubject_sex_menu), amitk_subject_sex_get_name(i_subject_sex)); g_signal_connect(G_OBJECT(dialog->subject_sex_menu), "changed", G_CALLBACK(dialog_change_subject_sex_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->subject_sex_menu, 3,4, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->subject_sex_menu); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; table_column=0; /* widget to change the scaling factor */ label = gtk_label_new(_("Conversion Type:")); gtk_table_attach(GTK_TABLE(packing_table), label, table_column,table_column+1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); inner_table_row = table_row+1; for (i_conversion=0; i_conversion < AMITK_CONVERSION_NUM; i_conversion++) { if (i_conversion == 0) dialog->conversion_button[0] = gtk_radio_button_new_with_label(NULL, amitk_conversion_names[i_conversion]); else dialog->conversion_button[i_conversion] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(dialog->conversion_button[0]), amitk_conversion_names[i_conversion]); g_object_set_data(G_OBJECT(dialog->conversion_button[i_conversion]), "conversion", GINT_TO_POINTER(i_conversion)); gtk_table_attach(GTK_TABLE(packing_table), dialog->conversion_button[i_conversion], table_column,table_column+1, inner_table_row, inner_table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->conversion_button[i_conversion]); g_signal_connect(G_OBJECT(dialog->conversion_button[i_conversion]), "clicked", G_CALLBACK(dialog_conversion_cb), dialog); if (i_conversion == 0) inner_table_row+=2; else inner_table_row++; } table_row++; table_column++; label = gtk_label_new(_("Scaling Factor:")); gtk_table_attach(GTK_TABLE(packing_table), label, table_column,table_column+1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->scaling_factor_spin = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->scaling_factor_spin), FALSE); g_signal_connect(G_OBJECT(dialog->scaling_factor_spin), "value_changed", G_CALLBACK(dialog_change_scale_factor_cb), dialog); g_signal_connect(G_OBJECT(dialog->scaling_factor_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->scaling_factor_spin, table_column+1,table_column+2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->scaling_factor_spin); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 1, 5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* injected dose */ label = gtk_label_new(_("Injected Dose:")); gtk_table_attach(GTK_TABLE(packing_table), label, table_column,table_column+1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->dose_spin = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->dose_spin), FALSE); g_signal_connect(G_OBJECT(dialog->dose_spin), "value_changed", G_CALLBACK(dialog_change_dose_cb), dialog); g_signal_connect(G_OBJECT(dialog->dose_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->dose_spin, table_column+1,table_column+2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->dose_spin); /* injected dose units */ dialog->dose_unit_menu = gtk_combo_box_new_text(); for (i_dose_unit=0; i_dose_unitdose_unit_menu), amitk_dose_unit_names[i_dose_unit]); g_signal_connect(G_OBJECT(dialog->dose_unit_menu), "changed", G_CALLBACK(dialog_change_dose_unit_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->dose_unit_menu, table_column+2, table_column+3, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->dose_unit_menu); table_row++; /* subject weight */ label = gtk_label_new(_("Subject Weight:")); gtk_table_attach(GTK_TABLE(packing_table), label, table_column,table_column+1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->weight_spin = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->weight_spin), FALSE); g_signal_connect(G_OBJECT(dialog->weight_spin), "value_changed", G_CALLBACK(dialog_change_weight_cb), dialog); g_signal_connect(G_OBJECT(dialog->weight_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->weight_spin, table_column+1,table_column+2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->weight_spin); /* subject weight units */ dialog->weight_unit_menu = gtk_combo_box_new_text(); for (i_weight_unit=0; i_weight_unitweight_unit_menu), amitk_weight_unit_names[i_weight_unit]); g_signal_connect(G_OBJECT(dialog->weight_unit_menu), "changed", G_CALLBACK(dialog_change_weight_unit_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->weight_unit_menu, table_column+2, table_column+3, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->weight_unit_menu); table_row++; /* cylinder factor */ label = gtk_label_new(_("Cylinder Factor:")); gtk_table_attach(GTK_TABLE(packing_table), label, table_column,table_column+1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->cylinder_spin = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->cylinder_spin), FALSE); g_signal_connect(G_OBJECT(dialog->cylinder_spin), "value_changed", G_CALLBACK(dialog_change_cylinder_cb), dialog); g_signal_connect(G_OBJECT(dialog->cylinder_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->cylinder_spin, table_column+1,table_column+2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->cylinder_spin); /* cylinder factor units */ dialog->cylinder_unit_menu = gtk_combo_box_new_text(); for (i_cylinder_unit=0; i_cylinder_unitcylinder_unit_menu), amitk_cylinder_unit_names[i_cylinder_unit]); g_signal_connect(G_OBJECT(dialog->cylinder_unit_menu), "changed", G_CALLBACK(dialog_change_cylinder_unit_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->cylinder_unit_menu, table_column+2, table_column+3, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->cylinder_unit_menu); table_row++; dialog_update_interpolation(dialog); dialog_update_rendering(dialog); dialog_update_conversion(dialog); } else if (AMITK_IS_STUDY(object)) { /* widgets to change the study's creation date */ label = gtk_label_new(_("Creation Date:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->creation_date_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->creation_date_entry), TRUE); g_signal_connect(G_OBJECT(dialog->creation_date_entry), "changed", G_CALLBACK(dialog_change_creation_date_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), dialog->creation_date_entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->creation_date_entry); table_row++; } /* --------------------------- Center adjustment page --------------------------- notes: - shifting the center of an entire study doesn't mean anything, instead, the option is to change the view center */ /* keep this on page 1 for fiducial points */ if (AMITK_IS_FIDUCIAL_MARK(object)) { /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; } else { /* the next page of options */ packing_table = gtk_table_new(7,7,FALSE); table_row=0; if (AMITK_IS_STUDY(object)) label = gtk_label_new(_("View Center")); else label = gtk_label_new(_("Center")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); } if (AMITK_IS_STUDY(object)) label = gtk_label_new(_("View Center (mm from origin)")); else label = gtk_label_new(_("Center Location (mm from origin)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; /* location, and dimensions for data set's */ for (i_axis=0; i_axiscenter_spin[i_axis] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, DIMENSION_STEP); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->center_spin[i_axis]), FALSE); g_object_set_data(G_OBJECT(dialog->center_spin[i_axis]), "axis", GINT_TO_POINTER(i_axis)); g_signal_connect(G_OBJECT(dialog->center_spin[i_axis]), "value_changed", G_CALLBACK(dialog_change_center_cb), dialog); g_signal_connect(G_OBJECT(dialog->center_spin[i_axis]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->center_spin[i_axis],1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->center_spin[i_axis]); table_row++; } if (AMITK_IS_STUDY(object)) { button = gtk_button_new_with_label("Shift all objects so view center is origin"); gtk_table_attach(GTK_TABLE(packing_table), button, 0,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(dialog_set_view_center_to_origin_cb), object); gtk_widget_show(button); table_row++; } /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* a canvas to indicate which way is x, y, and z */ axis_indicator = ui_common_create_view_axis_indicator(layout); gtk_table_attach(GTK_TABLE(packing_table), axis_indicator,0,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(axis_indicator); table_row++; gtk_widget_show(packing_table); /* --------------------------- Voxel Size Page for Data Set's --------------------------- */ if (AMITK_IS_DATA_SET(object)) { /* the next page of options */ packing_table = gtk_table_new(4,2,FALSE); table_row=0; label = gtk_label_new(_("Voxel Size")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); label = gtk_label_new(_("Voxel Size (mm)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; for (i_axis=0; i_axisvoxel_size_spin[i_axis] = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, DIMENSION_STEP); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->voxel_size_spin[i_axis]), FALSE); g_object_set_data(G_OBJECT(dialog->voxel_size_spin[i_axis]), "axis", GINT_TO_POINTER(i_axis)); g_signal_connect(G_OBJECT(dialog->voxel_size_spin[i_axis]), "value_changed", G_CALLBACK(dialog_change_voxel_size_cb), dialog); g_signal_connect(G_OBJECT(dialog->voxel_size_spin[i_axis]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->voxel_size_spin[i_axis],1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->voxel_size_spin[i_axis]); table_row++; } check_button = gtk_check_button_new_with_label ("keep aspect ratio"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), dialog->aspect_ratio); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(dialog_aspect_ratio_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), check_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(check_button); table_row++; gtk_widget_show(packing_table); } /* --------------------------- Dimension adjustment page for ROI's notes: 3D Isocontours/Freehands have no adjustable dimensions 2D Isocontours/Freehands can have their z dimension adjusted --------------------------- */ if (AMITK_IS_ROI(object)) { if ((AMITK_ROI_TYPE(object) != AMITK_ROI_TYPE_ISOCONTOUR_3D) && (AMITK_ROI_TYPE(object) != AMITK_ROI_TYPE_FREEHAND_3D)) { /* the next page of options */ packing_table = gtk_table_new(4,2,FALSE); table_row=0; label = gtk_label_new(_("Dimensions")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); /* widgets to change the dimensions of the objects (in object's space) */ label = gtk_label_new(_("Dimensions (mm) wrt to ROI")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; for (i_axis=0; i_axisdimension_spin[i_axis] = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, DIMENSION_STEP); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->dimension_spin[i_axis]), FALSE); g_object_set_data(G_OBJECT(dialog->dimension_spin[i_axis]), "axis", GINT_TO_POINTER(i_axis)); g_signal_connect(G_OBJECT(dialog->dimension_spin[i_axis]), "value_changed", G_CALLBACK(dialog_change_dim_cb), dialog); g_signal_connect(G_OBJECT(dialog->dimension_spin[i_axis]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->dimension_spin[i_axis],1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->dimension_spin[i_axis]); table_row++; } } gtk_widget_show(packing_table); } } /* ---------------------------------------- Rotations page ---------------------------------------- notes: -fiducial points don't need to be rotated,as they're 0 dimensional */ if (!AMITK_IS_FIDUCIAL_MARK(object)) { label = gtk_label_new(_("Rotate")); space_edit = amitk_space_edit_new(object); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), space_edit, label); gtk_widget_show(space_edit); gtk_widget_show(label); } /* ---------------------------------------- Colormap/threshold page ---------------------------------------- */ if (AMITK_IS_DATA_SET(object)) { GtkWidget * threshold; label = gtk_label_new(_("Colormap/Threshold")); threshold = amitk_threshold_new(AMITK_DATA_SET(object), AMITK_THRESHOLD_BOX_LAYOUT, GTK_WINDOW(dialog), FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), threshold, label); gtk_widget_show(label); gtk_widget_show(threshold); } /* ---------------------------------------- Time page ---------------------------------------- */ if (AMITK_IS_DATA_SET(object)) { GtkWidget * secondary_table; GtkWidget * scrolled; /* start making the page to adjust time values */ label = gtk_label_new(_("Time/Gate")); packing_table = gtk_table_new(4,5,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); table_row=0; gtk_widget_show(label); /* scan start time..... */ label = gtk_label_new(_("Scan Start Time (s)")); gtk_table_attach(GTK_TABLE(packing_table),label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->start_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->start_spin), FALSE); g_signal_connect(GTK_OBJECT(dialog->start_spin), "value_changed", G_CALLBACK(dialog_change_scan_start_cb), dialog); g_signal_connect(G_OBJECT(dialog->start_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), dialog->start_spin,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->start_spin); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,0,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* frame duration(s).... */ label = gtk_label_new(_("Frame")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); label = gtk_label_new(_("Duration (s)")); gtk_table_attach(GTK_TABLE(packing_table), label, 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; /* make a scrolled area for the info */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); secondary_table = gtk_table_new(AMITK_DATA_SET_NUM_FRAMES(object),2,TRUE); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), secondary_table); gtk_widget_show(secondary_table); gtk_table_attach(GTK_TABLE(packing_table), scrolled, 0,2, table_row, table_row+1, 0, GTK_FILL|GTK_EXPAND, X_PADDING, Y_PADDING); /* get memory for the spin buttons */ dialog->duration_spins = g_try_new(GtkWidget *,AMITK_DATA_SET_NUM_FRAMES(object)); /* iterate throught the frames */ for (i=0; i< AMITK_DATA_SET_NUM_FRAMES(object); i++) { /* this frame's label */ temp_string = g_strdup_printf("%d", i); label = gtk_label_new(temp_string); g_free(temp_string); gtk_table_attach(GTK_TABLE(secondary_table), label, 0,1, i, i+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); /* and this frame's spin_button */ dialog->duration_spins[i] = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->duration_spins[i]), FALSE); gtk_editable_set_editable(GTK_EDITABLE(dialog->duration_spins[i]), TRUE); g_object_set_data(G_OBJECT(dialog->duration_spins[i]), "frame", GINT_TO_POINTER(i)); g_signal_connect(G_OBJECT(dialog->duration_spins[i]), "value_changed", G_CALLBACK(dialog_change_frame_duration_cb), dialog); g_signal_connect(G_OBJECT(dialog->duration_spins[i]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(secondary_table), dialog->duration_spins[i],1,2, i, i+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->duration_spins[i]); } gtk_widget_show(scrolled); /* a separator for clarity */ vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), vseparator,2,3, 0, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_show(vseparator); table_row=0; /* skip two rows to make things line up well */ table_row +=2; /* gate time(s).... */ label = gtk_label_new(_("Gate")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); label = gtk_label_new(_("Trigger Time (s)")); gtk_table_attach(GTK_TABLE(packing_table), label, 4,5, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; /* make a scrolled area for the info */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); secondary_table = gtk_table_new(AMITK_DATA_SET_NUM_GATES(object),2,TRUE); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), secondary_table); gtk_widget_show(secondary_table); gtk_table_attach(GTK_TABLE(packing_table), scrolled, 3,5, table_row, table_row+1, 0, GTK_FILL|GTK_EXPAND, X_PADDING, Y_PADDING); /* get memory for the spin buttons */ dialog->gate_spins = g_try_new(GtkWidget *,AMITK_DATA_SET_NUM_GATES(object)); /* iterate throught the gates */ for (i=0; i< AMITK_DATA_SET_NUM_GATES(object); i++) { /* this frame's label */ temp_string = g_strdup_printf("%d", i); label = gtk_label_new(temp_string); g_free(temp_string); gtk_table_attach(GTK_TABLE(secondary_table), label, 0,1, i, i+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); /* and this gates spin_button */ dialog->gate_spins[i] = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(dialog->gate_spins[i]), FALSE); gtk_editable_set_editable(GTK_EDITABLE(dialog->gate_spins[i]), TRUE); g_object_set_data(G_OBJECT(dialog->gate_spins[i]), "gate", GINT_TO_POINTER(i)); g_signal_connect(G_OBJECT(dialog->gate_spins[i]), "value_changed", G_CALLBACK(dialog_change_gate_time_cb), dialog); g_signal_connect(G_OBJECT(dialog->gate_spins[i]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(secondary_table), dialog->gate_spins[i],1,2, i, i+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->gate_spins[i]); } gtk_widget_show(scrolled); table_row++; gtk_widget_show(packing_table); } /* ---------------------------------------- Misc. Preferences Page ---------------------------------------- */ if (AMITK_IS_STUDY(object) || AMITK_IS_DATA_SET(object)) { packing_table = gtk_table_new(4,2,FALSE); if (AMITK_IS_STUDY(object)) label = gtk_label_new(_("ROI/View Preferences")); else /* AMITK_IS_DATA_SET */ label = gtk_label_new(_("Windowing Prefs")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); if (AMITK_IS_STUDY(object)) { ui_common_study_preferences_widgets(packing_table, table_row, &(dialog->roi_width_spin), &(dialog->roi_item), #ifdef AMIDE_LIBGNOMECANVAS_AA &(dialog->roi_transparency_spin), #else &(dialog->line_style_menu), &(dialog->fill_roi_button), #endif &(dialog->layout_button1), &(dialog->layout_button2), &(dialog->panel_layout_button1), &(dialog->panel_layout_button2), &(dialog->panel_layout_button3), &(dialog->maintain_size_button), &(dialog->target_size_spin)); g_signal_connect(G_OBJECT(dialog->roi_width_spin), "value_changed", G_CALLBACK(dialog_change_roi_width_cb), dialog); #ifdef AMIDE_LIBGNOMECANVAS_AA g_signal_connect(G_OBJECT(dialog->roi_transparency_spin), "value_changed", G_CALLBACK(dialog_change_roi_transparency_cb), dialog); #else g_signal_connect(G_OBJECT(dialog->line_style_menu), "changed", G_CALLBACK(dialog_change_line_style_cb), dialog); g_signal_connect(G_OBJECT(dialog->fill_roi_button), "toggled", G_CALLBACK(dialog_change_fill_roi_cb), dialog); #endif g_signal_connect(G_OBJECT(dialog->layout_button1), "clicked", G_CALLBACK(dialog_change_layout_cb), dialog); g_signal_connect(G_OBJECT(dialog->layout_button2), "clicked", G_CALLBACK(dialog_change_layout_cb), dialog); g_signal_connect(G_OBJECT(dialog->panel_layout_button1), "clicked", G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_connect(G_OBJECT(dialog->panel_layout_button2), "clicked", G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_connect(G_OBJECT(dialog->panel_layout_button3), "clicked", G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_connect(G_OBJECT(dialog->maintain_size_button), "toggled", G_CALLBACK(dialog_change_maintain_size_cb), dialog); g_signal_connect(G_OBJECT(dialog->target_size_spin), "value_changed", G_CALLBACK(dialog_change_target_empty_area_cb), dialog); } else if (AMITK_IS_DATA_SET(object)) { GtkWidget * windows_widget; GtkWidget * scrolled; scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); windows_widget = amitk_window_edit_new(AMITK_DATA_SET(object), NULL); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), windows_widget); gtk_widget_show(windows_widget); gtk_table_attach(GTK_TABLE(packing_table), scrolled, 0,4, table_row, table_row+1, 0, GTK_FILL|GTK_EXPAND, X_PADDING, Y_PADDING); gtk_widget_show(scrolled); } gtk_widget_show(packing_table); } /* ---------------------------------------- Specify Color Page ---------------------------------------- */ if (AMITK_IS_ROI(object) || AMITK_IS_FIDUCIAL_MARK(object)) { rgba_t color_rgba; GdkColor color_gdk; guint16 alpha_gdk; GtkWidget * color_sel; packing_table = gtk_table_new(2,2,FALSE); label = gtk_label_new(_("Color")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); check_button = gtk_check_button_new_with_label ("Specify Color"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), AMITK_IS_ROI(object) ? AMITK_ROI_SPECIFY_COLOR(object) : AMITK_FIDUCIAL_MARK_SPECIFY_COLOR(object)); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(dialog_specify_color_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), check_button,0,1, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(check_button); table_row++; color_rgba = AMITK_IS_ROI(object) ? AMITK_ROI_COLOR(object) : AMITK_FIDUCIAL_MARK_COLOR(object); color_gdk.red = color_rgba.r << 8; color_gdk.green = color_rgba.g << 8; color_gdk.blue = color_rgba.b << 8; alpha_gdk = color_rgba.a << 8; color_sel = gtk_color_selection_new(); gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(color_sel), TRUE); gtk_color_selection_set_has_palette(GTK_COLOR_SELECTION(color_sel), TRUE); gtk_color_selection_set_current_alpha(GTK_COLOR_SELECTION(color_sel), alpha_gdk); gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(color_sel), &color_gdk); g_signal_connect(G_OBJECT(color_sel), "color_changed", G_CALLBACK(dialog_change_color_cb), dialog); gtk_table_attach(GTK_TABLE(packing_table), color_sel, 0, 2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(color_sel); table_row++; gtk_widget_show(packing_table); } /* ---------------------------------------- Immutables Page: ---------------------------------------- */ immutables = FALSE; if (AMITK_IS_STUDY(object)) immutables = TRUE; else if (AMITK_IS_DATA_SET(object)) immutables = TRUE; else if (AMITK_IS_ROI(object)) { if (AMITK_ROI_TYPE_ISOCONTOUR(object)) immutables = TRUE; } if (immutables) { packing_table = gtk_table_new(12,5,FALSE); label = gtk_label_new(_("Immutables")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); gtk_widget_show(label); if (AMITK_IS_STUDY(object)) { label = gtk_label_new(_("Max-Min Voxel Dim")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->voxel_dim_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->voxel_dim_entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), dialog->voxel_dim_entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->voxel_dim_entry); table_row++; } else if (AMITK_IS_ROI(object)) { if (AMITK_ROI_TYPE_ISOCONTOUR(object)) { label = gtk_label_new(_("Isocontour Min Specified Value")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->isocontour_min_value_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->isocontour_min_value_entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), dialog->isocontour_min_value_entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->isocontour_min_value_entry); table_row++; label = gtk_label_new(_("Isocontour Max Specified Value")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); dialog->isocontour_max_value_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(dialog->isocontour_max_value_entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), dialog->isocontour_max_value_entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(dialog->isocontour_max_value_entry); table_row++; } } else if (AMITK_IS_DATA_SET(object)) { AmitkDim i_dim; GtkWidget * entry; gdouble memory_used; AmitkRawData * rd; gint prefix=0; rd = AMITK_DATA_SET_RAW_DATA(object); memory_used = amitk_raw_data_size_data_mem(rd); if ((memory_used/1024.0) > 1.0) { memory_used /= 1024.0; prefix=1; } if ((memory_used/1024.0) > 1.0) { memory_used /= 1024.0; prefix=2; } if ((memory_used/1024.0) > 1.0) { memory_used /= 1024.0; prefix=3; } /* how big in memory the raw data is */ switch(prefix) { case 3: label = gtk_label_new(_("Memory Used (GB):")); break; case 2: label = gtk_label_new(_("Memory Used (MB):")); break; case 1: label = gtk_label_new(_("Memory Used (KB):")); break; case 0: default: label = gtk_label_new(_("Memory Used (bytes):")); break; } gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%5.3f", memory_used); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* widget to tell you the internal data format */ label = gtk_label_new(_("Data Format:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), amitk_format_names[AMITK_DATA_SET_FORMAT(object)]); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,0,2, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* widget to tell you the scaling format */ label = gtk_label_new(_("Scale Format:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), amitk_scaling_menu_names[AMITK_DATA_SET_SCALING_TYPE(object)]); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,0,2, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* widgets to display the data set dimensions */ label = gtk_label_new(_("Data Set Dimensions (voxels)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; /**************/ for (i_dim=0; i_dim < AMITK_DIM_NUM; i_dim++) { label = gtk_label_new(amitk_dim_get_name(i_dim)); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%d", voxel_get_dim(AMITK_DATA_SET_DIM(object),i_dim)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; } /* a separator for clarity */ vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), vseparator,2,3, 0, table_row, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_show(vseparator); table_row=0; /* MRI parameters */ label = gtk_label_new(_("MRI Parameters")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,5, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; /* inversion time */ label = gtk_label_new(_("Inversion Time (ms):")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%f", AMITK_DATA_SET_INVERSION_TIME(object)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* echo time */ label = gtk_label_new(_("Echo Time (ms):")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%f", AMITK_DATA_SET_ECHO_TIME(object)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* b factor */ label = gtk_label_new(_("Diffusion B Value:")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%f", AMITK_DATA_SET_DIFFUSION_B_VALUE(object)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* diffusion direction */ label = gtk_label_new(_("Diffusion Direction:")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%5.3f %5.3f %5.3f", AMITK_DATA_SET_DIFFUSION_DIRECTION(object).x, AMITK_DATA_SET_DIFFUSION_DIRECTION(object).y, AMITK_DATA_SET_DIFFUSION_DIRECTION(object).z); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,3,5, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* additional parameters */ label = gtk_label_new(_("Misc. Parameters")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,5, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; /* series number */ label = gtk_label_new(_("Series Number:")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); temp_string = g_strdup_printf("%d", AMITK_DATA_SET_SERIES_NUMBER(object)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; /* dicom image type */ label = gtk_label_new(_("Dicom Image Type:")); gtk_table_attach(GTK_TABLE(packing_table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); entry = gtk_entry_new(); if (AMITK_DATA_SET_DICOM_IMAGE_TYPE(object) != NULL) gtk_entry_set_text(GTK_ENTRY(entry), AMITK_DATA_SET_DICOM_IMAGE_TYPE(object)); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(packing_table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(entry); table_row++; } gtk_widget_show(packing_table); } return; } static void dialog_update_entries(AmitkObjectDialog * dialog) { AmitkAxis i_axis; AmitkPoint center; gchar * temp_str; gint i; gboolean immutables; gboolean center_valid = TRUE; /* object name */ g_signal_handlers_block_by_func(G_OBJECT(dialog->name_entry),G_CALLBACK(dialog_change_name_cb), dialog); if (AMITK_OBJECT_NAME(dialog->object) != NULL) gtk_entry_set_text(GTK_ENTRY(dialog->name_entry), AMITK_OBJECT_NAME(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->name_entry), G_CALLBACK(dialog_change_name_cb), dialog); if (AMITK_IS_ROI(dialog->object)) { g_signal_handlers_block_by_func(G_OBJECT(dialog->roi_type_menu),G_CALLBACK(dialog_change_roi_type_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->roi_type_menu), AMITK_ROI_TYPE(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->roi_type_menu),G_CALLBACK(dialog_change_roi_type_cb), dialog); } else if (AMITK_IS_DATA_SET(dialog->object)) { g_signal_handlers_block_by_func(G_OBJECT(dialog->scan_date_entry),G_CALLBACK(dialog_change_scan_date_cb), dialog); gtk_entry_set_text(GTK_ENTRY(dialog->scan_date_entry), AMITK_DATA_SET_SCAN_DATE(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->scan_date_entry),G_CALLBACK(dialog_change_scan_date_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->subject_name_entry),G_CALLBACK(dialog_change_subject_name_cb), dialog); gtk_entry_set_text(GTK_ENTRY(dialog->subject_name_entry), AMITK_DATA_SET_SUBJECT_NAME(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->subject_name_entry),G_CALLBACK(dialog_change_subject_name_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->subject_id_entry),G_CALLBACK(dialog_change_subject_id_cb), dialog); gtk_entry_set_text(GTK_ENTRY(dialog->subject_id_entry), AMITK_DATA_SET_SUBJECT_ID(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->subject_id_entry),G_CALLBACK(dialog_change_subject_id_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->subject_dob_entry),G_CALLBACK(dialog_change_subject_dob_cb), dialog); gtk_entry_set_text(GTK_ENTRY(dialog->subject_dob_entry), AMITK_DATA_SET_SUBJECT_DOB(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->subject_dob_entry),G_CALLBACK(dialog_change_subject_dob_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->modality_menu),G_CALLBACK(dialog_change_modality_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->modality_menu), AMITK_DATA_SET_MODALITY(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->modality_menu),G_CALLBACK(dialog_change_modality_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->subject_orientation_menu),G_CALLBACK(dialog_change_subject_orientation_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->subject_orientation_menu), AMITK_DATA_SET_SUBJECT_ORIENTATION(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->subject_orientation_menu),G_CALLBACK(dialog_change_subject_orientation_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->subject_sex_menu),G_CALLBACK(dialog_change_subject_sex_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->subject_sex_menu), AMITK_DATA_SET_SUBJECT_SEX(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->subject_sex_menu),G_CALLBACK(dialog_change_subject_sex_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->scaling_factor_spin), G_CALLBACK(dialog_change_scale_factor_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->scaling_factor_spin), AMITK_DATA_SET_SCALE_FACTOR(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->scaling_factor_spin), G_CALLBACK(dialog_change_scale_factor_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->dose_spin), G_CALLBACK(dialog_change_dose_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->dose_spin), amitk_dose_unit_convert_to(AMITK_DATA_SET_INJECTED_DOSE(dialog->object), AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(dialog->object))); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->dose_spin), G_CALLBACK(dialog_change_dose_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->dose_unit_menu), G_CALLBACK(dialog_change_dose_unit_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->dose_unit_menu), AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->dose_unit_menu), G_CALLBACK(dialog_change_dose_unit_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->weight_spin), G_CALLBACK(dialog_change_weight_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->weight_spin), amitk_weight_unit_convert_to(AMITK_DATA_SET_SUBJECT_WEIGHT(dialog->object), AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(dialog->object))); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->weight_spin), G_CALLBACK(dialog_change_weight_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->weight_unit_menu), G_CALLBACK(dialog_change_weight_unit_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->weight_unit_menu), AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->weight_unit_menu), G_CALLBACK(dialog_change_weight_unit_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->cylinder_spin), G_CALLBACK(dialog_change_cylinder_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->cylinder_spin), amitk_cylinder_unit_convert_to(AMITK_DATA_SET_CYLINDER_FACTOR(dialog->object), AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(dialog->object))); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->cylinder_spin), G_CALLBACK(dialog_change_cylinder_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->cylinder_unit_menu), G_CALLBACK(dialog_change_cylinder_unit_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->cylinder_unit_menu), AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->cylinder_unit_menu), G_CALLBACK(dialog_change_cylinder_unit_cb), dialog); } else if (AMITK_IS_STUDY(dialog->object)) { g_signal_handlers_block_by_func(G_OBJECT(dialog->creation_date_entry),G_CALLBACK(dialog_change_creation_date_cb), dialog); gtk_entry_set_text(GTK_ENTRY(dialog->creation_date_entry), AMITK_STUDY_CREATION_DATE(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->creation_date_entry),G_CALLBACK(dialog_change_creation_date_cb), dialog); } if (AMITK_IS_VOLUME(dialog->object)) { if (AMITK_VOLUME_VALID(dialog->object)) center = amitk_volume_get_center(AMITK_VOLUME(dialog->object)); else center_valid = FALSE; } else if (AMITK_IS_STUDY(dialog->object)) { center = AMITK_STUDY_VIEW_CENTER(dialog->object); } else if (AMITK_IS_FIDUCIAL_MARK(dialog->object)) { center = AMITK_FIDUCIAL_MARK_GET(dialog->object); } else g_return_if_reached(); for (i_axis=0; i_axiscenter_spin[i_axis]), G_CALLBACK(dialog_change_center_cb), dialog); gtk_widget_set_sensitive(GTK_WIDGET(dialog->center_spin[i_axis]), center_valid); if (center_valid) gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->center_spin[i_axis]), point_get_component(center, i_axis)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->center_spin[i_axis]), G_CALLBACK(dialog_change_center_cb), dialog); if (AMITK_IS_DATA_SET(dialog->object)) { g_signal_handlers_block_by_func(G_OBJECT(dialog->voxel_size_spin[i_axis]), G_CALLBACK(dialog_change_voxel_size_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->voxel_size_spin[i_axis]), point_get_component(AMITK_DATA_SET_VOXEL_SIZE(dialog->object), i_axis)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->voxel_size_spin[i_axis]), G_CALLBACK(dialog_change_voxel_size_cb), dialog); } } if (AMITK_IS_ROI(dialog->object)) { if ((AMITK_ROI_TYPE(dialog->object) != AMITK_ROI_TYPE_ISOCONTOUR_3D) && (AMITK_ROI_TYPE(dialog->object) != AMITK_ROI_TYPE_FREEHAND_3D)) { for (i_axis=0; i_axisobject) != AMITK_ROI_TYPE_ISOCONTOUR_2D) && (AMITK_ROI_TYPE(dialog->object) != AMITK_ROI_TYPE_FREEHAND_2D)) || (i_axis == AMITK_AXIS_Z)) { g_signal_handlers_block_by_func(G_OBJECT(dialog->dimension_spin[i_axis]), G_CALLBACK(dialog_change_dim_cb), dialog); gtk_widget_set_sensitive(GTK_WIDGET(dialog->dimension_spin[i_axis]), center_valid); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->dimension_spin[i_axis]), point_get_component(AMITK_VOLUME_CORNER(dialog->object), i_axis)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->dimension_spin[i_axis]), G_CALLBACK(dialog_change_dim_cb), dialog); } } } } /* Preferences Page */ if (AMITK_IS_STUDY(dialog->object)) { dialog_update_roi_sample_item(dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->roi_width_spin), G_CALLBACK(dialog_change_roi_width_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->roi_width_spin), AMITK_STUDY_CANVAS_ROI_WIDTH(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->roi_width_spin), G_CALLBACK(dialog_change_roi_width_cb), dialog); #ifdef AMIDE_LIBGNOMECANVAS_AA g_signal_handlers_block_by_func(G_OBJECT(dialog->roi_transparency_spin), G_CALLBACK(dialog_change_roi_transparency_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->roi_transparency_spin), AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->roi_transparency_spin), G_CALLBACK(dialog_change_roi_transparency_cb), dialog); #else g_signal_handlers_block_by_func(G_OBJECT(dialog->line_style_menu), G_CALLBACK(dialog_change_line_style_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->line_style_menu), AMITK_STUDY_CANVAS_LINE_STYLE(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->line_style_menu), G_CALLBACK(dialog_change_line_style_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->fill_roi_button), G_CALLBACK(dialog_change_fill_roi_cb), dialog); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->fill_roi_button), AMITK_STUDY_CANVAS_FILL_ROI(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->fill_roi_button), G_CALLBACK(dialog_change_fill_roi_cb), dialog); #endif g_signal_handlers_block_by_func(G_OBJECT(dialog->layout_button1), G_CALLBACK(dialog_change_layout_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->layout_button2), G_CALLBACK(dialog_change_layout_cb), dialog); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->layout_button1), (AMITK_STUDY_CANVAS_LAYOUT(dialog->object) == AMITK_LAYOUT_LINEAR)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->layout_button2), (AMITK_STUDY_CANVAS_LAYOUT(dialog->object) == AMITK_LAYOUT_ORTHOGONAL)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->layout_button1), G_CALLBACK(dialog_change_layout_cb), dialog); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->layout_button2), G_CALLBACK(dialog_change_layout_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->panel_layout_button1), G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->panel_layout_button2), G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->panel_layout_button3), G_CALLBACK(dialog_change_panel_layout_cb), dialog); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->panel_layout_button1), (AMITK_STUDY_PANEL_LAYOUT(dialog->object) == AMITK_PANEL_LAYOUT_MIXED)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->panel_layout_button2), (AMITK_STUDY_PANEL_LAYOUT(dialog->object) == AMITK_PANEL_LAYOUT_LINEAR_X)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->panel_layout_button3), (AMITK_STUDY_PANEL_LAYOUT(dialog->object) == AMITK_PANEL_LAYOUT_LINEAR_Y)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->panel_layout_button1), G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->panel_layout_button2), G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->panel_layout_button3), G_CALLBACK(dialog_change_panel_layout_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->maintain_size_button), G_CALLBACK(dialog_change_maintain_size_cb), dialog); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->maintain_size_button), AMITK_STUDY_CANVAS_MAINTAIN_SIZE(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->maintain_size_button), G_CALLBACK(dialog_change_maintain_size_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(dialog->target_size_spin), G_CALLBACK(dialog_change_target_empty_area_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->target_size_spin), AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->target_size_spin), G_CALLBACK(dialog_change_target_empty_area_cb), dialog); } /* Immutables Page */ immutables = FALSE; if (AMITK_IS_STUDY(dialog->object)) immutables = TRUE; else if (AMITK_IS_DATA_SET(dialog->object)) immutables = TRUE; else if (AMITK_IS_ROI(dialog->object)) if (AMITK_ROI_TYPE_ISOCONTOUR(dialog->object)) immutables = TRUE; if (immutables) { if (AMITK_IS_STUDY(dialog->object)) { temp_str = g_strdup_printf("%f", AMITK_STUDY_VOXEL_DIM(dialog->object)); gtk_entry_set_text(GTK_ENTRY(dialog->voxel_dim_entry), temp_str); g_free(temp_str); } else if AMITK_IS_ROI(dialog->object) { if (AMITK_ROI_TYPE_ISOCONTOUR(dialog->object)) { temp_str = g_strdup_printf("%f", AMITK_ROI_ISOCONTOUR_MIN_VALUE(dialog->object)); gtk_entry_set_text(GTK_ENTRY(dialog->isocontour_min_value_entry), temp_str); g_free(temp_str); gtk_widget_set_sensitive(dialog->isocontour_min_value_entry, AMITK_ROI_ISOCONTOUR_RANGE(dialog->object) != AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX); temp_str = g_strdup_printf("%f", AMITK_ROI_ISOCONTOUR_MAX_VALUE(dialog->object)); gtk_entry_set_text(GTK_ENTRY(dialog->isocontour_max_value_entry), temp_str); g_free(temp_str); gtk_widget_set_sensitive(dialog->isocontour_max_value_entry, AMITK_ROI_ISOCONTOUR_RANGE(dialog->object) != AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN); } } else if (AMITK_IS_DATA_SET(dialog->object)) { g_signal_handlers_block_by_func(G_OBJECT(dialog->start_spin), G_CALLBACK(dialog_change_scan_start_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->start_spin), AMITK_DATA_SET_SCAN_START(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->start_spin), G_CALLBACK(dialog_change_scan_start_cb), dialog); /* iterate throught the frames */ for (i=0; i< AMITK_DATA_SET_NUM_FRAMES(dialog->object); i++) { g_signal_handlers_block_by_func(G_OBJECT(dialog->duration_spins[i]), G_CALLBACK(dialog_change_frame_duration_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->duration_spins[i]), amitk_data_set_get_frame_duration(AMITK_DATA_SET(dialog->object),i)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->duration_spins[i]), G_CALLBACK(dialog_change_frame_duration_cb), dialog); } /* iterate throught the gates */ for (i=0; i< AMITK_DATA_SET_NUM_GATES(dialog->object); i++) { g_signal_handlers_block_by_func(G_OBJECT(dialog->gate_spins[i]), G_CALLBACK(dialog_change_gate_time_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->gate_spins[i]), amitk_data_set_get_gate_time(AMITK_DATA_SET(dialog->object),i)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->gate_spins[i]), G_CALLBACK(dialog_change_gate_time_cb), dialog); } } } return; } /* set which toggle button is depressed */ static void dialog_update_interpolation(AmitkObjectDialog * dialog) { AmitkInterpolation i_interpolation; AmitkInterpolation interpolation; interpolation = AMITK_DATA_SET_INTERPOLATION(dialog->object); for (i_interpolation=0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) g_signal_handlers_block_by_func(G_OBJECT(dialog->interpolation_button[i_interpolation]), G_CALLBACK(dialog_change_interpolation_cb), dialog); /* need the button pressed to get the display to update correctly */ gtk_button_pressed(GTK_BUTTON(dialog->interpolation_button[interpolation])); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->interpolation_button[interpolation]),TRUE); for (i_interpolation=0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) g_signal_handlers_unblock_by_func(G_OBJECT(dialog->interpolation_button[i_interpolation]), G_CALLBACK(dialog_change_interpolation_cb), dialog); return; } /* set which combo box item is present */ static void dialog_update_rendering(AmitkObjectDialog * dialog) { g_signal_handlers_block_by_func(G_OBJECT(dialog->rendering_menu), G_CALLBACK(dialog_change_rendering_cb), dialog); gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->rendering_menu), AMITK_DATA_SET_RENDERING(dialog->object)); g_signal_handlers_unblock_by_func(G_OBJECT(dialog->rendering_menu), G_CALLBACK(dialog_change_rendering_cb), dialog); return; } static void dialog_update_conversion(AmitkObjectDialog * dialog) { AmitkConversion i_conversion; AmitkConversion conversion; conversion = AMITK_DATA_SET_CONVERSION(dialog->object); for (i_conversion=0; i_conversion < AMITK_CONVERSION_NUM; i_conversion++) g_signal_handlers_block_by_func(G_OBJECT(dialog->conversion_button[i_conversion]), G_CALLBACK(dialog_conversion_cb), dialog); /* need the button pressed to get the display to update correctly */ gtk_button_pressed(GTK_BUTTON(dialog->conversion_button[conversion])); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->conversion_button[conversion]),TRUE); for (i_conversion=0; i_conversion < AMITK_CONVERSION_NUM; i_conversion++) g_signal_handlers_unblock_by_func(G_OBJECT(dialog->conversion_button[i_conversion]), G_CALLBACK(dialog_conversion_cb), dialog); switch (conversion) { case AMITK_CONVERSION_PERCENT_ID_PER_CC: gtk_widget_set_sensitive(dialog->scaling_factor_spin, FALSE); gtk_widget_set_sensitive(dialog->dose_spin, TRUE); gtk_widget_set_sensitive(dialog->weight_spin, FALSE); gtk_widget_set_sensitive(dialog->cylinder_spin, TRUE); break; case AMITK_CONVERSION_SUV: gtk_widget_set_sensitive(dialog->scaling_factor_spin, FALSE); gtk_widget_set_sensitive(dialog->dose_spin, TRUE); gtk_widget_set_sensitive(dialog->weight_spin, TRUE); gtk_widget_set_sensitive(dialog->cylinder_spin, TRUE); break; case AMITK_CONVERSION_STRAIGHT: default: gtk_widget_set_sensitive(dialog->scaling_factor_spin, TRUE); gtk_widget_set_sensitive(dialog->dose_spin, FALSE); gtk_widget_set_sensitive(dialog->weight_spin, FALSE); gtk_widget_set_sensitive(dialog->cylinder_spin, FALSE); break; } } static void dialog_update_roi_sample_item(AmitkObjectDialog * dialog) { ui_common_update_sample_roi_item(dialog->roi_item, AMITK_STUDY_CANVAS_ROI_WIDTH(dialog->object), #ifdef AMIDE_LIBGNOMECANVAS_AA AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(dialog->object) #else AMITK_STUDY_CANVAS_LINE_STYLE(dialog->object) #endif ); return; } static void dialog_change_interpolation_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkInterpolation interpolation; interpolation = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"interpolation")); amitk_data_set_set_interpolation(AMITK_DATA_SET(dialog->object), interpolation); return; } static void dialog_change_rendering_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); amitk_data_set_set_rendering(AMITK_DATA_SET(dialog->object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } static void dialog_conversion_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkConversion conversion; conversion = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"conversion")); amitk_data_set_set_conversion(AMITK_DATA_SET(dialog->object), conversion); return; } static void dialog_set_view_center_to_origin_cb(GtkWidget * widget, gpointer data) { AmitkStudy * study = data; AmitkPoint shift; GList * objects; g_return_if_fail(AMITK_IS_STUDY(data)); /* move all children by the given amount */ objects = AMITK_OBJECT_CHILDREN(study); shift = point_neg(AMITK_STUDY_VIEW_CENTER(study)); while (objects != NULL) { amitk_space_shift_offset(AMITK_SPACE(objects->data), shift); objects = objects->next; } /* and reset the view center */ amitk_study_set_view_center(study, zero_point); return; } /* function called when the aspect ratio button gets clicked */ static void dialog_aspect_ratio_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog=data; dialog->aspect_ratio = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); return; } /* function called when the name of the roi has been changed */ static void dialog_change_name_cb(GtkWidget * widget, gpointer data) { gchar * new_name; AmitkObjectDialog * dialog = data; /* get the contents of the name entry box and save it */ new_name = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); amitk_object_set_name(dialog->object, new_name); g_free(new_name); return; } /* function called when the creation date of the study has been changed */ static void dialog_change_creation_date_cb(GtkWidget * widget, gpointer data) { gchar * new_date; AmitkObjectDialog * dialog = data; /* get the contents of the name entry box and save it */ new_date = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); amitk_study_set_creation_date(AMITK_STUDY(dialog->object), new_date); g_free(new_date); return; } /* function called when the scan date of the data set has been changed */ static void dialog_change_scan_date_cb(GtkWidget * widget, gpointer data) { gchar * new_date; AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* get the contents of the name entry box and save it */ new_date = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); amitk_data_set_set_scan_date(AMITK_DATA_SET(dialog->object), new_date); g_free(new_date); return; } /* function called when the subject name of the data set has been changed */ static void dialog_change_subject_name_cb(GtkWidget * widget, gpointer data) { gchar * new_name; AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* get the contents of the name entry box and save it */ new_name = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); amitk_data_set_set_subject_name(AMITK_DATA_SET(dialog->object), new_name); g_free(new_name); return; } /* function called when the subject id of the data set has been changed */ static void dialog_change_subject_id_cb(GtkWidget * widget, gpointer data) { gchar * new_id; AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* get the contents of the id entry box and save it */ new_id = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); amitk_data_set_set_subject_id(AMITK_DATA_SET(dialog->object), new_id); g_free(new_id); return; } /* function called when the subject date of birth of the volume has been changed */ static void dialog_change_subject_dob_cb(GtkWidget * widget, gpointer data) { gchar * new_dob; AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* get the contents of the name entry box and save it */ new_dob = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); amitk_data_set_set_subject_dob(AMITK_DATA_SET(dialog->object), new_dob); g_free(new_dob); return; } static void dialog_change_center_cb(GtkWidget * widget, gpointer data) { gdouble temp_val; AmitkAxis axis; AmitkPoint old_center; AmitkPoint new_center; AmitkObjectDialog * dialog=data; /* figure out which widget this is */ axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "axis")); if (AMITK_IS_VOLUME(dialog->object)) old_center = amitk_volume_get_center(AMITK_VOLUME(dialog->object)); /* in base coords */ else if (AMITK_IS_STUDY(dialog->object)) old_center = AMITK_STUDY_VIEW_CENTER(dialog->object); else if (AMITK_IS_FIDUCIAL_MARK(dialog->object)) old_center = AMITK_FIDUCIAL_MARK_GET(dialog->object); else g_return_if_reached(); new_center = old_center; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->center_spin[axis])); point_set_component(&new_center, axis, temp_val); if (AMITK_IS_STUDY(dialog->object)) amitk_study_set_view_center(AMITK_STUDY(dialog->object), new_center); else /* recalculate the object's offset based on the new dimensions/center/and axis */ amitk_space_shift_offset(AMITK_SPACE(dialog->object), point_sub(new_center, old_center)); dialog_update_entries(dialog); return; } static void dialog_change_dim_cb(GtkWidget * widget, gpointer data) { gdouble temp_val; AmitkAxis axis; AmitkPoint shift; AmitkPoint new_corner; AmitkPoint old_corner; AmitkCorners temp_corner; AmitkObjectDialog * dialog=data; /* figure out which widget this is */ axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "axis")); /* initialize the center and dimension variables based on the old roi info */ if (AMITK_IS_VOLUME(dialog->object)) new_corner = old_corner = AMITK_VOLUME_CORNER(dialog->object); /* in object's coords */ else g_return_if_reached(); temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->dimension_spin[axis])); point_set_component(&new_corner, axis, fabs(temp_val)); /* recalculate the object's offset based on the new dimensions/center/and axis */ if (AMITK_IS_ROI(dialog->object)) { temp_corner[0] = amitk_space_s2b(AMITK_SPACE(dialog->object), new_corner); temp_corner[1] = amitk_space_s2b(AMITK_SPACE(dialog->object), old_corner); shift = point_cmult(-0.5, point_sub(temp_corner[0], temp_corner[1])); } amitk_space_shift_offset(AMITK_SPACE(dialog->object), shift); /* reset the far corner */ if (AMITK_IS_ROI(dialog->object)) { amitk_volume_set_corner(AMITK_VOLUME(dialog->object), new_corner); if ((AMITK_ROI_TYPE(dialog->object) == AMITK_ROI_TYPE_ISOCONTOUR_2D) || (AMITK_ROI_TYPE(dialog->object) == AMITK_ROI_TYPE_FREEHAND_2D)) { AmitkPoint new_voxel_size = AMITK_ROI_VOXEL_SIZE(dialog->object); new_voxel_size.z = new_corner.z; amitk_roi_set_voxel_size(AMITK_ROI(dialog->object), new_voxel_size); } } dialog_update_entries(dialog); return; } static void dialog_change_voxel_size_cb(GtkWidget * widget, gpointer data) { gdouble temp_val; AmitkAxis start_axis, end_axis, axis; AmitkAxis i_axis; AmitkObjectDialog * dialog=data; AmitkPoint new_voxel_size=one_point; amide_real_t scale; AmitkPoint center; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* figure out which widget this is */ axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "axis")); new_voxel_size = AMITK_DATA_SET_VOXEL_SIZE(dialog->object); center = amitk_volume_get_center(AMITK_VOLUME(dialog->object)); /* which ones we need to change */ if (dialog->aspect_ratio) { start_axis = axis; end_axis = start_axis+1; } else { start_axis = 0; end_axis = AMITK_AXIS_NUM; } for (i_axis = start_axis; i_axis < end_axis; i_axis++) { temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->voxel_size_spin[i_axis])); if (temp_val > EPSILON) { /* can't be having negative/very small numbers */ switch(i_axis) { case AMITK_AXIS_X: if (dialog->aspect_ratio) { scale = temp_val/new_voxel_size.x; new_voxel_size.y = scale*new_voxel_size.y; new_voxel_size.z = scale*new_voxel_size.z; } new_voxel_size.x = temp_val; break; case AMITK_AXIS_Y: if (dialog->aspect_ratio) { scale = temp_val/new_voxel_size.y; new_voxel_size.x = scale*new_voxel_size.x; new_voxel_size.z = scale*new_voxel_size.z; } new_voxel_size.y = temp_val; break; case AMITK_AXIS_Z: if (dialog->aspect_ratio) { scale = temp_val/new_voxel_size.z; new_voxel_size.y = scale*new_voxel_size.y; new_voxel_size.x = scale*new_voxel_size.x; } new_voxel_size.z = temp_val; break; default: g_return_if_reached(); /* error */ break; } } } amitk_data_set_set_voxel_size(AMITK_DATA_SET(dialog->object), new_voxel_size); amitk_volume_set_center(AMITK_VOLUME(dialog->object), center); /* preserve center location */ dialog_update_entries(dialog); return; } static void dialog_change_scale_factor_cb(GtkWidget * widget, gpointer data) { gdouble temp_val; AmitkObjectDialog * dialog=data; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (fabs(temp_val) > EPSILON) { /* make sure it's a valid number and avoid zero */ amitk_data_set_set_scale_factor(AMITK_DATA_SET(dialog->object), temp_val); } dialog_update_entries(dialog); return; } static void dialog_change_dose_cb(GtkWidget * widget, gpointer data) { amide_data_t injected_dose; AmitkObjectDialog * dialog=data; injected_dose = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (injected_dose >= 0.0) { injected_dose = amitk_dose_unit_convert_from(injected_dose, AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(dialog->object)); amitk_data_set_set_injected_dose(AMITK_DATA_SET(dialog->object), injected_dose); } dialog_update_entries(dialog); return; } static void dialog_change_weight_cb(GtkWidget * widget, gpointer data) { amide_data_t subject_weight; AmitkObjectDialog * dialog=data; subject_weight = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); /* we allow zero, so that the user can put in a proxy for "I don't know" */ if (subject_weight >= 0.0) { subject_weight = amitk_weight_unit_convert_from(subject_weight, AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(dialog->object)); amitk_data_set_set_subject_weight(AMITK_DATA_SET(dialog->object), subject_weight); } dialog_update_entries(dialog); return; } static void dialog_change_cylinder_cb(GtkWidget * widget, gpointer data) { gdouble cylinder_factor; AmitkObjectDialog * dialog=data; cylinder_factor = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); /* make sure it's a valid number and avoid zero */ if (fabs(cylinder_factor) > EPSILON) { cylinder_factor = amitk_cylinder_unit_convert_from(cylinder_factor, AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(dialog->object)); amitk_data_set_set_cylinder_factor(AMITK_DATA_SET(dialog->object), cylinder_factor); } dialog_update_entries(dialog); return; } static void dialog_change_scan_start_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog=data; amitk_data_set_set_scan_start(AMITK_DATA_SET(dialog->object), gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget))); dialog_update_entries(dialog); return; } static void dialog_change_frame_duration_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog=data; guint i; i = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "frame")); amitk_data_set_set_frame_duration(AMITK_DATA_SET(dialog->object),i, gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget))); dialog_update_entries(dialog); return; } static void dialog_change_gate_time_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog=data; guint i; i = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "gate")); amitk_data_set_set_gate_time(AMITK_DATA_SET(dialog->object),i, gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget))); dialog_update_entries(dialog); return; } /* function to change an roi's type */ static void dialog_change_roi_type_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; amitk_roi_set_type(AMITK_ROI(dialog->object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } /* function called when the modality type of a data set gets changed */ static void dialog_change_modality_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); amitk_data_set_set_modality(AMITK_DATA_SET(dialog->object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } /* function called when the subject orientation of a data set gets changed */ static void dialog_change_subject_orientation_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* figure out which menu item called me */ amitk_data_set_set_subject_orientation(AMITK_DATA_SET(dialog->object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } /* function called when the subject sex of a data set gets changed */ static void dialog_change_subject_sex_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); /* figure out which menu item called me */ amitk_data_set_set_subject_sex(AMITK_DATA_SET(dialog->object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } /* function called when the displayed dose unit type of a data set gets changed */ static void dialog_change_dose_unit_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkDoseUnit dose_unit; amide_data_t injected_dose; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); dose_unit = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if (dose_unit != AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(dialog->object)) { injected_dose = amitk_dose_unit_convert_to(AMITK_DATA_SET_INJECTED_DOSE(dialog->object), AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(dialog->object)); injected_dose = amitk_dose_unit_convert_from(injected_dose, dose_unit); amitk_data_set_set_displayed_dose_unit(AMITK_DATA_SET(dialog->object), dose_unit); amitk_data_set_set_injected_dose(AMITK_DATA_SET(dialog->object), injected_dose); } return; } /* function called when the displayed weight unit type of a data set gets changed */ static void dialog_change_weight_unit_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkWeightUnit weight_unit; amide_data_t subject_weight; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); weight_unit = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if (weight_unit != AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(dialog->object)) { subject_weight = amitk_weight_unit_convert_to(AMITK_DATA_SET_SUBJECT_WEIGHT(dialog->object), AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(dialog->object)); subject_weight = amitk_weight_unit_convert_from(subject_weight, weight_unit); amitk_data_set_set_displayed_weight_unit(AMITK_DATA_SET(dialog->object), weight_unit); amitk_data_set_set_subject_weight(AMITK_DATA_SET(dialog->object), subject_weight); } return; } /* function called when the displayed cylinder unit type of a data set gets changed */ static void dialog_change_cylinder_unit_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkCylinderUnit cylinder_unit; amide_data_t cylinder_factor; g_return_if_fail(AMITK_IS_DATA_SET(dialog->object)); cylinder_unit = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if (cylinder_unit != AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(dialog->object)) { cylinder_factor = amitk_cylinder_unit_convert_to(AMITK_DATA_SET_CYLINDER_FACTOR(dialog->object), AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(dialog->object)); cylinder_factor = amitk_cylinder_unit_convert_from(cylinder_factor, cylinder_unit); amitk_data_set_set_displayed_cylinder_unit(AMITK_DATA_SET(dialog->object), cylinder_unit); amitk_data_set_set_cylinder_factor(AMITK_DATA_SET(dialog->object), cylinder_factor); } return; } static void dialog_change_roi_width_cb(GtkWidget * widget, gpointer data){ AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); amitk_study_set_canvas_roi_width(AMITK_STUDY(dialog->object), gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget))); return; } #ifdef AMIDE_LIBGNOMECANVAS_AA static void dialog_change_roi_transparency_cb(GtkWidget * widget, gpointer data){ AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); amitk_study_set_canvas_roi_transparency(AMITK_STUDY(dialog->object), gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget))); return; } #else static void dialog_change_line_style_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); amitk_study_set_canvas_line_style(AMITK_STUDY(dialog->object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } static void dialog_change_fill_roi_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); amitk_study_set_canvas_fill_roi(AMITK_STUDY(dialog->object), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } #endif static void dialog_change_layout_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkLayout new_layout; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); new_layout = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "layout")); amitk_study_set_canvas_layout(AMITK_STUDY(dialog->object),new_layout); return; } static void dialog_change_panel_layout_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; AmitkPanelLayout new_panel_layout; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); new_panel_layout = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "panel_layout")); amitk_study_set_panel_layout(AMITK_STUDY(dialog->object),new_panel_layout); return; } static void dialog_change_maintain_size_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); amitk_study_set_canvas_maintain_size(AMITK_STUDY(dialog->object), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void dialog_change_target_empty_area_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; g_return_if_fail(AMITK_IS_STUDY(dialog->object)); amitk_study_set_canvas_target_empty_area(AMITK_STUDY(dialog->object), gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget))); return; } static void dialog_specify_color_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; if (AMITK_IS_ROI(dialog->object)) amitk_roi_set_specify_color(AMITK_ROI(dialog->object), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); else if (AMITK_IS_FIDUCIAL_MARK(dialog->object)) amitk_fiducial_mark_set_specify_color(AMITK_FIDUCIAL_MARK(dialog->object), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); else g_return_if_reached(); return; } static void dialog_change_color_cb(GtkWidget * widget, gpointer data) { AmitkObjectDialog * dialog = data; rgba_t new_color; GdkColor color_gdk; guint16 alpha; gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(widget), &color_gdk); alpha = gtk_color_selection_get_current_alpha(GTK_COLOR_SELECTION(widget)); new_color.r = color_gdk.red >> 8; new_color.g = color_gdk.green >> 8; new_color.b = color_gdk.blue >> 8; new_color.a = alpha >> 8; if (AMITK_IS_ROI(dialog->object)) amitk_roi_set_color(AMITK_ROI(dialog->object), new_color); else if (AMITK_IS_FIDUCIAL_MARK(dialog->object)) amitk_fiducial_mark_set_color(AMITK_FIDUCIAL_MARK(dialog->object),new_color); else g_return_if_reached(); } /* function called when we hit the apply button */ static void dialog_response_cb(GtkDialog* dialog, gint response_id, gpointer data) { gboolean return_val; g_return_if_fail(AMITK_IS_OBJECT_DIALOG(dialog)); switch(response_id) { case AMITK_RESPONSE_REVERT: /* copy the old info on over */ amitk_object_copy_in_place(AMITK_OBJECT_DIALOG(dialog)->object, AMITK_OBJECT_DIALOG(dialog)->original_object); dialog_update_entries(AMITK_OBJECT_DIALOG(dialog)); break; case GTK_RESPONSE_HELP: if (AMITK_IS_DATA_SET(AMITK_OBJECT_DIALOG(dialog)->object)) amide_call_help("data-set-dialog"); else if (AMITK_IS_ROI(AMITK_OBJECT_DIALOG(dialog)->object)) amide_call_help("roi-dialog"); else if (AMITK_IS_FIDUCIAL_MARK(AMITK_OBJECT_DIALOG(dialog)->object)) amide_call_help("fiducial-marker-dialog"); else if (AMITK_IS_STUDY(AMITK_OBJECT_DIALOG(dialog)->object)) amide_call_help("study-dialog"); break; case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } GtkWidget* amitk_object_dialog_new (AmitkObject * object) { AmitkObjectDialog *dialog; gchar * temp_string; AmitkObject * study; g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); /* find study - use for the layout */ if (AMITK_IS_STUDY(object)) study = object; else study = amitk_object_get_parent_of_type(object, AMITK_OBJECT_TYPE_STUDY); /* unreferenced pointer */ g_return_val_if_fail(AMITK_IS_STUDY(study), NULL); if (object->dialog != NULL) { if (AMITK_IS_OBJECT_DIALOG(object->dialog)) return NULL; /* already modifying */ else if (AMITK_IS_THRESHOLD(object->dialog)) gtk_widget_destroy(GTK_WIDGET(object->dialog)); else g_return_val_if_reached(NULL); } dialog = g_object_new (AMITK_TYPE_OBJECT_DIALOG, NULL); object->dialog = G_OBJECT(dialog); object_dialog_construct(dialog, object, AMITK_STUDY_CANVAS_LAYOUT(study)); g_signal_connect_swapped(G_OBJECT(object), "space_changed", G_CALLBACK(dialog_update_entries), dialog); if (AMITK_IS_STUDY(object)) { g_signal_connect_swapped(G_OBJECT(object), "voxel_dim_or_zoom_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "view_center_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "canvas_roi_preference_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "canvas_general_preference_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "canvas_target_preference_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "canvas_layout_preference_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "panel_layout_preference_changed", G_CALLBACK(dialog_update_entries), dialog); } if (AMITK_IS_VOLUME(object)) { g_signal_connect_swapped(G_OBJECT(object), "volume_changed", G_CALLBACK(dialog_update_entries), dialog); } if (AMITK_IS_ROI(object)) { g_signal_connect_swapped(G_OBJECT(object), "roi_changed", G_CALLBACK(dialog_update_entries), dialog); } if (AMITK_IS_FIDUCIAL_MARK(object)) { g_signal_connect_swapped(G_OBJECT(object), "fiducial_mark_changed", G_CALLBACK(dialog_update_entries), dialog); } if (AMITK_IS_DATA_SET(object)) { g_signal_connect_swapped(G_OBJECT(object), "data_set_changed", G_CALLBACK(dialog_update_entries), dialog); g_signal_connect_swapped(G_OBJECT(object), "interpolation_changed", G_CALLBACK(dialog_update_interpolation), dialog); g_signal_connect_swapped(G_OBJECT(object), "rendering_changed", G_CALLBACK(dialog_update_rendering), dialog); g_signal_connect_swapped(G_OBJECT(object), "conversion_changed", G_CALLBACK(dialog_update_conversion), dialog); } /* fill in values */ dialog_update_entries(dialog); temp_string = g_strdup_printf(_("Modification Dialog: %s"),AMITK_OBJECT_NAME(object)); gtk_window_set_title (GTK_WINDOW (dialog), temp_string); g_free(temp_string); return GTK_WIDGET (dialog); } amide-1.0.6/amide-current/src/amitk_object_dialog.h000066400000000000000000000072331423227705100222560ustar00rootroot00000000000000/* amitk_object_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapated from gtkcolorsel.h */ #ifndef __AMITK_OBJECT_DIALOG_H__ #define __AMITK_OBJECT_DIALOG_H__ /* includes we always need with this widget */ #include #include #include "amitk_object.h" #include "amitk_data_set.h" G_BEGIN_DECLS /* ------------- Threshold---------- */ #define AMITK_TYPE_OBJECT_DIALOG (amitk_object_dialog_get_type ()) #define AMITK_OBJECT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_OBJECT_DIALOG, AmitkObjectDialog)) #define AMITK_OBJECT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLD, AmitkObjectDialogClass)) #define AMITK_IS_OBJECT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_OBJECT_DIALOG)) #define AMITK_IS_OBJECT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_OBJECT_DIALOG)) typedef struct _AmitkObjectDialog AmitkObjectDialog; typedef struct _AmitkObjectDialogClass AmitkObjectDialogClass; struct _AmitkObjectDialog { GtkDialog parent; AmitkObject * object; AmitkObject * original_object; gboolean aspect_ratio; GtkWidget * name_entry; GtkWidget * roi_type_menu; GtkWidget * scan_date_entry; GtkWidget * subject_name_entry; GtkWidget * subject_id_entry; GtkWidget * subject_dob_entry; GtkWidget * modality_menu; GtkWidget * subject_orientation_menu; GtkWidget * subject_sex_menu; GtkWidget * scaling_factor_spin; GtkWidget * dose_spin; GtkWidget * dose_unit_menu; GtkWidget * weight_spin; GtkWidget * weight_unit_menu; GtkWidget * cylinder_spin; GtkWidget * cylinder_unit_menu; GtkWidget * creation_date_entry; GtkWidget * interpolation_button[AMITK_INTERPOLATION_NUM]; GtkWidget * rendering_menu; GtkWidget * conversion_button[AMITK_CONVERSION_NUM]; GtkWidget * center_spin[AMITK_AXIS_NUM]; GtkWidget * voxel_size_spin[AMITK_AXIS_NUM]; GtkWidget * dimension_spin[AMITK_AXIS_NUM]; GtkWidget * start_spin; GtkWidget * * duration_spins; GtkWidget * * gate_spins; GtkWidget * isocontour_min_value_entry; GtkWidget * isocontour_max_value_entry; GtkWidget * voxel_dim_entry; /* study preferences */ GtkWidget * roi_width_spin; GnomeCanvasItem * roi_item; #ifdef AMIDE_LIBGNOMECANVAS_AA GtkWidget * roi_transparency_spin; #else GtkWidget * line_style_menu; GtkWidget * fill_roi_button; #endif GtkWidget * layout_button1; GtkWidget * layout_button2; GtkWidget * panel_layout_button1; GtkWidget * panel_layout_button2; GtkWidget * panel_layout_button3; GtkWidget * maintain_size_button; GtkWidget * target_size_spin; }; struct _AmitkObjectDialogClass { GtkDialogClass parent_class; }; GType amitk_object_dialog_get_type (void); GtkWidget* amitk_object_dialog_new (AmitkObject * object); G_END_DECLS #endif /* __AMITK_OBJECT_DIALOG_H__ */ amide-1.0.6/amide-current/src/amitk_point.c000066400000000000000000000626561423227705100206270ustar00rootroot00000000000000/* amitk_point.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amitk_point.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" const AmitkAxes base_axes = {{1.0,0.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0}}; GType amitk_point_get_type (void) { static GType our_type = 0; if (our_type == 0) our_type = g_boxed_type_register_static ("AmitkPoint", (GBoxedCopyFunc) amitk_point_copy, (GBoxedFreeFunc) amitk_point_free); return our_type; } AmitkPoint * amitk_point_copy(const AmitkPoint * point) { return (AmitkPoint *)g_memdup(point, sizeof(AmitkPoint)); } void amitk_point_free (AmitkPoint * point) { g_free (point); } AmitkPoint amitk_point_read_xml(xmlNodePtr nodes, gchar * descriptor, gchar **perror_buf) { gchar * temp_str; AmitkPoint return_rp; gint error=EOF; gchar * saved_locale; saved_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_NUMERIC,"POSIX"); temp_str = xml_get_string(nodes, descriptor); if (temp_str != NULL) { xml_convert_radix_to_local(temp_str); #if (SIZE_OF_AMIDE_REAL_T == 8) /* convert to doubles */ error = sscanf(temp_str, "%lf\t%lf\t%lf", &(return_rp.x), &(return_rp.y), &(return_rp.z)); #elif (SIZE_OF_AMIDE_REAL_T == 4) /* convert to float */ error = sscanf(temp_str, "%f\t%f\t%f", &(return_rp.x), &(return_rp.y), &(return_rp.z)); #else #error "Unknown size for SIZE_OF_AMIDE_REAL_T" #endif g_free(temp_str); } if ((temp_str == NULL) || (error == EOF)) { return_rp = zero_point; amitk_append_str_with_newline(perror_buf,_("Couldn't read value for %s, substituting [%5.3f %5.3f %5.3f]"), descriptor, return_rp.x, return_rp.y, return_rp.z); } setlocale(LC_NUMERIC, saved_locale); g_free(saved_locale); return return_rp; } void amitk_point_write_xml(xmlNodePtr node, gchar * descriptor, AmitkPoint point) { #ifdef OLD_WIN32_HACKS gchar temp_str[128]; #else gchar * temp_str; #endif gchar * saved_locale; saved_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_NUMERIC,"POSIX"); #ifdef OLD_WIN32_HACKS snprintf(temp_str, 128, "%10.9f\t%10.9f\t%10.9f", point.x,point.y,point.z); #else temp_str = g_strdup_printf("%10.9f\t%10.9f\t%10.9f",point.x, point.y,point.z); #endif xml_save_string(node, descriptor, temp_str); #ifndef OLD_WIN32_HACKS g_free(temp_str); #endif setlocale(LC_NUMERIC, saved_locale); g_free(saved_locale); return; } GType amitk_voxel_get_type (void) { static GType our_type = 0; if (our_type == 0) our_type = g_boxed_type_register_static ("AmitkVoxel", (GBoxedCopyFunc) amitk_voxel_copy, (GBoxedFreeFunc) amitk_voxel_free); return our_type; } AmitkVoxel * amitk_voxel_copy(const AmitkVoxel * voxel) { return (AmitkVoxel *)g_memdup(voxel, sizeof(AmitkVoxel)); } void amitk_voxel_free (AmitkVoxel * voxel) { g_free(voxel); } AmitkVoxel amitk_voxel_read_xml(xmlNodePtr nodes, gchar * descriptor, gchar **perror_buf) { gchar * temp_str; AmitkVoxel voxel; gint x,y,z,g,t; gint error=0; voxel = one_voxel; /* initialize */ temp_str = xml_get_string(nodes, descriptor); if (temp_str != NULL) { /* convert to a voxel */ error = sscanf(temp_str,"%d\t%d\t%d\t%d\t%d", &x,&y,&z, &g, &t); g_free(temp_str); voxel.x = x; voxel.y = y; voxel.z = z; voxel.g = g; voxel.t = t; } if ((temp_str == NULL) || (error == EOF)) { voxel = zero_voxel; amitk_append_str_with_newline(perror_buf,_("Couldn't read value for %s, substituting [%d %d %d %d %d]"), descriptor, voxel.x, voxel.y,voxel.z,voxel.g, voxel.t); } if (error < 5) { /* note, gate was added later, so if we only read 4, the 4th is most likely frames */ voxel.t = voxel.g; voxel.g = 1; amitk_append_str_with_newline(perror_buf, _("Couldn't read gate value for %s, substituting %d"), descriptor, voxel.g); } else if (error < 4) { voxel.t = 1; amitk_append_str_with_newline(perror_buf,_("Couldn't read frame value for %s, substituting %d"), descriptor, voxel.t); } return voxel; } void amitk_voxel_write_xml(xmlNodePtr node, gchar * descriptor, AmitkVoxel voxel) { gchar * temp_str; temp_str = g_strdup_printf("%d\t%d\t%d\t%d\t%d",voxel.x, voxel.y, voxel.z, voxel.g, voxel.t); xml_save_string(node, descriptor, temp_str); g_free(temp_str); return; } GType amitk_pixel_get_type (void) { static GType our_type = 0; if (our_type == 0) our_type = g_boxed_type_register_static ("AmitkPixel", (GBoxedCopyFunc) amitk_pixel_copy, (GBoxedFreeFunc) amitk_pixel_free); return our_type; } AmitkPixel * amitk_pixel_copy(const AmitkPixel * pixel) { return (AmitkPixel *)g_memdup(pixel, sizeof(AmitkPixel)); } void amitk_pixel_free (AmitkPixel * pixel) { g_free (pixel); } GType amitk_canvas_point_get_type (void) { static GType our_type = 0; if (our_type == 0) our_type = g_boxed_type_register_static ("AmitkCanvasPoint", (GBoxedCopyFunc) amitk_canvas_point_copy, (GBoxedFreeFunc) amitk_canvas_point_free); return our_type; } AmitkCanvasPoint * amitk_canvas_point_copy(const AmitkCanvasPoint * point) { return (AmitkCanvasPoint *)g_memdup(point, sizeof(AmitkCanvasPoint)); } void amitk_canvas_point_free (AmitkCanvasPoint * point) { g_free (point); } GType amitk_axes_get_type (void) { static GType our_type = 0; if (our_type == 0) our_type = g_boxed_type_register_static ("AmitkAxes", (GBoxedCopyFunc) amitk_axes_copy, (GBoxedFreeFunc) amitk_axes_free); return our_type; } AmitkAxes * amitk_axes_copy(const AmitkAxes * axes) { return (AmitkAxes *)g_memdup(axes, sizeof(AmitkAxes)); } void amitk_axes_free (AmitkAxes * axes) { g_free (axes); } void amitk_axes_copy_in_place(AmitkAxes dest_axes, const AmitkAxes src_axes) { AmitkAxis i_axis; for (i_axis=0; i_axis volume_corner.x) canvas_point.x = volume_corner.x; if (canvas_point.y > volume_corner.y) canvas_point.y = volume_corner.y; return canvas_point; } /* converts a point in the canvas's coordinate space to a gnome canvas event location */ AmitkCanvasPoint point_2_canvas_point(AmitkPoint volume_corner, gint width,gint height, gdouble x_offset, gdouble y_offset, AmitkPoint canvas_point) { AmitkCanvasPoint canvas_cpoint; canvas_cpoint.x = width * canvas_point.x/volume_corner.x + x_offset; canvas_cpoint.y = height * (volume_corner.y - canvas_point.y)/volume_corner.y + y_offset; return canvas_cpoint; } /* returns voxel1+voxel2 for voxelpoint structures */ AmitkVoxel voxel_add(const AmitkVoxel voxel1,const AmitkVoxel voxel2) { AmitkVoxel temp; temp.x = voxel1.x+voxel2.x; temp.y = voxel1.y+voxel2.y; temp.z = voxel1.z+voxel2.z; temp.g = voxel1.g+voxel2.g; temp.t = voxel1.t+voxel2.t; return temp; } /* returns voxel1-voxel2 for voxelpoint structures */ AmitkVoxel voxel_sub(const AmitkVoxel voxel1,const AmitkVoxel voxel2) { AmitkVoxel temp; temp.x = voxel1.x-voxel2.x; temp.y = voxel1.y-voxel2.y; temp.z = voxel1.z-voxel2.z; temp.g = voxel1.g-voxel2.g; temp.t = voxel1.t-voxel2.t; return temp; } /* returns voxel1 == voxel2 for voxelpoint structures */ gboolean voxel_equal(const AmitkVoxel voxel1, const AmitkVoxel voxel2) { return VOXEL_EQUAL(voxel1, voxel2); } /* returns the maximum dimension of the "box" defined by voxel1 */ amide_real_t voxel_max_dim(const AmitkVoxel voxel1) { AmitkPoint temp_point; VOXEL_TO_POINT(voxel1, one_point, temp_point); return point_mag(temp_point); } /* little utility function for debugging */ void voxel_print(gchar * message, const AmitkVoxel voxel) { g_print("%s\t%d\t%d\t%d\t%d\t%d\n",message, voxel.x, voxel.y, voxel.z, voxel.g, voxel.t); return; } amide_intpoint_t voxel_get_dim(const AmitkVoxel voxel, const AmitkDim which_dim) { switch(which_dim) { case AMITK_DIM_X: return voxel.x; break; case AMITK_DIM_Y: return voxel.y; break; case AMITK_DIM_Z: return voxel.z; break; case AMITK_DIM_G: return voxel.g; break; case AMITK_DIM_T: return voxel.t; break; default: g_error("inappropriate case in %s at %d\n", __FILE__, __LINE__); g_return_val_if_reached(0); } } void voxel_set_dim(AmitkVoxel * voxel, const AmitkDim which_dim, amide_intpoint_t value) { switch(which_dim) { case AMITK_DIM_X: voxel->x = value; break; case AMITK_DIM_Y: voxel->y = value; break; case AMITK_DIM_Z: voxel->z = value; break; case AMITK_DIM_G: voxel->g = value; break; case AMITK_DIM_T: voxel->t = value; break; default: g_error("inappropriate case in %s at %d\n", __FILE__, __LINE__); g_return_if_reached(); } } /* returns true if the realpoint is in the given box */ /* box first corner is zero point */ gboolean point_in_box(const AmitkPoint p, const AmitkPoint box_corner) { return (((p.z >= 0.0) && (p.z <= box_corner.z)) && ((p.y >= 0.0) && (p.y <= box_corner.y)) && ((p.x >= 0.0) && (p.x <= box_corner.x))); } /* returns true if the realpoint is in the elliptic cylinder, cylinder must be inline with the coordinate space center is in note: height is in the z direction, and radius.z isn't used for anything */ gboolean point_in_elliptic_cylinder(const AmitkPoint p, const AmitkPoint center, const amide_real_t height, const AmitkPoint radius) { AmitkPoint diff; diff.x = p.x-center.x; diff.y = p.y-center.y; return ((1.0 >= ((diff.x*diff.x)/(radius.x*radius.x) + (diff.y*diff.y)/(radius.y*radius.y))) && ((p.z >= (center.z-height/2.0)) && (p.z <= (center.z+height/2.0)))); } /* returns true if the realpoint is in the ellipsoid */ gboolean point_in_ellipsoid(const AmitkPoint p, const AmitkPoint center, const AmitkPoint radius) { AmitkPoint diff; diff = point_sub(p, center); return (1.0 >= (diff.x*diff.x)/(radius.x*radius.x) + (diff.y*diff.y)/(radius.y*radius.y) + (diff.z*diff.z)/(radius.z*radius.z)); } /* little utility function for debugging */ void point_print(gchar * message, const AmitkPoint point) { g_print("%s\t%5.3f\t%5.3f\t%5.3f\n",message, point.x, point.y, point.z); return; } /* rotate the vector on the given vector by the given rotation */ AmitkPoint point_rotate_on_vector(const AmitkPoint in, const AmitkPoint vector, const amide_real_t theta) { AmitkPoint return_vector; return_vector.x = (vector.x*vector.x + cos(theta) * (1.0 - vector.x*vector.x)) * in.x + (vector.x*vector.y*(1.0-cos(theta)) - vector.z * sin(theta)) * in.y + (vector.z*vector.x*(1.0-cos(theta)) + vector.y * sin(theta)) * in.z; return_vector.y = (vector.x*vector.y*(1.0-cos(theta)) + vector.z * sin(theta)) * in.x + (vector.y*vector.y + cos(theta) * (1.0 - vector.y*vector.y)) * in.y + (vector.y*vector.z*(1.0-cos(theta)) - vector.x * sin(theta)) * in.z; return_vector.z = (vector.z*vector.x*(1.0-cos(theta)) - vector.y * sin(theta)) * in.x + (vector.y*vector.z*(1.0-cos(theta)) + vector.x * sin(theta)) * in.y + (vector.z*vector.z + cos(theta) * (1.0 - vector.z*vector.z)) * in.z; return return_vector; } amide_real_t point_get_component(const AmitkPoint point, const AmitkAxis which_axis) { switch(which_axis) { case AMITK_AXIS_X: return point.x; break; case AMITK_AXIS_Y: return point.y; break; case AMITK_AXIS_Z: return point.z; break; default: g_return_val_if_reached(0.0); } } void point_set_component(AmitkPoint * point, const AmitkAxis which_axis, const amide_real_t value) { switch(which_axis) { case AMITK_AXIS_X: point->x = value; break; case AMITK_AXIS_Y: point->y = value; break; case AMITK_AXIS_Z: point->z = value; break; default: g_return_if_reached(); } return; } const gchar * amitk_view_get_name(const AmitkView view) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_VIEW); enum_value = g_enum_get_value(enum_class, view); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_dim_get_name(const AmitkDim dim) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_DIM); enum_value = g_enum_get_value(enum_class, dim); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_axis_get_name(const AmitkAxis axis) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_AXIS); enum_value = g_enum_get_value(enum_class, axis); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_length_unit_get_name(const AmitkLengthUnit length_unit) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_LENGTH_UNIT); enum_value = g_enum_get_value(enum_class, length_unit); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_point.h000066400000000000000000000343441423227705100206250ustar00rootroot00000000000000/* amitk_point.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_POINT_H__ #define __AMITK_POINT_H__ #ifndef _GNU_SOURCE #define _GNU_SOURCE /* use GNU extensions, i.e. NaN */ #endif #include #include "amitk_common.h" #include "amitk_type.h" #include "xml.h" G_BEGIN_DECLS typedef enum { AMITK_VIEW_TRANSVERSE, AMITK_VIEW_CORONAL, AMITK_VIEW_SAGITTAL, AMITK_VIEW_NUM } AmitkView; typedef enum { AMITK_AXIS_X, AMITK_AXIS_Y, AMITK_AXIS_Z, AMITK_AXIS_NUM } AmitkAxis; typedef enum { AMITK_DIM_X, AMITK_DIM_Y, AMITK_DIM_Z, AMITK_DIM_G, AMITK_DIM_T, AMITK_DIM_NUM } AmitkDim; typedef enum { AMITK_LENGTH_UNIT_MM, AMITK_LENGTH_UNIT_CM, AMITK_LENGTH_UNIT_M, AMITK_LENGTH_UNIT_INCHES, AMITK_LENGTH_UNIT_FEET, AMITK_LENGTH_UNIT_NUM } AmitkLengthUnit; #define AMITK_TYPE_POINT (amitk_point_get_type ()) #define AMITK_TYPE_VOXEL (amitk_voxel_get_type ()) #define AMITK_TYPE_PIXEL (amitk_pixel_get_type ()) #define AMITK_TYPE_CANVAS_POINT (amitk_canvas_point_get_type ()) #define AMITK_TYPE_AXES (amitk_axes_get_type ()) typedef struct _AmitkPoint AmitkPoint; typedef struct _AmitkVoxel AmitkVoxel; typedef struct _AmitkPixel AmitkPixel; typedef struct _AmitkCanvasPoint AmitkCanvasPoint; /* realpoint is a point in real (float) 3D space */ struct _AmitkPoint { amide_real_t x; amide_real_t y; amide_real_t z; }; GType amitk_point_get_type (void); AmitkPoint * amitk_point_copy(const AmitkPoint * point); void amitk_point_free (AmitkPoint * point); AmitkPoint amitk_point_read_xml(xmlNodePtr nodes, gchar * descriptor, gchar **perror_buf); void amitk_point_write_xml(xmlNodePtr node, gchar * descriptor, AmitkPoint point); /* voxel point is a point in voxel (integer) 4D space */ struct _AmitkVoxel { amide_intpoint_t x; amide_intpoint_t y; amide_intpoint_t z; amide_intpoint_t g; amide_intpoint_t t; }; GType amitk_voxel_get_type (void); AmitkVoxel * amitk_voxel_copy(const AmitkVoxel * voxel); void amitk_voxel_free (AmitkVoxel * voxel); AmitkVoxel amitk_voxel_read_xml(xmlNodePtr nodes, gchar * descriptor, gchar ** perror_buf); void amitk_voxel_write_xml(xmlNodePtr node, gchar * descriptor, AmitkVoxel voxel); /* pixel point is a point in pixel (integer) 2D space */ struct _AmitkPixel { amide_intpoint_t x; amide_intpoint_t y; }; GType amitk_pixel_get_type (void); AmitkPixel * amitk_pixel_copy(const AmitkPixel * pixel); void amitk_pixel_free (AmitkPixel * pixel); /* canvas point is a point in canvas (real) 2D space */ struct _AmitkCanvasPoint { amide_real_t x; amide_real_t y; }; GType amitk_canvas_point_get_type (void); AmitkCanvasPoint * amitk_canvas_point_copy(const AmitkCanvasPoint * point); void amitk_canvas_point_free (AmitkCanvasPoint * point); /* axes is an orthogonal set of axes in 3D space */ typedef AmitkPoint AmitkAxes[AMITK_AXIS_NUM]; GType amitk_axes_get_type(void); AmitkAxes * amitk_axes_copy(const AmitkAxes * axes); void amitk_axes_free (AmitkAxes * axes); void amitk_axes_copy_in_place(AmitkAxes dest_axes, const AmitkAxes src_axes); void amitk_axes_transpose(AmitkAxes axes); void amitk_axes_mult(const AmitkAxes const_axes1, const AmitkAxes const_axes2, AmitkAxes dest_axes); void amitk_axes_make_orthonormal(AmitkAxes axes); void amitk_axes_rotate_on_vector(AmitkAxes axes, AmitkPoint vector, amide_real_t theta); AmitkPoint amitk_axes_get_orthogonal_axis(const AmitkAxes axes, const AmitkView which_view, const AmitkLayout which_layout, const AmitkAxis which_axis); AmitkPoint amitk_axes_get_normal_axis (const AmitkAxes axes, const AmitkView which_view); /* corners of a box */ typedef AmitkPoint AmitkCorners[2]; GType amitk_corners_get_type (void); void amitk_corners_free (AmitkCorners * corners); AmitkCorners * amitk_corners_copy(const AmitkCorners * corners); /* Constants */ /* some reference values to remember when setting epsilon DBL_EPSILON 2.2204460492503131e-16 SQRT_DBL_EPSILON 1.4901161193847656e-08 FLT_EPSILON 1.1920928955078125e-07 SQRT_FLT_EPSILON 3.4526698300124393e-04 */ #define EPSILON 1.4901161193847656e-08 /* what's close enough to be equal.... */ #define CLOSE 0.0001 /* within 0.01% */ #define EMPTY 0.0 /* convert a gaussian's sigma value to FWHM, FWHM = sigma*2*sqrt(ln 4)*/ #define SIGMA_TO_FWHM 2.354820045 /* convert a guassian's sigma value to FWTM, FWTM = sigma*2*sqrt(ln 100)*/ #define SIGMA_TO_FWTM 4.291932053 /* Macros */ /* returns the boolean value of fp1==fp2 (within a factor of EPSILON) */ #define REAL_EQUAL(x,y) (fabs(x-y)/MAX(MAX(fabs(x),fabs(y)),DBL_MIN) < EPSILON) #define EQUAL_ZERO(fp1) (REAL_EQUAL((fp1), 0.0)) /* are two things pretty close */ #define REAL_CLOSE(x,y) (fabs(x-y)/MAX(MAX(fabs(x),fabs(y)),DBL_MIN) < CLOSE) /* returns the boolean value of point1==point2 (within a factor of EPSILON */ #define POINT_EQUAL(point1,point2) (REAL_EQUAL(((point1).x),((point2).x)) && \ REAL_EQUAL(((point1).y),((point2).y)) && \ REAL_EQUAL(((point1).z),((point2).z))) /* returns the boolean value of point1==point2 (within a factor of CLOSE */ #define POINT_CLOSE(point1,point2) (REAL_CLOSE(((point1).x),((point2).x)) && \ REAL_CLOSE(((point1).y),((point2).y)) && \ REAL_CLOSE(((point1).z),((point2).z))) #define VOXEL_EQUAL(voxel1,voxel2) (((voxel1).x == (voxel2).x) && \ ((voxel1).y == (voxel2).y) && \ ((voxel1).z == (voxel2).z) && \ ((voxel1).g == (voxel2).g) && \ ((voxel1).t == (voxel2).t)) /* figure out the real point that corresponds to the voxel coordinates */ #define VOXEL_TO_POINT(vox, vox_size, real) (((real).x = (((amide_real_t) (vox).x)+0.5) * (vox_size).x), \ ((real).y = (((amide_real_t) (vox).y)+0.5) * (vox_size).y), \ ((real).z = (((amide_real_t) (vox).z)+0.5) * (vox_size).z)) /* Macro to fill in a voxelpoint from a real coordinate. This does no error checking, the real coordinates have to be non-negative for this to work properly. The implementation use to use the "floor" function instead of casting to type amide_intpoint_t, but the floor function is really slow and this macro tends to get used a lot in tight loops. Casting to int should be equivalent for positive values. */ #define POINT_TO_VOXEL(real, vox_size, frame, gate, vox) (((vox).x = (amide_intpoint_t) ((real).x/(vox_size).x)), \ ((vox).y = (amide_intpoint_t) ((real).y/(vox_size).y)), \ ((vox).z = (amide_intpoint_t) ((real).z/(vox_size).z)), \ ((vox).g = (gate)), \ ((vox).t = (frame))) /* a version of the above that assumes vox.t and vox.g have already been set */ #define POINT_TO_VOXEL_COORDS_ONLY(real, vox_size, vox) (((vox).x = (amide_intpoint_t) ((real).x/(vox_size).x)), \ ((vox).y = (amide_intpoint_t) ((real).y/(vox_size).y)), \ ((vox).z = (amide_intpoint_t) ((real).z/(vox_size).z))) /* corner of the voxel in real coordinates */ #define VOXEL_CORNER(vox, vox_size, corner) (((corner).x = (((amide_real_t) (vox).x)) * (vox_size).x), \ ((corner).y = (((amide_real_t) (vox).y)) * (vox_size).y), \ ((corner).z = (((amide_real_t) (vox).z)) * (vox_size).z)) /* returned the maximum of point1 */ #define POINT_MAX(point1) (MAX( MAX((point1).x, (point1).y), (point1).z)) /* returns point1 dot point2" */ #define POINT_DOT_PRODUCT(point1,point2) ((point1).x*(point2).x+(point1).y*(point2).y+(point1).z*(point2).z) /* returns sqrt(point1 dot point1) */ #define POINT_MAGNITUDE(point) (sqrt(POINT_DOT_PRODUCT((point), (point)))) /* returns point2 = abs(point1)" */ #define POINT_ABS(point1,point2) ((point2).x = fabs((point1).x), \ (point2).y = fabs((point1).y), \ (point2).z = fabs((point1).z)) /* does point3=point1+point2 for realpoint structures */ #define POINT_ADD(point1,point2,point3) (((point3).x = (point1).x+(point2).x), \ ((point3).y = (point1).y+(point2).y), \ ((point3).z = (point1).z+(point2).z)) /* does point3=point1-point2 for realpoint structures */ #define POINT_SUB(point1,point2,point3) (((point3).x = (point1).x-(point2).x), \ ((point3).y = (point1).y-(point2).y), \ ((point3).z = (point1).z-(point2).z)) /* does point3=point1.*point2 for realpoint structures */ #define POINT_MULT(point1,point2,point3) (((point3).x = (point1).x*(point2).x), \ ((point3).y = (point1).y*(point2).y), \ ((point3).z = (point1).z*(point2).z)) /* does point3=point1./point2 for realpoint structures */ #define POINT_DIV(point1,point2,point3) (((point3).x = (point1).x/(point2).x), \ ((point3).y = (point1).y/(point2).y), \ ((point3).z = (point1).z/(point2).z)) /* does point3=fabs(point1-point2) for realpoint structures */ #define POINT_DIFF(point1,point2,point3) (((point3).x = fabs((point1).x-(point2).x)), \ ((point3).y = fabs((point1).y-(point2).y)), \ ((point3).z = fabs((point1).z-(point2).z))) /* does point3=cm*point1 for realpoint structures */ #define POINT_CMULT(cm,point1,point3) (((point3).x = (cm)*(point1).x), \ ((point3).y = (cm)*(point1).y), \ ((point3).z = (cm)*(point1).z)) #define POINT_CROSS_PRODUCT(point1, point2, point3) (((point3).x = (point1).y*(point2).z-(point1).z*(point2).y), \ ((point3).y = (point1).z*(point2).x-(point1).x*(point2).z), \ ((point3).z = (point1).x*(point2).y-(point1).y*(point2).x)) /* does point3=cm*point1+dm*point2 for realpoint structures */ #define POINT_MADD(cm,point1,dm,point2,point3) (((point3).x = cm*(point1).x+dm*(point2).x), \ ((point3).y = cm*(point1).y+dm*(point2).y), \ ((point3).z = cm*(point1).z+dm*(point2).z)) /* external functions */ /* note! the equivalent defines above are faster and should be used in any time critical spots */ AmitkPoint point_abs(const AmitkPoint point1); AmitkPoint point_neg(const AmitkPoint point1); AmitkPoint point_add(const AmitkPoint point1, const AmitkPoint point2); AmitkPoint point_sub(const AmitkPoint point1, const AmitkPoint point2); AmitkPoint point_mult(const AmitkPoint point1, const AmitkPoint point2); AmitkPoint point_div(const AmitkPoint point1, const AmitkPoint point2); AmitkPoint point_diff(const AmitkPoint point1, const AmitkPoint point2); AmitkPoint point_cmult(const amide_real_t cmult, const AmitkPoint point1); AmitkPoint point_cross_product(const AmitkPoint point1, const AmitkPoint point2); amide_real_t point_dot_product(const AmitkPoint point1, const AmitkPoint point2); amide_real_t point_mag(const AmitkPoint point1); amide_real_t point_min_dim(const AmitkPoint point1); amide_real_t point_max_dim(const AmitkPoint point1); AmitkCanvasPoint canvas_point_diff(const AmitkCanvasPoint point1,const AmitkCanvasPoint point2); AmitkCanvasPoint canvas_point_sub(const AmitkCanvasPoint point1,const AmitkCanvasPoint point2); AmitkCanvasPoint canvas_point_add(const AmitkCanvasPoint point1,const AmitkCanvasPoint point2); AmitkCanvasPoint canvas_point_cmult(const amide_real_t cmult, const AmitkCanvasPoint point1); amide_real_t canvas_point_dot_product(const AmitkCanvasPoint point1, const AmitkCanvasPoint point2); amide_real_t canvas_point_mag(const AmitkCanvasPoint point1); AmitkPoint canvas_point_2_point(AmitkPoint volume_corner, gint width, gint height, gdouble x_offset,gdouble y_offset, AmitkCanvasPoint canvas_cpoint); AmitkCanvasPoint point_2_canvas_point(AmitkPoint volume_corner, gint width,gint height, gdouble x_offset, gdouble y_offset, AmitkPoint canvas_point); AmitkVoxel voxel_add(const AmitkVoxel voxel1,const AmitkVoxel voxel2); AmitkVoxel voxel_sub(const AmitkVoxel voxel1,const AmitkVoxel voxel2); gboolean voxel_equal(const AmitkVoxel voxel1, const AmitkVoxel voxel2); amide_real_t voxel_max_dim(const AmitkVoxel voxel1); void voxel_print(gchar * message, const AmitkVoxel voxel); amide_intpoint_t voxel_get_dim(const AmitkVoxel voxel, const AmitkDim which_dim); void voxel_set_dim(AmitkVoxel * voxel, const AmitkDim which_dim, amide_intpoint_t value); gboolean point_in_box(const AmitkPoint p, const AmitkPoint box_corner); gboolean point_in_elliptic_cylinder(const AmitkPoint p, const AmitkPoint center, const amide_real_t height, const AmitkPoint radius); gboolean point_in_ellipsoid(const AmitkPoint p, const AmitkPoint center, const AmitkPoint radius); void point_print(gchar * message, const AmitkPoint point); AmitkPoint point_rotate_on_vector(const AmitkPoint in, const AmitkPoint vector, const amide_real_t theta); amide_real_t point_get_component(const AmitkPoint point, const AmitkAxis which_axis); void point_set_component(AmitkPoint * point, const AmitkAxis which_axis, const amide_real_t value); extern const AmitkPoint zero_point; #define ONE_POINT {1.0,1.0,1.0} extern const AmitkPoint one_point; extern const AmitkPoint ten_point; extern const AmitkVoxel zero_voxel; #define ONE_VOXEL {1,1,1,1,1} extern const AmitkVoxel one_voxel; extern const AmitkAxes base_axes; const gchar * amitk_view_get_name(const AmitkView view); const gchar * amitk_dim_get_name(const AmitkDim dim); const gchar * amitk_axis_get_name(const AmitkAxis axis); const gchar * amitk_length_unit_get_name(const AmitkLengthUnit length_unit); G_END_DECLS #endif /* __AMITK_POINT_H__ */ amide-1.0.6/amide-current/src/amitk_preferences.c000066400000000000000000000411511423227705100217620ustar00rootroot00000000000000/* amitk_preferences.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amide.h" #include "amide_gconf.h" #include "amitk_preferences.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "amitk_data_set.h" #define GCONF_AMIDE_ROI "ROI" #define GCONF_AMIDE_CANVAS "CANVAS" #define GCONF_AMIDE_MISC "MISC" #define GCONF_AMIDE_DATASETS "DATASETS" #define GCONF_AMIDE_WINDOWS "WINDOWS" enum { DATA_SET_PREFERENCES_CHANGED, STUDY_PREFERENCES_CHANGED, MISC_PREFERENCES_CHANGED, LAST_SIGNAL }; static void preferences_class_init (AmitkPreferencesClass *klass); static void preferences_init (AmitkPreferences *object); static void preferences_finalize (GObject *object); static GObjectClass * parent_class; static guint preferences_signals[LAST_SIGNAL]; /* external variables */ const gchar * amitk_which_default_directory_names[] = { N_("None"), N_("Specified Directory"), N_("Working Directory") }; GType amitk_preferences_get_type(void) { static GType preferences_type = 0; if (!preferences_type) { static const GTypeInfo preferences_info = { sizeof (AmitkPreferencesClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) preferences_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkPreferences), 0, /* n_preallocs */ (GInstanceInitFunc) preferences_init, NULL /* value table */ }; preferences_type = g_type_register_static (G_TYPE_OBJECT, "AmitkPreferences", &preferences_info, 0); } return preferences_type; } static void preferences_class_init (AmitkPreferencesClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent(class); gobject_class->finalize = preferences_finalize; preferences_signals[DATA_SET_PREFERENCES_CHANGED] = g_signal_new ("data_set_preferences_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkPreferencesClass, data_set_preferences_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); preferences_signals[STUDY_PREFERENCES_CHANGED] = g_signal_new ("study_preferences_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkPreferencesClass, study_preferences_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); preferences_signals[MISC_PREFERENCES_CHANGED] = g_signal_new ("misc_preferences_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkPreferencesClass, misc_preferences_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void preferences_init (AmitkPreferences * preferences) { gchar * temp_str; AmitkLimit i_limit; AmitkWindow i_window; AmitkModality i_modality; /* load in saved preferences */ preferences->canvas_roi_width = amide_gconf_get_int_with_default(GCONF_AMIDE_ROI,"Width", AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_WIDTH); #ifdef AMIDE_LIBGNOMECANVAS_AA preferences->canvas_roi_transparency = amide_gconf_get_float_with_default(GCONF_AMIDE_ROI,"Transparency", AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_TRANSPARENCY); #else preferences->canvas_line_style = amide_gconf_get_int_with_default(GCONF_AMIDE_ROI,"LineStyle",AMITK_PREFERENCES_DEFAULT_CANVAS_LINE_STYLE); preferences->canvas_fill_roi = amide_gconf_get_bool_with_default(GCONF_AMIDE_ROI,"FillIsocontour", AMITK_PREFERENCES_DEFAULT_CANVAS_FILL_ROI); #endif preferences->canvas_layout = amide_gconf_get_int_with_default(GCONF_AMIDE_CANVAS,"Layout", AMITK_PREFERENCES_DEFAULT_CANVAS_LAYOUT); preferences->canvas_maintain_size = amide_gconf_get_bool_with_default(GCONF_AMIDE_CANVAS,"MaintainSize", AMITK_PREFERENCES_DEFAULT_CANVAS_MAINTAIN_SIZE); preferences->canvas_target_empty_area = amide_gconf_get_int_with_default(GCONF_AMIDE_CANVAS,"TargetEmptyArea", AMITK_PREFERENCES_DEFAULT_CANVAS_TARGET_EMPTY_AREA); preferences->panel_layout = amide_gconf_get_int_with_default(GCONF_AMIDE_CANVAS,"PanelLayout", AMITK_PREFERENCES_DEFAULT_PANEL_LAYOUT); preferences->warnings_to_console = amide_gconf_get_bool_with_default(GCONF_AMIDE_MISC,"WarningsToConsole", AMITK_PREFERENCES_DEFAULT_WARNINGS_TO_CONSOLE); preferences->prompt_for_save_on_exit = amide_gconf_get_bool_with_default(GCONF_AMIDE_MISC,"PromptForSaveOnExit", AMITK_PREFERENCES_DEFAULT_PROMPT_FOR_SAVE_ON_EXIT); preferences->which_default_directory = amide_gconf_get_int_with_default(GCONF_AMIDE_MISC,"WhichDefaultDirectory", AMITK_PREFERENCES_DEFAULT_WHICH_DEFAULT_DIRECTORY); preferences->default_directory = amide_gconf_get_string_with_default(GCONF_AMIDE_MISC,"DefaultDirectory", AMITK_PREFERENCES_DEFAULT_DEFAULT_DIRECTORY); for (i_modality=0; i_modalitycolor_table[i_modality] = amide_gconf_get_int_with_default(GCONF_AMIDE_DATASETS,temp_str, amitk_modality_default_color_table[i_modality]); g_free(temp_str); } for (i_window = 0; i_window < AMITK_WINDOW_NUM; i_window++) for (i_limit = 0; i_limit < AMITK_LIMIT_NUM; i_limit++) { temp_str = g_strdup_printf("%s-%s", amitk_window_get_name(i_window), amitk_limit_get_name(i_limit)); preferences->window[i_window][i_limit] = amide_gconf_get_float_with_default(GCONF_AMIDE_WINDOWS,temp_str, amitk_window_default[i_window][i_limit]); } preferences->threshold_style = amide_gconf_get_int_with_default(GCONF_AMIDE_DATASETS,"ThresholdStyle", AMITK_PREFERENCES_DEFAULT_THRESHOLD_STYLE); preferences->dialog = NULL; return; } static void preferences_finalize (GObject *object) { // AmitkPreferences * preferences = AMITK_PREFERENCES(object); G_OBJECT_CLASS (parent_class)->finalize (object); } AmitkPreferences * amitk_preferences_new (void) { AmitkPreferences * preferences; preferences = g_object_new(amitk_preferences_get_type(), NULL); return preferences; } void amitk_preferences_set_canvas_roi_width(AmitkPreferences * preferences, gint roi_width) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (roi_width < AMITK_PREFERENCES_MIN_ROI_WIDTH) roi_width = AMITK_PREFERENCES_MIN_ROI_WIDTH; if (roi_width > AMITK_PREFERENCES_MAX_ROI_WIDTH) roi_width = AMITK_PREFERENCES_MAX_ROI_WIDTH; if (AMITK_PREFERENCES_CANVAS_ROI_WIDTH(preferences) != roi_width) { preferences->canvas_roi_width = roi_width; amide_gconf_set_int(GCONF_AMIDE_ROI,"Width", roi_width); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } #ifdef AMIDE_LIBGNOMECANVAS_AA void amitk_preferences_set_canvas_roi_transparency(AmitkPreferences * preferences, gdouble roi_transparency) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); g_return_if_fail(roi_transparency >= 0.0); g_return_if_fail(roi_transparency <= 1.0); if (AMITK_PREFERENCES_CANVAS_ROI_TRANSPARENCY(preferences) != roi_transparency) { preferences->canvas_roi_transparency = roi_transparency; amide_gconf_set_float(GCONF_AMIDE_ROI,"Transparency", roi_transparency); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } #else void amitk_preferences_set_canvas_line_style(AmitkPreferences * preferences, GdkLineStyle line_style) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_CANVAS_LINE_STYLE(preferences) != line_style) { preferences->canvas_line_style = line_style; amide_gconf_set_int(GCONF_AMIDE_ROI,"LineStyle",line_style); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_canvas_fill_roi(AmitkPreferences * preferences, gboolean fill_roi) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_CANVAS_FILL_ROI(preferences) != fill_roi) { preferences->canvas_fill_roi = fill_roi; amide_gconf_set_bool(GCONF_AMIDE_ROI,"FillIsocontour",fill_roi); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } #endif void amitk_preferences_set_canvas_layout(AmitkPreferences * preferences, AmitkLayout layout) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_CANVAS_LAYOUT(preferences) != layout) { preferences->canvas_layout = layout; amide_gconf_set_int(GCONF_AMIDE_CANVAS,"Layout", layout); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_canvas_maintain_size(AmitkPreferences * preferences, gboolean maintain_size) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_CANVAS_MAINTAIN_SIZE(preferences) != maintain_size) { preferences->canvas_maintain_size = maintain_size; amide_gconf_set_bool(GCONF_AMIDE_CANVAS,"MaintainSize",maintain_size); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; }; void amitk_preferences_set_canvas_target_empty_area(AmitkPreferences * preferences, gint target_empty_area) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); /* sanity checks */ if (target_empty_area < AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA) target_empty_area = AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA; if (target_empty_area > AMITK_PREFERENCES_MAX_TARGET_EMPTY_AREA) target_empty_area = AMITK_PREFERENCES_MAX_TARGET_EMPTY_AREA; if (AMITK_PREFERENCES_CANVAS_TARGET_EMPTY_AREA(preferences) != target_empty_area) { preferences->canvas_target_empty_area = target_empty_area; amide_gconf_set_int(GCONF_AMIDE_CANVAS,"TargetEmptyArea", target_empty_area); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_panel_layout(AmitkPreferences * preferences, AmitkPanelLayout panel_layout) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_PANEL_LAYOUT(preferences) != panel_layout) { preferences->panel_layout = panel_layout; amide_gconf_set_int(GCONF_AMIDE_CANVAS,"PanelLayout", panel_layout); g_signal_emit(G_OBJECT(preferences), preferences_signals[STUDY_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_warnings_to_console(AmitkPreferences * preferences, gboolean new_value) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_WARNINGS_TO_CONSOLE(preferences) != new_value) { preferences->warnings_to_console = new_value; amide_gconf_set_bool(GCONF_AMIDE_MISC,"WarningsToConsole",new_value); g_signal_emit(G_OBJECT(preferences), preferences_signals[MISC_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_prompt_for_save_on_exit(AmitkPreferences * preferences, gboolean new_value) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_PROMPT_FOR_SAVE_ON_EXIT(preferences) != new_value) { preferences->prompt_for_save_on_exit = new_value; amide_gconf_set_bool(GCONF_AMIDE_MISC,"PromptForSaveOnExit",new_value); g_signal_emit(G_OBJECT(preferences), preferences_signals[MISC_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_which_default_directory(AmitkPreferences * preferences, AmitkWhichDefaultDirectory new_value) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_WHICH_DEFAULT_DIRECTORY(preferences) != new_value) { preferences->which_default_directory = new_value; amide_gconf_set_int(GCONF_AMIDE_MISC,"WhichDefaultDirectory",new_value); g_signal_emit(G_OBJECT(preferences), preferences_signals[MISC_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_default_directory(AmitkPreferences * preferences, const gchar * new_directory) { gboolean different=FALSE; g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (((AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences) == NULL) && (new_directory != NULL)) || ((AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences) != NULL) && (new_directory == NULL))) different=TRUE; else if ((AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences) != NULL) && (new_directory != NULL)) if (strcmp(AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences), new_directory) != 0) different=TRUE; if (different) { if (preferences->default_directory != NULL) g_free(preferences->default_directory); if (new_directory != NULL) preferences->default_directory = g_strdup(new_directory); amide_gconf_set_string(GCONF_AMIDE_MISC,"DefaultDirectory", new_directory); g_signal_emit(G_OBJECT(preferences), preferences_signals[MISC_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_color_table(AmitkPreferences * preferences, AmitkModality modality, AmitkColorTable color_table) { gchar * temp_string; g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); g_return_if_fail((modality >= 0) && (modality < AMITK_MODALITY_NUM)); g_return_if_fail((color_table >= 0) && (color_table < AMITK_COLOR_TABLE_NUM)); if (AMITK_PREFERENCES_COLOR_TABLE(preferences,modality) != color_table) { preferences->color_table[modality] = color_table; temp_string = g_strdup_printf("DefaultColorTable%s", amitk_modality_get_name(modality)); amide_gconf_set_int(GCONF_AMIDE_DATASETS,temp_string, color_table); g_free(temp_string); g_signal_emit(G_OBJECT(preferences), preferences_signals[DATA_SET_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_default_window(AmitkPreferences * preferences, const AmitkWindow window, const AmitkLimit limit, const amide_data_t value) { gchar * temp_string; g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); g_return_if_fail((window >= 0) && (window < AMITK_WINDOW_NUM)); g_return_if_fail((limit >= 0) && (limit < AMITK_LIMIT_NUM)); if (!REAL_EQUAL(AMITK_PREFERENCES_WINDOW(preferences, window, limit), value)) { preferences->window[window][limit] = value; temp_string = g_strdup_printf("%s-%s", amitk_window_get_name(window), amitk_limit_get_name(limit)); amide_gconf_set_float(GCONF_AMIDE_WINDOWS,temp_string,value); g_free(temp_string); g_signal_emit(G_OBJECT(preferences), preferences_signals[DATA_SET_PREFERENCES_CHANGED], 0); } return; } void amitk_preferences_set_threshold_style(AmitkPreferences * preferences, const AmitkThresholdStyle threshold_style) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); if (AMITK_PREFERENCES_THRESHOLD_STYLE(preferences) != threshold_style) { preferences->threshold_style = threshold_style; amide_gconf_set_int(GCONF_AMIDE_DATASETS,"ThresholdStyle", threshold_style); g_signal_emit(G_OBJECT(preferences), preferences_signals[DATA_SET_PREFERENCES_CHANGED], 0); } } void amitk_preferences_set_dialog(AmitkPreferences * preferences, GtkWidget * dialog) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); preferences->dialog = dialog; } /* conviencence function */ void amitk_preferences_set_file_chooser_directory(AmitkPreferences * preferences, GtkWidget * file_chooser) { g_return_if_fail(AMITK_IS_PREFERENCES(preferences)); g_return_if_fail(GTK_IS_FILE_CHOOSER(file_chooser)); switch(AMITK_PREFERENCES_WHICH_DEFAULT_DIRECTORY(preferences)) { case AMITK_WHICH_DEFAULT_DIRECTORY_SPECIFIED: if (AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences) != NULL) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), AMITK_PREFERENCES_DEFAULT_DIRECTORY(preferences)); break; case AMITK_WHICH_DEFAULT_DIRECTORY_WORKING: gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), ""); break; case AMITK_WHICH_DEFAULT_DIRECTORY_NONE: default: break; } } amide-1.0.6/amide-current/src/amitk_preferences.h000066400000000000000000000216561423227705100217770ustar00rootroot00000000000000/* amitk_preferences.h * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_PREFERENCES_H__ #define __AMITK_PREFERENCES_H__ /* header files that are always needed with this file */ #include #include "amitk_common.h" #include "amitk_color_table.h" G_BEGIN_DECLS #define AMITK_TYPE_PREFERENCES (amitk_preferences_get_type ()) #define AMITK_PREFERENCES(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_PREFERENCES, AmitkPreferences)) #define AMITK_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_PREFERENCES, AmitkPreferencesClass)) #define AMITK_IS_PREFERENCES(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_PREFERENCES)) #define AMITK_IS_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_PREFERENCES)) #define AMITK_PREFERENCES_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_PREFERENCES, AmitkPreferencesClass)) #define AMITK_PREFERENCES_WARNINGS_TO_CONSOLE(object) (AMITK_PREFERENCES(object)->warnings_to_console) #define AMITK_PREFERENCES_PROMPT_FOR_SAVE_ON_EXIT(object) (AMITK_PREFERENCES(object)->prompt_for_save_on_exit) #define AMITK_PREFERENCES_WHICH_DEFAULT_DIRECTORY(object) (AMITK_PREFERENCES(object)->which_default_directory) #define AMITK_PREFERENCES_DEFAULT_DIRECTORY(object) (AMITK_PREFERENCES(object)->default_directory) #define AMITK_PREFERENCES_CANVAS_ROI_WIDTH(pref) (AMITK_PREFERENCES(pref)->canvas_roi_width) #ifdef AMIDE_LIBGNOMECANVAS_AA #define AMITK_PREFERENCES_CANVAS_ROI_TRANSPARENCY(pref) (AMITK_PREFERENCES(pref)->canvas_roi_transparency) #else #define AMITK_PREFERENCES_CANVAS_LINE_STYLE(pref) (AMITK_PREFERENCES(pref)->canvas_line_style) #define AMITK_PREFERENCES_CANVAS_FILL_ROI(pref) (AMITK_PREFERENCES(pref)->canvas_fill_roi) #endif #define AMITK_PREFERENCES_CANVAS_LAYOUT(pref) (AMITK_PREFERENCES(pref)->canvas_layout) #define AMITK_PREFERENCES_CANVAS_MAINTAIN_SIZE(pref) (AMITK_PREFERENCES(pref)->canvas_maintain_size) #define AMITK_PREFERENCES_CANVAS_TARGET_EMPTY_AREA(pref) (AMITK_PREFERENCES(pref)->canvas_target_empty_area) #define AMITK_PREFERENCES_PANEL_LAYOUT(pref) (AMITK_PREFERENCES(pref)->panel_layout) #define AMITK_PREFERENCES_COLOR_TABLE(pref, modality) (AMITK_PREFERENCES(pref)->color_table[modality]) #define AMITK_PREFERENCES_WINDOW(pref, which_window, limit) (AMITK_PREFERENCES(pref)->window[which_window][limit]) #define AMITK_PREFERENCES_THRESHOLD_STYLE(pref) (AMITK_PREFERENCES(pref)->threshold_style) #define AMITK_PREFERENCES_DIALOG(pref) (AMITK_PREFERENCES(pref)->dialog) typedef enum { AMITK_WHICH_DEFAULT_DIRECTORY_NONE, AMITK_WHICH_DEFAULT_DIRECTORY_SPECIFIED, AMITK_WHICH_DEFAULT_DIRECTORY_WORKING, AMITK_WHICH_DEFAULT_DIRECTORY_NUM } AmitkWhichDefaultDirectory; #define AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_WIDTH 2 #ifdef AMIDE_LIBGNOMECANVAS_AA #define AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_TRANSPARENCY 0.5 #else #define AMITK_PREFERENCES_DEFAULT_CANVAS_LINE_STYLE GDK_LINE_SOLID #define AMITK_PREFERENCES_DEFAULT_CANVAS_FILL_ROI TRUE #endif #define AMITK_PREFERENCES_DEFAULT_CANVAS_LAYOUT AMITK_LAYOUT_LINEAR #define AMITK_PREFERENCES_DEFAULT_CANVAS_MAINTAIN_SIZE TRUE #define AMITK_PREFERENCES_DEFAULT_CANVAS_TARGET_EMPTY_AREA 5 #define AMITK_PREFERENCES_DEFAULT_PANEL_LAYOUT AMITK_PANEL_LAYOUT_MIXED #define AMITK_PREFERENCES_DEFAULT_WARNINGS_TO_CONSOLE FALSE #define AMITK_PREFERENCES_DEFAULT_PROMPT_FOR_SAVE_ON_EXIT TRUE #define AMITK_PREFERENCES_DEFAULT_SAVE_XIF_AS_DIRECTORY FALSE #define AMITK_PREFERENCES_DEFAULT_WHICH_DEFAULT_DIRECTORY AMITK_WHICH_DEFAULT_DIRECTORY_NONE #define AMITK_PREFERENCES_DEFAULT_DEFAULT_DIRECTORY NULL #define AMITK_PREFERENCES_DEFAULT_THRESHOLD_STYLE AMITK_THRESHOLD_STYLE_MIN_MAX #define AMITK_PREFERENCES_MIN_ROI_WIDTH 1 #define AMITK_PREFERENCES_MAX_ROI_WIDTH 5 #define AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA 0 #define AMITK_PREFERENCES_MAX_TARGET_EMPTY_AREA 25 typedef struct _AmitkPreferencesClass AmitkPreferencesClass; typedef struct _AmitkPreferences AmitkPreferences; struct _AmitkPreferences { GObject parent; /* debug preferences */ gboolean warnings_to_console; /* file saving preferences */ gboolean prompt_for_save_on_exit; gboolean save_xif_as_directory; AmitkWhichDefaultDirectory which_default_directory; gchar * default_directory; /* canvas preferences -> study preferences */ gint canvas_roi_width; gdouble canvas_roi_transparency; #ifdef AMIDE_LIBGNOMECANVAS_AA GdkLineStyle canvas_line_style; gboolean canvas_fill_roi; #endif AmitkLayout canvas_layout; gboolean canvas_maintain_size; gint canvas_target_empty_area; /* in pixels */ AmitkPanelLayout panel_layout; /* data set preferences */ AmitkColorTable color_table[AMITK_MODALITY_NUM]; amide_data_t window[AMITK_WINDOW_NUM][AMITK_LIMIT_NUM]; AmitkThresholdStyle threshold_style; /* misc pointers */ GtkWidget * dialog; }; struct _AmitkPreferencesClass { GObjectClass parent_class; void (* data_set_preferences_changed) (AmitkPreferences * preferences); void (* study_preferences_changed) (AmitkPreferences * preferences); void (* misc_preferences_changed) (AmitkPreferences * preferences); }; /* ------------ external functions ---------- */ GType amitk_preferences_get_type (void); AmitkPreferences* amitk_preferences_new (void); void amitk_preferences_set_canvas_roi_width (AmitkPreferences * preferences, gint roi_width); #ifdef AMIDE_LIBGNOMECANVAS_AA void amitk_preferences_set_canvas_roi_transparency(AmitkPreferences * preferences, gdouble roi_transparency); #else void amitk_preferences_set_canvas_line_style (AmitkPreferences * preferences, GdkLineStyle line_style); void amitk_preferences_set_canvas_fill_roi (AmitkPreferences * preferences, gboolean fill_roi); #endif void amitk_preferences_set_canvas_layout (AmitkPreferences * preferences, AmitkLayout layout); void amitk_preferences_set_canvas_maintain_size (AmitkPreferences * preferences, gboolean maintain_size); void amitk_preferences_set_canvas_target_empty_area(AmitkPreferences * preferences, gint target_empty_area); void amitk_preferences_set_panel_layout (AmitkPreferences * preferences, AmitkPanelLayout panel_layout); void amitk_preferences_set_warnings_to_console (AmitkPreferences * preferences, gboolean new_value); void amitk_preferences_set_prompt_for_save_on_exit(AmitkPreferences * preferences, gboolean new_value); void amitk_preferences_set_xif_as_directory (AmitkPreferences * preferences, gboolean new_value); void amitk_preferences_set_which_default_directory(AmitkPreferences * preferences, const AmitkWhichDefaultDirectory which_default_directory); void amitk_preferences_set_default_directory (AmitkPreferences * preferences, const gchar * directory); void amitk_preferences_set_color_table (AmitkPreferences * preferences, AmitkModality modality, AmitkColorTable color_table); void amitk_preferences_set_default_window (AmitkPreferences * preferences, const AmitkWindow window, const AmitkLimit limit, const amide_data_t value); void amitk_preferences_set_threshold_style (AmitkPreferences * preferences, const AmitkThresholdStyle threshold_style); void amitk_preferences_set_dialog (AmitkPreferences * preferences, GtkWidget * dialog); void amitk_preferences_set_file_chooser_directory (AmitkPreferences * preferences, GtkWidget * file_chooser); /* external variables */ extern const gchar * amitk_which_default_directory_names[]; G_END_DECLS #endif /* __AMITK_PREFERENCES_H__ */ amide-1.0.6/amide-current/src/amitk_progress_dialog.c000066400000000000000000000120631423227705100226440ustar00rootroot00000000000000/* amitk_progress_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapted from gtkcolorsel.c */ #include "amide_config.h" #include "amide_intl.h" #include "amitk_marshal.h" #include "amitk_progress_dialog.h" static void dialog_class_init (AmitkProgressDialogClass *klass); static void dialog_init (AmitkProgressDialog *progress_dialog); static void dialog_response(GtkDialog * dialog, gint response_id); static GtkDialogClass *progress_dialog_parent_class; GType amitk_progress_dialog_get_type (void) { static GType progress_dialog_type = 0; if (!progress_dialog_type) { GTypeInfo progress_dialog_info = { sizeof (AmitkProgressDialogClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) dialog_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkProgressDialog), 0, /* # preallocs */ (GInstanceInitFunc) dialog_init, NULL /* value table */ }; progress_dialog_type = g_type_register_static(GTK_TYPE_DIALOG, "AmitkProgressDialog", &progress_dialog_info, 0); } return progress_dialog_type; } static void dialog_class_init (AmitkProgressDialogClass *klass) { /* GtkObjectClass *gtkobject_class; */ GtkDialogClass *gtkdialog_class = GTK_DIALOG_CLASS(klass); /* gtkobject_class = (GtkObjectClass*) klass; */ progress_dialog_parent_class = g_type_class_peek_parent(klass); gtkdialog_class->response = dialog_response; } static void dialog_init (AmitkProgressDialog * dialog) { gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); dialog->can_continue = TRUE; dialog->message_label = gtk_label_new(NULL); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), dialog->message_label, FALSE, FALSE, 0); dialog->progress_bar = gtk_progress_bar_new(); gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(dialog->progress_bar), 0.01); gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(dialog->progress_bar), GTK_PROGRESS_LEFT_TO_RIGHT); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), dialog->progress_bar, FALSE, FALSE, 0); return; } static void dialog_response(GtkDialog * dialog, gint response_id) { g_return_if_fail(AMITK_IS_PROGRESS_DIALOG(dialog)); AMITK_PROGRESS_DIALOG(dialog)->can_continue = FALSE; if (progress_dialog_parent_class->response) (* progress_dialog_parent_class->response) (dialog, response_id); return; } gboolean amitk_progress_dialog_update(gpointer dialog_pointer, char * message, gdouble fraction) { AmitkProgressDialog * dialog = AMITK_PROGRESS_DIALOG(dialog_pointer); if (message != NULL) amitk_progress_dialog_set_text(dialog, message); if ((fraction >= 0.0) || (fraction < -0.5)) return amitk_progress_dialog_set_fraction(dialog, fraction); else return AMITK_PROGRESS_DIALOG_CAN_CONTINUE(dialog); } void amitk_progress_dialog_set_text(AmitkProgressDialog * dialog, gchar * message) { g_return_if_fail(AMITK_IS_PROGRESS_DIALOG(dialog)); gtk_label_set_text(GTK_LABEL(dialog->message_label), message); } gboolean amitk_progress_dialog_set_fraction(AmitkProgressDialog * dialog, gdouble fraction) { if (fraction > 1.0) { if (GTK_WIDGET_VISIBLE(dialog)) gtk_widget_hide_all(GTK_WIDGET(dialog)); } else if (fraction >= 0.0) { if (!GTK_WIDGET_VISIBLE(dialog)) { gtk_widget_show_all(GTK_WIDGET(dialog)); dialog->can_continue = TRUE; } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->progress_bar), fraction); } else if (fraction < -0.5) { if (!GTK_WIDGET_VISIBLE(dialog)) { gtk_widget_show_all(GTK_WIDGET(dialog)); dialog->can_continue = TRUE; } gtk_progress_bar_pulse(GTK_PROGRESS_BAR(dialog->progress_bar)); } /* let spin while events are pending, this allows cancel to happen */ while (gtk_events_pending()) gtk_main_iteration(); return AMITK_PROGRESS_DIALOG_CAN_CONTINUE(dialog); } GtkWidget* amitk_progress_dialog_new (GtkWindow * parent) { AmitkProgressDialog *dialog; dialog = g_object_new(AMITK_TYPE_PROGRESS_DIALOG, NULL); gtk_window_set_title (GTK_WINDOW (dialog), _("Progress Dialog")); gtk_window_set_transient_for(GTK_WINDOW (dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW (dialog), TRUE); gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); return GTK_WIDGET (dialog); } amide-1.0.6/amide-current/src/amitk_progress_dialog.h000066400000000000000000000051571423227705100226570ustar00rootroot00000000000000/* amitk_progress_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapated from gtkcolorsel.h */ #ifndef __AMITK_PROGRESS_DIALOG_H__ #define __AMITK_PROGRESS_DIALOG_H__ /* includes we always need with this widget */ #include G_BEGIN_DECLS /* ------------- Progress_Dialog---------- */ #define AMITK_TYPE_PROGRESS_DIALOG (amitk_progress_dialog_get_type ()) #define AMITK_PROGRESS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_PROGRESS_DIALOG, AmitkProgressDialog)) #define AMITK_PROGRESS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLD, AmitkProgressDialogClass)) #define AMITK_IS_PROGRESS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_PROGRESS_DIALOG)) #define AMITK_IS_PROGRESS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_PROGRESS_DIALOG)) #define AMITK_PROGRESS_DIALOG_CAN_CONTINUE(obj) (AMITK_PROGRESS_DIALOG(obj)->can_continue); typedef struct _AmitkProgressDialog AmitkProgressDialog; typedef struct _AmitkProgressDialogClass AmitkProgressDialogClass; struct _AmitkProgressDialog { GtkDialog dialog; GtkWidget * message_label; GtkWidget * progress_bar; gboolean can_continue; }; struct _AmitkProgressDialogClass { GtkDialogClass parent_class; }; GType amitk_progress_dialog_get_type (void); gboolean amitk_progress_dialog_update (gpointer dialog, char * message, gdouble fraction); void amitk_progress_dialog_set_text (AmitkProgressDialog * dialog, gchar * message); gboolean amitk_progress_dialog_set_fraction (AmitkProgressDialog * dialog, gdouble fraction); GtkWidget* amitk_progress_dialog_new (GtkWindow * parent); G_END_DECLS #endif /* __AMITK_PROGRESS_DIALOG_H__ */ amide-1.0.6/amide-current/src/amitk_raw_data.c000066400000000000000000001022331423227705100212420ustar00rootroot00000000000000/* amitk_raw_data.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include "amitk_raw_data.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #define DATA_CONTENT(data, dim, voxel) ((data)[(voxel).x + (dim).x*(voxel).y]) /* external variables */ guint amitk_format_sizes[] = { sizeof(amitk_format_UBYTE_t), sizeof(amitk_format_SBYTE_t), sizeof(amitk_format_USHORT_t), sizeof(amitk_format_SSHORT_t), sizeof(amitk_format_UINT_t), sizeof(amitk_format_SINT_t), sizeof(amitk_format_FLOAT_t), sizeof(amitk_format_DOUBLE_t), 1 }; gboolean amitk_format_signed[AMITK_FORMAT_NUM] = { FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE }; gchar * amitk_format_names[AMITK_FORMAT_NUM] = { N_("Unsigned Byte (8 bit)"), N_("Signed Byte (8 bit)"), N_("Unsigned Short (16 bit)"), N_("Signed Short (16 bit)"), N_("Unsigned Integer (32 bit)"), N_("Signed Integer (32 bit)"), N_("Float (32 bit)"), N_("Double (64 bit)") }; amide_data_t amitk_format_max[AMITK_FORMAT_NUM] = { 255.0, 127.0, G_MAXUSHORT, G_MAXSHORT, G_MAXUINT, G_MAXINT, G_MAXFLOAT, G_MAXDOUBLE }; amide_data_t amitk_format_min[AMITK_FORMAT_NUM] = { 0.0, -128.0, 0.0, G_MINSHORT, 0.0, G_MININT, -G_MAXFLOAT, -G_MAXDOUBLE }; guint amitk_raw_format_sizes[] = { sizeof(amitk_format_UBYTE_t), sizeof(amitk_format_SBYTE_t), sizeof(amitk_format_USHORT_t), sizeof(amitk_format_SSHORT_t), sizeof(amitk_format_UINT_t), sizeof(amitk_format_SINT_t), sizeof(amitk_format_FLOAT_t), sizeof(amitk_format_DOUBLE_t), sizeof(amitk_format_USHORT_t), sizeof(amitk_format_SSHORT_t), sizeof(amitk_format_UINT_t), sizeof(amitk_format_SINT_t), sizeof(amitk_format_FLOAT_t), sizeof(amitk_format_DOUBLE_t), sizeof(amitk_format_UINT_t), sizeof(amitk_format_SINT_t), sizeof(amitk_format_FLOAT_t), 1, }; /* what used to be saved in the file */ gchar * amitk_raw_format_legacy_names[] = { "Unsigned Byte (8 bit)", "Signed Byte (8 bit)", "Unsigned Short, Little Endian (16 bit)", "Signed Short, Little Endian (16 bit)", "Unsigned Integer, Little Endian (32 bit)", "Signed Integer, Little Endian (32 bit)", "Float, Little Endian (32 bit)", "Double, Little Endian (64 bit)", "Unsigned Short, Big Endian (16 bit)", "Signed Short, Big Endian (16 bit)", "Unsigned Integer, Big Endian (32 bit)", "Signed Integer, Big Endian (32 bit)", "Float, Big Endian (32 bit)", "Double, Big Endian (64 bit)", "Unsigned Integer, PDP (32 bit)", "Signed Integer, PDP (32 bit)", "Float, PDP/VAX (32 bit)", "ASCII (8 bit)" }; /* what's shown to the user - can be translated */ gchar * amitk_raw_format_names[] = { N_("Unsigned Byte (8 bit)"), N_("Signed Byte (8 bit)"), N_("Unsigned Short, Little Endian (16 bit)"), N_("Signed Short, Little Endian (16 bit)"), N_("Unsigned Integer, Little Endian (32 bit)"), N_("Signed Integer, Little Endian (32 bit)"), N_("Float, Little Endian (32 bit)"), N_("Double, Little Endian (64 bit)"), N_("Unsigned Short, Big Endian (16 bit)"), N_("Signed Short, Big Endian (16 bit)"), N_("Unsigned Integer, Big Endian (32 bit)"), N_("Signed Integer, Big Endian (32 bit)"), N_("Float, Big Endian (32 bit)"), N_("Double, Big Endian (64 bit)"), N_("Unsigned Integer, PDP (32 bit)"), N_("Signed Integer, PDP (32 bit)"), N_("Float, PDP/VAX (32 bit)"), N_("ASCII (8 bit)") }; //enum { // LAST_SIGNAL //}; static void raw_data_class_init (AmitkRawDataClass *klass); static void raw_data_init (AmitkRawData *object); static void raw_data_finalize (GObject *object); static GObjectClass * parent_class; //static guint raw_data_signals[LAST_SIGNAL]; GType amitk_raw_data_get_type(void) { static GType raw_data_type = 0; if (!raw_data_type) { static const GTypeInfo raw_data_info = { sizeof (AmitkRawDataClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) raw_data_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkRawData), 0, /* n_preallocs */ (GInstanceInitFunc) raw_data_init, NULL /* value table */ }; raw_data_type = g_type_register_static (G_TYPE_OBJECT, "AmitkRawData", &raw_data_info, 0); } return raw_data_type; } static void raw_data_class_init (AmitkRawDataClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent(class); gobject_class->finalize = raw_data_finalize; } static void raw_data_init (AmitkRawData * raw_data) { raw_data->dim = zero_voxel; raw_data->data = NULL; raw_data->format = AMITK_FORMAT_DOUBLE; return; } static void raw_data_finalize (GObject *object) { AmitkRawData * raw_data = AMITK_RAW_DATA(object); if (raw_data->data != NULL) { #ifdef AMIDE_DEBUG //g_print("\tfreeing raw data\n"); #endif g_free(raw_data->data); raw_data->data = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } AmitkRawData * amitk_raw_data_new (void) { AmitkRawData * raw_data; raw_data = g_object_new(amitk_raw_data_get_type(), NULL); return raw_data; } AmitkRawData* amitk_raw_data_new_with_data(AmitkFormat format, AmitkVoxel dim) { AmitkRawData * raw_data; raw_data = amitk_raw_data_new(); g_return_val_if_fail(raw_data != NULL, NULL); raw_data->format = format; raw_data->dim = dim; /* allocate the space for the data */ raw_data->data = amitk_raw_data_get_data_mem(raw_data); if (raw_data->data == NULL) { g_object_unref(raw_data); return NULL; } return raw_data; } /* initalize a 2D slice, with values initialized to 0 */ AmitkRawData * amitk_raw_data_new_2D_with_data0(AmitkFormat format, amide_intpoint_t y_dim, amide_intpoint_t x_dim) { AmitkRawData * raw_data; AmitkVoxel dim; dim.x = x_dim; dim.y = y_dim; dim.z = dim.g = dim.t = 1; raw_data = amitk_raw_data_new_with_data0(format, dim); g_return_val_if_fail(raw_data != NULL, NULL); return raw_data; } /* initalize a 2D slice, with values initialized to 0 */ AmitkRawData * amitk_raw_data_new_3D_with_data0(AmitkFormat format, amide_intpoint_t z_dim, amide_intpoint_t y_dim, amide_intpoint_t x_dim) { AmitkRawData * raw_data; AmitkVoxel dim; dim.x = x_dim; dim.y = y_dim; dim.z = z_dim; dim.g = dim.t = 1; raw_data = amitk_raw_data_new_with_data0(format, dim); g_return_val_if_fail(raw_data != NULL, NULL); return raw_data; } /* same as amitk_raw_data_new_with_data, except allocated data memory is initialized to 0 */ AmitkRawData* amitk_raw_data_new_with_data0(AmitkFormat format, AmitkVoxel dim) { AmitkRawData * raw_data; raw_data = amitk_raw_data_new(); g_return_val_if_fail(raw_data != NULL, NULL); raw_data->format = format; raw_data->dim = dim; /* allocate the space for the data */ raw_data->data = amitk_raw_data_get_data_mem0(raw_data); if (raw_data->data == NULL) { g_object_unref(raw_data); return NULL; } return raw_data; } /* reads the contents of a raw data file into an amide raw data structure, notes: 1. file_offset is bytes for a binary file, lines for an ascii file 2. either file_name, of existing_file need to be specified. If existing_file is not being used, it must be NULL */ AmitkRawData * amitk_raw_data_import_raw_file(const gchar * file_name, FILE * existing_file, AmitkRawFormat raw_format, AmitkVoxel dim, long file_offset, AmitkUpdateFunc update_func, gpointer update_data) { FILE * new_file_pointer=NULL; FILE * file_pointer=NULL; void * file_buffer=NULL; size_t bytes_per_slice=0; size_t bytes_read; AmitkVoxel i; gint error_code, j; AmitkRawData * raw_data=NULL;; gchar * temp_string; gint total_planes; gint i_plane; div_t x; gint divider; gboolean continue_work = TRUE; g_return_val_if_fail((file_name != NULL) || (existing_file != NULL), NULL); if (update_func != NULL) { temp_string = g_strdup_printf(_("Reading: %s"), (file_name != NULL) ? file_name : "raw data"); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = dim.z*dim.t*dim.g; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); raw_data = amitk_raw_data_new_with_data(amitk_raw_format_to_format(raw_format), dim); if (raw_data == NULL) { g_warning(_("couldn't allocate memory space for the raw data set structure")); goto error_condition; } /* open the raw data file for reading */ if (existing_file == NULL) { if (raw_format == AMITK_RAW_FORMAT_ASCII_8_NE) { if ((new_file_pointer = fopen(file_name, "r")) == NULL) { g_warning(_("couldn't open raw data file %s"), file_name); goto error_condition; } } else { /* note, rb==r on any POSIX compliant system (i.e. Linux). */ if ((new_file_pointer = fopen(file_name, "rb")) == NULL) { g_warning(_("couldn't open raw data file %s"), file_name); goto error_condition; } } file_pointer = new_file_pointer; } else { file_pointer = existing_file; } /* jump forward by the given offset */ if (raw_format == AMITK_RAW_FORMAT_ASCII_8_NE) { for (j=0; j= 0) && (continue_work); i.t++) { for (i.g = 0; (i.g < dim.g) && (error_code >= 0) && (continue_work); i.g++) { for (i.z = 0; (i.z < dim.z) && (error_code >= 0) && (continue_work); i.z++, i_plane++) { if (update_func != NULL) { x = div(i_plane,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) i_plane)/((gdouble) total_planes)); } /* read in the contents of the file */ if (raw_format != AMITK_RAW_FORMAT_ASCII_8_NE) { /* ASCII handled in the loop below */ bytes_read = fread(file_buffer, 1, bytes_per_slice, file_pointer ); if (bytes_read != bytes_per_slice) { g_warning(_("read wrong # of elements from raw data, expected %zd, got %zd"), bytes_per_slice, bytes_read); goto error_condition; } } /* and convert the data */ switch (raw_format) { case AMITK_RAW_FORMAT_ASCII_8_NE: /* copy this frame into the data set */ i.x = 0; for (i.y = 0; (i.y < dim.y) && (error_code >= 0); i.y++) { for (i.x = 0; (i.x < dim.x) && (error_code >= 0); i.x++) { if (raw_data->format == AMITK_FORMAT_DOUBLE) error_code = fscanf(file_pointer, "%lf", AMITK_RAW_DATA_DOUBLE_POINTER(raw_data,i)); else // (raw_data->format == FLOAT) error_code = fscanf(file_pointer, "%f", AMITK_RAW_DATA_FLOAT_POINTER(raw_data,i)); if (error_code == 0) error_code = EOF; /* if we couldn't read, may as well be EOF*/ } } if (error_code < 0) { /* EOF = -1 (usually) */ g_warning(_("could not read ascii file after %d elements, file or parameters are erroneous"), i.x + dim.x*i.y + dim.x*dim.y*i_plane); goto error_condition; } break; case AMITK_RAW_FORMAT_FLOAT_32_PDP: { guint32 * data = file_buffer; guint32 temp; gfloat * float_p; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { /* keep compiler from generating bad code with a noop,occurs with gcc 3.0.3 */ if (i.x == -1) g_print("no_op\n"); temp = GUINT32_FROM_PDP(DATA_CONTENT(data, dim,i)); float_p = (void *) &temp; AMITK_RAW_DATA_FLOAT_SET_CONTENT(raw_data,i) = *float_p; } } break; case AMITK_RAW_FORMAT_SINT_32_PDP: { gint32 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SINT_SET_CONTENT(raw_data,i) = GINT32_FROM_PDP(DATA_CONTENT(data, dim,i)); } break; case AMITK_RAW_FORMAT_UINT_32_PDP: { guint32 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { /* keep compiler from generating bad code with a noop,occurs with gcc 3.0.3 */ if (i.x == -1) g_print("no_op\n"); AMITK_RAW_DATA_UINT_SET_CONTENT(raw_data,i) = GUINT32_FROM_PDP(DATA_CONTENT(data, dim,i)); } } break; case AMITK_RAW_FORMAT_DOUBLE_64_BE: { #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) guint64 * data = file_buffer; guint64 temp; gdouble * double_p; #else #if (G_BYTE_ORDER == G_BIG_ENDIAN) gdouble * data = file_buffer; #else #error "need to specify G_BIG_ENDIAN or G_LITTLE_ENDIAN" #endif #endif /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) temp = GUINT64_FROM_BE(DATA_CONTENT(data, dim, i)); double_p = (void *) &temp; if (i.x == -1) g_print("no op\n"); /* gets around compiler bug in gcc 4.1.2-27 */ AMITK_RAW_DATA_DOUBLE_SET_CONTENT(raw_data,i) = *double_p; #else /* G_BIG_ENDIAN */ AMITK_RAW_DATA_DOUBLE_SET_CONTENT(raw_data,i) = DATA_CONTENT(data, dim, i); #endif } } break; case AMITK_RAW_FORMAT_FLOAT_32_BE: { #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) guint32 * data = file_buffer; guint32 temp; gfloat * float_p; #else /* (G_BYTE_ORDER == G_BIG_ENDIAN) */ gfloat * data = file_buffer; #endif /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { /* keep compiler from generating bad code with a noop, occurs with gcc 3.0.3 */ if (i.x == -1) g_print("no op\n"); #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) temp = GUINT32_FROM_BE(DATA_CONTENT(data, dim, i)); float_p = (void *) &temp; if (i.x == -1) g_print("no op\n"); /* gets around compiler bug in gcc 4.1.2-27 */ AMITK_RAW_DATA_FLOAT_SET_CONTENT(raw_data,i) = *float_p; #else /* G_BIG_ENDIAN */ AMITK_RAW_DATA_FLOAT_SET_CONTENT(raw_data,i) = DATA_CONTENT(data, dim, i); #endif } } break; case AMITK_RAW_FORMAT_SINT_32_BE: { gint32 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SINT_SET_CONTENT(raw_data,i) = GINT32_FROM_BE(DATA_CONTENT(data, dim, i)); } break; case AMITK_RAW_FORMAT_UINT_32_BE: { guint32 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { /* keep compiler from generating bad code with a noop occurs with gcc 3.0.3 */ if (i.x == -1) g_print("no op\n"); AMITK_RAW_DATA_UINT_SET_CONTENT(raw_data,i) = GUINT32_FROM_BE(DATA_CONTENT(data, dim, i)); } } break; case AMITK_RAW_FORMAT_SSHORT_16_BE: { gint16 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SSHORT_SET_CONTENT(raw_data,i) = GINT16_FROM_BE(DATA_CONTENT(data, dim, i)); } break; case AMITK_RAW_FORMAT_USHORT_16_BE: { guint16 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_USHORT_SET_CONTENT(raw_data,i) = GUINT16_FROM_BE(DATA_CONTENT(data, dim, i)); } break; case AMITK_RAW_FORMAT_DOUBLE_64_LE: { #if (G_BYTE_ORDER == G_BIG_ENDIAN) guint64 * data = file_buffer; guint64 temp; gdouble * double_p; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ gdouble * data = file_buffer; #endif /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { #if (G_BYTE_ORDER == G_BIG_ENDIAN) temp = GUINT64_FROM_LE(DATA_CONTENT(data, dim, i)); double_p = (void *) &temp; if (i.x == -1) g_print("no op\n"); /* gets around compiler bug in gcc 4.1.2-27 */ AMITK_RAW_DATA_DOUBLE_SET_CONTENT(raw_data,i) = *double_p; #else /* G_LITTLE_ENDIAN */ AMITK_RAW_DATA_DOUBLE_SET_CONTENT(raw_data,i) = DATA_CONTENT(data, dim, i); #endif } } break; case AMITK_RAW_FORMAT_FLOAT_32_LE: { #if (G_BYTE_ORDER == G_BIG_ENDIAN) guint32 * data = file_buffer; guint32 temp; gfloat * float_p; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ gfloat * data = file_buffer; #endif /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { /* keep compiler from generating bad code with a noop,occurs with gcc 3.0.3 */ if (i.x == -1) g_print("no op\n"); #if (G_BYTE_ORDER == G_BIG_ENDIAN) temp = GUINT32_FROM_LE(DATA_CONTENT(data, dim, i)); float_p = (void *) &temp; if (i.x == -1) g_print("no op\n"); /* gets around compiler bug in gcc 4.1.2-27 */ AMITK_RAW_DATA_FLOAT_SET_CONTENT(raw_data,i) = *float_p; #else /* G_LITTLE_ENDIAN */ AMITK_RAW_DATA_FLOAT_SET_CONTENT(raw_data,i) = DATA_CONTENT(data, dim, i); #endif } } break; case AMITK_RAW_FORMAT_SINT_32_LE: { gint32 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SINT_SET_CONTENT(raw_data,i) = GINT32_FROM_LE(DATA_CONTENT(data, dim, i)); } break; case AMITK_RAW_FORMAT_UINT_32_LE: { guint32 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { /* keep compiler from generating bad code with a noop,occurs with gcc 3.0.3 */ if (i.x == -1) g_print("no_op\n"); AMITK_RAW_DATA_UINT_SET_CONTENT(raw_data,i) = GUINT32_FROM_LE(DATA_CONTENT(data, dim, i)); } } break; case AMITK_RAW_FORMAT_SSHORT_16_LE: { gint16 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SSHORT_SET_CONTENT(raw_data,i) = GINT16_FROM_LE(DATA_CONTENT(data, dim, i)); } break; case AMITK_RAW_FORMAT_USHORT_16_LE: { guint16 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_USHORT_SET_CONTENT(raw_data,i) = GUINT16_FROM_LE(DATA_CONTENT(data, dim, i)); } break; case AMITK_RAW_FORMAT_SBYTE_8_NE: { gint8 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SBYTE_SET_CONTENT(raw_data,i) = DATA_CONTENT(data, dim, i); } break; case AMITK_RAW_FORMAT_UBYTE_8_NE: default: { guint8 * data=file_buffer; /* copy this frame into the data set */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_UBYTE_SET_CONTENT(raw_data,i) = DATA_CONTENT(data, dim, i); } break; } } } } goto exit_condition; error_condition: if (raw_data != NULL) g_object_unref(raw_data); raw_data = NULL; exit_condition: if (new_file_pointer != NULL) fclose(new_file_pointer); if (file_buffer != NULL) g_free(file_buffer); if (update_func != NULL) (*update_func)(update_data, NULL, (gdouble) 2.0); return raw_data; } /* function to write out the information content of a raw_data set into an xml file. Returns a string containing the name of the file. */ void amitk_raw_data_write_xml(AmitkRawData * raw_data, const gchar * name, FILE *study_file, gchar ** output_filename, guint64 * plocation, guint64 * psize) { gchar * xml_filename=NULL; gchar * raw_filename=NULL; guint count; struct stat file_info; xmlDocPtr doc; FILE * file_pointer; guint64 location, size; size_t num_wrote; size_t num_to_write; size_t num_to_write_this_time; size_t bytes_per_unit; size_t total_to_write; size_t total_wrote = 0; if (study_file == NULL) { /* make a guess as to our filename */ count = 1; xml_filename = g_strdup_printf("%s.xml", name); raw_filename = g_strdup_printf("%s.dat", name); /* see if this file already exists */ while ((stat(xml_filename, &file_info) == 0) ||(stat(raw_filename, &file_info) == 0)) { g_free(xml_filename); g_free(raw_filename); count++; xml_filename = g_strdup_printf("%s_%d.xml", name, count); raw_filename = g_strdup_printf("%s_%d.dat", name, count); } /* and we now have unique filenames */ #ifdef AMIDE_DEBUG g_print("\t- saving raw data in file %s\n",xml_filename); #endif /* Note, "wb" is same as "w" on Unix, but not in Windows */ if ((file_pointer = fopen(raw_filename, "wb")) == NULL) { g_warning(_("couldn't save raw data file: %s"),raw_filename); g_free(xml_filename); g_free(raw_filename); return; } } else { file_pointer = study_file; } /* write it on out. */ location = ftell(file_pointer); num_to_write = amitk_raw_data_num_voxels(raw_data); bytes_per_unit = amitk_format_sizes[AMITK_RAW_DATA_FORMAT(raw_data)]; total_to_write = num_to_write; /* write in small chunks (<=16MB) to get around a bad samba/cygwin interaction */ while(num_to_write > 0) { if (num_to_write*bytes_per_unit > 0x1000000) num_to_write_this_time = 0x1000000/bytes_per_unit; else num_to_write_this_time = num_to_write; num_to_write -= num_to_write_this_time; num_wrote = fwrite((raw_data->data + total_wrote*bytes_per_unit), bytes_per_unit, num_to_write_this_time, file_pointer); total_wrote += num_wrote; if (num_wrote != num_to_write_this_time) { g_warning(_("incomplete save of raw data, wrote %zd (bytes), needed %zd (bytes), file: %s"), total_wrote*bytes_per_unit, total_to_write*bytes_per_unit, raw_filename); g_free(xml_filename); g_free(raw_filename); if (study_file == NULL) fclose(file_pointer); return; } } size = ftell(file_pointer)-location; if (study_file == NULL) fclose(file_pointer); /* write the xml portion */ doc = xmlNewDoc((xmlChar *) "1.0"); doc->children = xmlNewDocNode(doc, NULL, (xmlChar *) "raw_data", (xmlChar *) name); amitk_voxel_write_xml(doc->children, "dim", raw_data->dim); xml_save_string(doc->children,"raw_format", amitk_raw_format_get_name(amitk_format_to_raw_format(raw_data->format))); /* store the info on our associated data */ if (study_file == NULL) { xml_save_string(doc->children, "raw_data_file", raw_filename); g_free(raw_filename); } else { xml_save_location_and_size(doc->children, "raw_data_location_and_size", location, size); } /* and save */ if (study_file == NULL) { xmlSaveFile(xml_filename, doc); if (output_filename != NULL) *output_filename = xml_filename; else g_free(xml_filename); } else { *plocation = ftell(study_file); xmlDocDump(study_file, doc); *psize = ftell(study_file)-*plocation; } /* and we're done with the xml stuff*/ xmlFreeDoc(doc); return; } /* function to load in a raw data xml file */ AmitkRawData * amitk_raw_data_read_xml(gchar * xml_filename, FILE * study_file, guint64 location, guint64 size, gchar ** perror_buf, AmitkUpdateFunc update_func, gpointer update_data) { xmlDocPtr doc; AmitkRawData * raw_data; xmlNodePtr nodes; AmitkRawFormat i_raw_format, raw_format; gchar * temp_string; gchar * raw_filename=NULL; guint64 offset, dummy; long offset_long=0; AmitkVoxel dim; if ((doc = xml_open_doc(xml_filename, study_file, location, size, perror_buf)) == NULL) return NULL; /* function already appends the error message */ /* get the root of our document */ if ((nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf,_("Raw data xml file doesn't appear to have a root: %s"), xml_filename); return NULL; } /* get the document tree */ nodes = nodes->children; dim = amitk_voxel_read_xml(nodes, "dim", perror_buf); /* figure out the data format */ temp_string = xml_get_string(nodes, "raw_format"); #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_DOUBLE_64_BE; /* sensible guess in case we don't figure it out from the file */ #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_format = AMITK_RAW_FORMAT_DOUBLE_64_LE; /* sensible guess in case we don't figure it out from the file */ #endif if (temp_string != NULL) for (i_raw_format=0; i_raw_format < AMITK_RAW_FORMAT_NUM; i_raw_format++) if (g_ascii_strcasecmp(temp_string, amitk_raw_format_get_name(i_raw_format)) == 0) raw_format = i_raw_format; /* also need to check against legacy names for files created before amide version 0.7.11 */ for (i_raw_format=0; i_raw_format < AMITK_RAW_FORMAT_NUM; i_raw_format++) if (g_ascii_strcasecmp(temp_string, amitk_raw_format_legacy_names[i_raw_format]) == 0) raw_format = i_raw_format; g_free(temp_string); /* get the filename or location of our associated data */ if (study_file == NULL) { raw_filename = xml_get_string(nodes, "raw_data_file"); /* now load in the raw data */ #ifdef AMIDE_DEBUG g_print("reading data from file %s\n", raw_filename); #endif } else { xml_get_location_and_size(nodes, "raw_data_location_and_size", &offset, &dummy, perror_buf); /* check for file size problems */ if (!xml_check_file_32bit_okay(offset)) { amitk_append_str_with_newline(perror_buf, _("File to large to read on 32bit platform.")); return NULL; } offset_long = offset; } raw_data = amitk_raw_data_import_raw_file(raw_filename, study_file, raw_format, dim, offset_long, update_func, update_data); /* and we're done */ if (raw_filename != NULL) g_free(raw_filename); xmlFreeDoc(doc); return raw_data; } amide_data_t amitk_raw_data_get_value(const AmitkRawData * rd, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_RAW_DATA(rd), EMPTY); if (!amitk_raw_data_includes_voxel(rd, i)) return EMPTY; /* hand everything off to the data type specific function */ switch(AMITK_RAW_DATA_FORMAT(rd)) { case AMITK_FORMAT_UBYTE: return AMITK_RAW_DATA_UBYTE_CONTENT(rd, i); case AMITK_FORMAT_SBYTE: return AMITK_RAW_DATA_SBYTE_CONTENT(rd, i); case AMITK_FORMAT_USHORT: return AMITK_RAW_DATA_USHORT_CONTENT(rd, i); case AMITK_FORMAT_SSHORT: return AMITK_RAW_DATA_SSHORT_CONTENT(rd, i); case AMITK_FORMAT_UINT: return AMITK_RAW_DATA_UINT_CONTENT(rd, i); case AMITK_FORMAT_SINT: return AMITK_RAW_DATA_SINT_CONTENT(rd, i); case AMITK_FORMAT_FLOAT: return AMITK_RAW_DATA_FLOAT_CONTENT(rd, i); case AMITK_FORMAT_DOUBLE: return AMITK_RAW_DATA_DOUBLE_CONTENT(rd, i); default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return EMPTY; } } gpointer amitk_raw_data_get_pointer(const AmitkRawData * rd, const AmitkVoxel i) { g_return_val_if_fail(AMITK_IS_RAW_DATA(rd), NULL); g_return_val_if_fail(amitk_raw_data_includes_voxel(rd, i), NULL); /* hand everything off to the data type specific function */ switch(AMITK_RAW_DATA_FORMAT(rd)) { case AMITK_FORMAT_UBYTE: return AMITK_RAW_DATA_UBYTE_POINTER(rd, i); case AMITK_FORMAT_SBYTE: return AMITK_RAW_DATA_SBYTE_POINTER(rd, i); case AMITK_FORMAT_USHORT: return AMITK_RAW_DATA_USHORT_POINTER(rd, i); case AMITK_FORMAT_SSHORT: return AMITK_RAW_DATA_SSHORT_POINTER(rd, i); case AMITK_FORMAT_UINT: return AMITK_RAW_DATA_UINT_POINTER(rd, i); case AMITK_FORMAT_SINT: return AMITK_RAW_DATA_SINT_POINTER(rd, i); case AMITK_FORMAT_FLOAT: return AMITK_RAW_DATA_FLOAT_POINTER(rd, i); case AMITK_FORMAT_DOUBLE: return AMITK_RAW_DATA_DOUBLE_POINTER(rd, i); default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); return NULL; } } /* take in one of the raw data formats, and return the corresponding data format */ AmitkFormat amitk_raw_format_to_format(AmitkRawFormat raw_format) { AmitkFormat format; switch(raw_format) { case AMITK_RAW_FORMAT_UBYTE_8_NE: format = AMITK_FORMAT_UBYTE; break; case AMITK_RAW_FORMAT_SBYTE_8_NE: format = AMITK_FORMAT_SBYTE; break; case AMITK_RAW_FORMAT_USHORT_16_LE: case AMITK_RAW_FORMAT_USHORT_16_BE: format = AMITK_FORMAT_USHORT; break; case AMITK_RAW_FORMAT_SSHORT_16_LE: case AMITK_RAW_FORMAT_SSHORT_16_BE: format = AMITK_FORMAT_SSHORT; break; case AMITK_RAW_FORMAT_UINT_32_LE: case AMITK_RAW_FORMAT_UINT_32_BE: case AMITK_RAW_FORMAT_UINT_32_PDP: format = AMITK_FORMAT_UINT; break; case AMITK_RAW_FORMAT_SINT_32_LE: case AMITK_RAW_FORMAT_SINT_32_BE: case AMITK_RAW_FORMAT_SINT_32_PDP: format = AMITK_FORMAT_SINT; break; case AMITK_RAW_FORMAT_FLOAT_32_LE: case AMITK_RAW_FORMAT_FLOAT_32_BE: case AMITK_RAW_FORMAT_FLOAT_32_PDP: #if (SIZE_OF_AMIDE_T == 4) case AMITK_RAW_FORMAT_ASCII_8_NE: #endif format = AMITK_FORMAT_FLOAT; break; case AMITK_RAW_FORMAT_DOUBLE_64_LE: case AMITK_RAW_FORMAT_DOUBLE_64_BE: #if (SIZE_OF_AMIDE_T == 8) case AMITK_RAW_FORMAT_ASCII_8_NE: #endif format = AMITK_FORMAT_DOUBLE; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); format = AMITK_FORMAT_FLOAT; /* take a wild guess */ break; } return format; } /* tells you what raw data format corresponds to the given data format */ AmitkRawFormat amitk_format_to_raw_format(AmitkFormat format) { AmitkRawFormat raw_format; switch(format) { case AMITK_FORMAT_UBYTE: raw_format = AMITK_RAW_FORMAT_UBYTE_8_NE; break; case AMITK_FORMAT_SBYTE: raw_format = AMITK_RAW_FORMAT_SBYTE_8_NE; break; case AMITK_FORMAT_USHORT: #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_USHORT_16_BE; #else #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) raw_format = AMITK_RAW_FORMAT_USHORT_16_LE; #else #error "must specify G_LITTLE_ENDIAN or G_BIG_ENDIAN)" #endif #endif break; case AMITK_FORMAT_SSHORT: #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_SSHORT_16_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_format = AMITK_RAW_FORMAT_SSHORT_16_LE; #endif break; case AMITK_FORMAT_UINT: #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_UINT_32_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_format = AMITK_RAW_FORMAT_UINT_32_LE; #endif break; case AMITK_FORMAT_SINT: #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_SINT_32_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_format = AMITK_RAW_FORMAT_SINT_32_LE; #endif break; case AMITK_FORMAT_FLOAT: #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_FLOAT_32_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_format = AMITK_RAW_FORMAT_FLOAT_32_LE; #endif break; case AMITK_FORMAT_DOUBLE: #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_format = AMITK_RAW_FORMAT_DOUBLE_64_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_format = AMITK_RAW_FORMAT_DOUBLE_64_LE; #endif break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); raw_format = AMITK_RAW_FORMAT_UBYTE_8_NE; /* take a wild guess */ break; } return raw_format; } const gchar * amitk_raw_format_get_name(const AmitkRawFormat raw_format) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_RAW_FORMAT); enum_value = g_enum_get_value(enum_class, raw_format); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_raw_data.h000066400000000000000000000173241423227705100212550ustar00rootroot00000000000000/* amitk_raw_data.h * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_RAW_DATA_H__ #define __AMITK_RAW_DATA_H__ /* header files that are always needed with this file */ #include #include "amitk_object.h" G_BEGIN_DECLS #define AMITK_TYPE_RAW_DATA (amitk_raw_data_get_type ()) #define AMITK_RAW_DATA(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_RAW_DATA, AmitkRawData)) #define AMITK_RAW_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_RAW_DATA, AmitkRawDataClass)) #define AMITK_IS_RAW_DATA(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_RAW_DATA)) #define AMITK_IS_RAW_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_RAW_DATA)) #define AMITK_RAW_DATA_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_RAW_DATA, AmitkRawDataClass)) #define AMITK_RAW_DATA_FORMAT(rd) (AMITK_RAW_DATA(rd)->format) #define AMITK_RAW_DATA_DIM(rd) (AMITK_RAW_DATA(rd)->dim) #define AMITK_RAW_DATA_DIM_X(rd) (AMITK_RAW_DATA(rd)->dim.x) #define AMITK_RAW_DATA_DIM_Y(rd) (AMITK_RAW_DATA(rd)->dim.y) #define AMITK_RAW_DATA_DIM_Z(rd) (AMITK_RAW_DATA(rd)->dim.z) #define AMITK_RAW_DATA_DIM_G(rd) (AMITK_RAW_DATA(rd)->dim.g) #define AMITK_RAW_DATA_DIM_T(rd) (AMITK_RAW_DATA(rd)->dim.t) /* glib doesn't define these for PDP */ #ifdef G_BIG_ENDIAN #define GINT32_TO_PDP(val) ((gint32) GUINT32_SWAP_BE_PDP (val)) #define GUINT32_TO_PDP(val) ((guint32) GUINT32_SWAP_BE_PDP (val)) #else /* G_LITTLE_ENDIAN */ #define GINT32_TO_PDP(val) ((gint32) GUINT32_SWAP_LE_PDP (val)) #define GUINT32_TO_PDP(val) ((guint32) GUINT32_SWAP_LE_PDP (val)) #endif #define GINT32_FROM_PDP(val) (GINT32_TO_PDP (val)) #define GUINT32_FROM_PDP(val) (GUINT32_TO_PDP (val)) /* setup the types for various internal data formats */ /*the formats that data can take in memory */ typedef enum { AMITK_FORMAT_UBYTE, AMITK_FORMAT_SBYTE, AMITK_FORMAT_USHORT, AMITK_FORMAT_SSHORT, AMITK_FORMAT_UINT, AMITK_FORMAT_SINT, AMITK_FORMAT_FLOAT, AMITK_FORMAT_DOUBLE, AMITK_FORMAT_NUM } AmitkFormat; typedef guint8 amitk_format_UBYTE_t; typedef gint8 amitk_format_SBYTE_t; typedef guint16 amitk_format_USHORT_t; typedef gint16 amitk_format_SSHORT_t; typedef guint32 amitk_format_UINT_t; typedef gint32 amitk_format_SINT_t; typedef gfloat amitk_format_FLOAT_t; typedef gdouble amitk_format_DOUBLE_t; /*the formats that data can take on disk */ typedef enum { AMITK_RAW_FORMAT_UBYTE_8_NE, AMITK_RAW_FORMAT_SBYTE_8_NE, AMITK_RAW_FORMAT_USHORT_16_LE, AMITK_RAW_FORMAT_SSHORT_16_LE, AMITK_RAW_FORMAT_UINT_32_LE, AMITK_RAW_FORMAT_SINT_32_LE, AMITK_RAW_FORMAT_FLOAT_32_LE, AMITK_RAW_FORMAT_DOUBLE_64_LE, AMITK_RAW_FORMAT_USHORT_16_BE, AMITK_RAW_FORMAT_SSHORT_16_BE, AMITK_RAW_FORMAT_UINT_32_BE, AMITK_RAW_FORMAT_SINT_32_BE, AMITK_RAW_FORMAT_FLOAT_32_BE, AMITK_RAW_FORMAT_DOUBLE_64_BE, AMITK_RAW_FORMAT_UINT_32_PDP, AMITK_RAW_FORMAT_SINT_32_PDP, AMITK_RAW_FORMAT_FLOAT_32_PDP, AMITK_RAW_FORMAT_ASCII_8_NE, AMITK_RAW_FORMAT_NUM } AmitkRawFormat; typedef struct _AmitkRawDataClass AmitkRawDataClass; typedef struct _AmitkRawData AmitkRawData; struct _AmitkRawData { GObject parent; AmitkVoxel dim; gpointer data; AmitkFormat format; }; struct _AmitkRawDataClass { GObjectClass parent_class; }; /* -------- defines ----------- */ #define amitk_raw_data_includes_voxel(rd, vox) (!(((vox).x < 0) || \ ((vox).y < 0) || \ ((vox).z < 0) || \ ((vox).g < 0) || \ ((vox).t < 0) || \ ((vox).x >= (rd)->dim.x) || \ ((vox).y >= (rd)->dim.y) || \ ((vox).z >= (rd)->dim.z) || \ ((vox).g >= (rd)->dim.g) || \ ((vox).t >= (rd)->dim.t))) #define amitk_raw_data_num_voxels(rd) ((rd)->dim.x * (rd)->dim.y * (rd)->dim.z * (rd)->dim.g * (rd)->dim.t) #define amitk_raw_data_size_data_mem(rd) (amitk_raw_data_num_voxels(rd) * amitk_format_sizes[(rd)->format]) #define amitk_raw_data_get_data_mem(rd) (g_try_malloc(amitk_raw_data_size_data_mem(rd))) #define amitk_raw_data_get_data_mem0(rd) (g_try_malloc0(amitk_raw_data_size_data_mem(rd))) /* ------------ external functions ---------- */ GType amitk_raw_data_get_type (void); AmitkRawData* amitk_raw_data_new (void); AmitkRawData* amitk_raw_data_new_with_data (AmitkFormat format, AmitkVoxel dim); AmitkRawData* amitk_raw_data_new_with_data0 (AmitkFormat format, AmitkVoxel dim); AmitkRawData * amitk_raw_data_new_2D_with_data0 (AmitkFormat format, amide_intpoint_t y_dim, amide_intpoint_t x_dim); AmitkRawData * amitk_raw_data_new_3D_with_data0 (AmitkFormat format, amide_intpoint_t z_dim, amide_intpoint_t y_dim, amide_intpoint_t x_dim); AmitkRawData * amitk_raw_data_import_raw_file (const gchar * file_name, FILE * existing_file, AmitkRawFormat raw_format, AmitkVoxel dim, long file_offset, AmitkUpdateFunc update_func, gpointer update_data); void amitk_raw_data_write_xml (AmitkRawData * raw_data, const gchar * name, FILE * study_file, gchar ** output_filename, guint64 * location, guint64 * size); AmitkRawData * amitk_raw_data_read_xml (gchar * xml_filename, FILE * study_file, guint64 location, guint64 size, gchar ** perror_buf, AmitkUpdateFunc update_func, gpointer update_data); amide_data_t amitk_raw_data_get_value (const AmitkRawData * rd, const AmitkVoxel i); gpointer amitk_raw_data_get_pointer (const AmitkRawData * rd, const AmitkVoxel i); AmitkFormat amitk_raw_format_to_format(AmitkRawFormat raw_format); AmitkRawFormat amitk_format_to_raw_format(AmitkFormat data_format); #define amitk_raw_format_calc_num_bytes_per_slice(dim, raw_format) ((dim).x*(dim).y*amitk_raw_format_sizes[raw_format]) #define amitk_raw_format_calc_num_bytes(dim, raw_format) ((dim).z*(dim).g*(dim).t*amitk_raw_format_calc_num_bytes_per_slice(dim,raw_format)) const gchar * amitk_raw_format_get_name(const AmitkRawFormat raw_format); /* external variables */ extern guint amitk_format_sizes[]; extern gboolean amitk_format_signed[]; extern gchar * amitk_format_names[]; extern amide_data_t amitk_format_max[]; extern amide_data_t amitk_format_min[]; extern guint amitk_raw_format_sizes[]; extern gchar * amitk_raw_format_names[]; extern gchar * amitk_raw_format_legacy_names[]; /* variable type function declarations */ #include "amitk_raw_data_UBYTE.h" #include "amitk_raw_data_SBYTE.h" #include "amitk_raw_data_USHORT.h" #include "amitk_raw_data_SSHORT.h" #include "amitk_raw_data_UINT.h" #include "amitk_raw_data_SINT.h" #include "amitk_raw_data_FLOAT.h" #include "amitk_raw_data_DOUBLE.h" G_END_DECLS #endif /* __AMITK_RAW_DATA_H__ */ amide-1.0.6/amide-current/src/amitk_raw_data_variable_type.c000066400000000000000000000037521423227705100241560ustar00rootroot00000000000000/* amitk_raw_data_variable_type.c - used to generate the different amitk_raw_data_*.c files * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amitk_raw_data_`'m4_Variable_Type`'.h" AmitkRawData * amitk_raw_data_`'m4_Variable_Type`'_0D_SCALING_init(amitk_format_`'m4_Variable_Type`'_t init_value) { AmitkRawData * temp_amitk_raw_data; temp_amitk_raw_data = amitk_raw_data_new_with_data(AMITK_FORMAT_`'m4_Variable_Type`', one_voxel); g_return_val_if_fail(temp_amitk_raw_data != NULL, NULL); (*AMITK_RAW_DATA_`'m4_Variable_Type`'_0D_SCALING_POINTER(temp_amitk_raw_data, zero_voxel)) = init_value; return temp_amitk_raw_data; } void amitk_raw_data_`'m4_Variable_Type`'_initialize_data(AmitkRawData * amitk_raw_data, amitk_format_`'m4_Variable_Type`'_t init_value) { AmitkVoxel i; for (i.t = 0; i.t < amitk_raw_data->dim.t; i.t++) for (i.g = 0; i.g < amitk_raw_data->dim.g; i.g++) for (i.z = 0; i.z < amitk_raw_data->dim.z; i.z++) for (i.y = 0; i.y < amitk_raw_data->dim.y; i.y++) for (i.x = 0; i.x < amitk_raw_data->dim.x; i.x++) AMITK_RAW_DATA_`'m4_Variable_Type`'_SET_CONTENT(amitk_raw_data,i)=init_value; return; } amide-1.0.6/amide-current/src/amitk_raw_data_variable_type.h000066400000000000000000000073651423227705100241670ustar00rootroot00000000000000/* amitk_raw_data_variable_type.h - used to generate the different amitk_raw_data_*.h files * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_RAW_DATA_`'m4_Variable_Type`'__ #define __AMITK_RAW_DATA_`'m4_Variable_Type`'__ /* header files that are always needed with this file */ #include "amitk_raw_data.h" /* defines */ #define AMITK_RAW_DATA_`'m4_Variable_Type`'_0D_SCALING_POINTER(amitk_raw_data,i) \ (((amitk_format_`'m4_Variable_Type`'_t *) (amitk_raw_data)->data)) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_1D_SCALING_POINTER(amitk_raw_data,i) \ (((amitk_format_`'m4_Variable_Type`'_t *) (amitk_raw_data)->data)+(i).t) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_2D_SCALING_POINTER(amitk_raw_data,i) \ (((amitk_format_`'m4_Variable_Type`'_t *) (amitk_raw_data)->data)+ \ (((((i).t) * ((amitk_raw_data)->dim.g) + \ (i).g) * ((amitk_raw_data)->dim.z)) + \ (i).z)) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER(amitk_raw_data,i) \ (((amitk_format_`'m4_Variable_Type`'_t *) (amitk_raw_data)->data)+ \ ((((((((((i).t) * ((amitk_raw_data)->dim.g)) + \ (i).g) * ((amitk_raw_data)->dim.z)) + \ (i).z) * ((amitk_raw_data)->dim.y)) + \ (i).y) * ((amitk_raw_data)->dim.x)) + \ (i).x)) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_3D_POINTER(amitk_raw_data,iz,iy,ix) \ (((amitk_format_`'m4_Variable_Type`'_t *) (amitk_raw_data)->data)+ \ ((((((iz)) * ((amitk_raw_data)->dim.y)) + \ (iy)) * ((amitk_raw_data)->dim.x)) + \ (ix))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_2D_POINTER(amitk_raw_data,iy,ix) \ (((amitk_format_`'m4_Variable_Type`'_t *) (amitk_raw_data)->data)+ \ ((((iy)) * ((amitk_raw_data)->dim.x)) + \ (ix))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_SET_CONTENT(amitk_raw_data,i) \ (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER((amitk_raw_data),(i)))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_CONTENT(amitk_raw_data,i) \ (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_POINTER((amitk_raw_data),(i)))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_2D_SET_CONTENT(amitk_raw_data,iy,ix) \ (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_2D_POINTER((amitk_raw_data),(iy),(ix)))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_2D_CONTENT(amitk_raw_data,iy,ix) \ (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_2D_POINTER((amitk_raw_data),(iy),(ix)))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_3D_SET_CONTENT(amitk_raw_data,iz,iy,ix) \ (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_3D_POINTER((amitk_raw_data), (iz),(iy), (ix)))) #define AMITK_RAW_DATA_`'m4_Variable_Type`'_3D_CONTENT(amitk_raw_data,iz,iy,ix) \ (*(AMITK_RAW_DATA_`'m4_Variable_Type`'_3D_POINTER((amitk_raw_data),(iz),(iy),(ix)))) /* function declarations */ AmitkRawData * amitk_raw_data_`'m4_Variable_Type`'_0D_SCALING_init(amitk_format_`'m4_Variable_Type`'_t init_value); void amitk_raw_data_`'m4_Variable_Type`'_initialize_data(AmitkRawData * amitk_raw_data, amitk_format_`'m4_Variable_Type`'_t init_value); #endif /* __AMITK_RAW_DATA_`'m4_Variable_Type`'__ */ amide-1.0.6/amide-current/src/amitk_roi.c000066400000000000000000000712711423227705100202600ustar00rootroot00000000000000/* amitk_roi.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_roi.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" /* variable type function declarations */ #include "amitk_roi_ELLIPSOID.h" #include "amitk_roi_CYLINDER.h" #include "amitk_roi_BOX.h" #include "amitk_roi_ISOCONTOUR_2D.h" #include "amitk_roi_ISOCONTOUR_3D.h" #include "amitk_roi_FREEHAND_2D.h" #include "amitk_roi_FREEHAND_3D.h" gchar * amitk_roi_menu_names[] = { N_("_Ellipsoid"), N_("Elliptic _Cylinder"), N_("_Box"), N_("_2D Isocontour"), N_("_3D Isocontour"), N_("_2D Freehand"), N_("_3D Freehand") }; gchar * amitk_roi_menu_explanation[] = { N_("Add a new elliptical ROI"), N_("Add a new elliptic cylinder ROI"), N_("Add a new box shaped ROI"), N_("Add a new 2D Isocontour ROI"), N_("Add a new 3D Isocontour ROI"), N_("Add a new 2D Freehand ROI"), N_("Add a new 3D Freehand ROI") }; enum { ROI_CHANGED, ROI_TYPE_CHANGED, LAST_SIGNAL }; static void roi_class_init (AmitkRoiClass *klass); static void roi_init (AmitkRoi *roi); static void roi_finalize (GObject *object); static void roi_scale (AmitkSpace *space, AmitkPoint *ref_point, AmitkPoint *scaling); static AmitkObject * roi_copy (const AmitkObject * object); static void roi_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); static void roi_write_xml (const AmitkObject *object, xmlNodePtr nodes, FILE *study_file); static gchar * roi_read_xml (AmitkObject *object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf); static void roi_get_center (const AmitkVolume *volume, AmitkPoint *center); static void roi_set_voxel_size (AmitkRoi * roi, AmitkPoint voxel_size); static AmitkVolumeClass * parent_class; static guint roi_signals[LAST_SIGNAL]; GType amitk_roi_get_type(void) { static GType roi_type = 0; if (!roi_type) { static const GTypeInfo roi_info = { sizeof (AmitkRoiClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) roi_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkRoi), 0, /* n_preallocs */ (GInstanceInitFunc) roi_init, NULL /* value table */ }; roi_type = g_type_register_static (AMITK_TYPE_VOLUME, "AmitkRoi", &roi_info, 0); } return roi_type; } static void roi_class_init (AmitkRoiClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); AmitkObjectClass * object_class = AMITK_OBJECT_CLASS(class); AmitkSpaceClass * space_class = AMITK_SPACE_CLASS(class); AmitkVolumeClass * volume_class = AMITK_VOLUME_CLASS(class); parent_class = g_type_class_peek_parent(class); space_class->space_scale = roi_scale; object_class->object_copy = roi_copy; object_class->object_copy_in_place = roi_copy_in_place; object_class->object_write_xml = roi_write_xml; object_class->object_read_xml = roi_read_xml; volume_class->volume_get_center = roi_get_center; gobject_class->finalize = roi_finalize; roi_signals[ROI_CHANGED] = g_signal_new ("roi_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkRoiClass, roi_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); roi_signals[ROI_TYPE_CHANGED] = g_signal_new ("roi_type_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkRoiClass, roi_type_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); } static void roi_init (AmitkRoi * roi) { roi->specify_color = FALSE; roi->color = amitk_color_table_uint32_to_rgba(AMITK_OBJECT_DEFAULT_COLOR); roi->voxel_size = zero_point; roi->map_data = NULL; roi->center_of_mass_calculated=FALSE; roi->center_of_mass=zero_point; roi->isocontour_min_value = 0.0; roi->isocontour_max_value = 0.0; roi->isocontour_range = AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN; } static void roi_finalize (GObject *object) { AmitkRoi * roi = AMITK_ROI(object); if (roi->map_data != NULL) { g_object_unref(roi->map_data); roi->map_data = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static void roi_scale(AmitkSpace *space, AmitkPoint *ref_point, AmitkPoint *scaling) { AmitkRoi * roi; AmitkPoint voxel_size; g_return_if_fail(AMITK_IS_ROI(space)); roi = AMITK_ROI(space); /* first, pass the signal on, this gets the volume corner value readjusted */ AMITK_SPACE_CLASS(parent_class)->space_scale (space, ref_point, scaling); /* and readjust the voxel size based on the new corner */ if (AMITK_VOLUME_VALID(roi)) { if (AMITK_ROI_TYPE_ISOCONTOUR(roi) || AMITK_ROI_TYPE_FREEHAND(roi)) { voxel_size = AMITK_VOLUME_CORNER(roi); voxel_size.x /= roi->map_data->dim.x; voxel_size.y /= roi->map_data->dim.y; voxel_size.z /= roi->map_data->dim.z; roi_set_voxel_size(roi, voxel_size); } } } static AmitkObject * roi_copy (const AmitkObject * object) { AmitkRoi * copy; g_return_val_if_fail(AMITK_IS_ROI(object), NULL); copy = amitk_roi_new(AMITK_ROI_TYPE(object)); amitk_object_copy_in_place(AMITK_OBJECT(copy), object); return AMITK_OBJECT(copy); } /* doesn't copy the data set used by isocontours and freehands, just adds a reference... */ static void roi_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object) { AmitkRoi * src_roi; AmitkRoi * dest_roi; g_return_if_fail(AMITK_IS_ROI(src_object)); g_return_if_fail(AMITK_IS_ROI(dest_object)); src_roi = AMITK_ROI(src_object); dest_roi = AMITK_ROI(dest_object); amitk_roi_set_type(dest_roi, AMITK_ROI_TYPE(src_object)); dest_roi->specify_color = AMITK_ROI_SPECIFY_COLOR(src_roi); dest_roi->color = AMITK_ROI_COLOR(src_roi); if (src_roi->map_data != NULL) { if (dest_roi->map_data != NULL) g_object_unref(dest_roi->map_data); dest_roi->map_data = g_object_ref(src_roi->map_data); } dest_roi->center_of_mass_calculated = src_roi->center_of_mass_calculated; dest_roi->center_of_mass = src_roi->center_of_mass; roi_set_voxel_size(dest_roi, AMITK_ROI_VOXEL_SIZE(src_object)); dest_roi->isocontour_min_value = AMITK_ROI_ISOCONTOUR_MIN_VALUE(src_object); dest_roi->isocontour_max_value = AMITK_ROI_ISOCONTOUR_MAX_VALUE(src_object); dest_roi->isocontour_range = AMITK_ROI_ISOCONTOUR_RANGE(src_object); AMITK_OBJECT_CLASS (parent_class)->object_copy_in_place (dest_object, src_object); } static void roi_write_xml (const AmitkObject * object, xmlNodePtr nodes, FILE * study_file) { AmitkRoi * roi; gchar * name; gchar * filename; guint64 location, size; AMITK_OBJECT_CLASS(parent_class)->object_write_xml(object, nodes, study_file); roi = AMITK_ROI(object); xml_save_string(nodes, "type", amitk_roi_type_get_name(AMITK_ROI_TYPE(roi))); xml_save_boolean(nodes, "specify_color", AMITK_ROI_SPECIFY_COLOR(roi)); xml_save_uint(nodes, "color", amitk_color_table_rgba_to_uint32(AMITK_ROI_COLOR(roi))); /* freehand and isocontour specific stuff */ amitk_point_write_xml(nodes, "voxel_size", AMITK_ROI_VOXEL_SIZE(roi)); xml_save_boolean(nodes, "center_of_mass_calculated", AMITK_ROI(roi)->center_of_mass_calculated); amitk_point_write_xml(nodes, "center_of_mass", AMITK_ROI(roi)->center_of_mass); if (AMITK_ROI_TYPE_ISOCONTOUR(roi) || AMITK_ROI_TYPE_FREEHAND(roi)) { name = g_strdup_printf("roi_%s_map_data", AMITK_OBJECT_NAME(roi)); amitk_raw_data_write_xml(roi->map_data, name, study_file, &filename, &location, &size); g_free(name); if (study_file == NULL) { xml_save_string(nodes,"map_file", filename); g_free(filename); } else { xml_save_location_and_size(nodes, "map_location_and_size", location, size); } } /* isocontour specific stuff */ xml_save_real(nodes, "isocontour_min_value", AMITK_ROI_ISOCONTOUR_MIN_VALUE(roi)); xml_save_real(nodes, "isocontour_max_value", AMITK_ROI_ISOCONTOUR_MAX_VALUE(roi)); xml_save_int(nodes, "isocontour_range", AMITK_ROI_ISOCONTOUR_RANGE(roi)); return; } static gchar * roi_read_xml (AmitkObject * object, xmlNodePtr nodes, FILE * study_file, gchar * error_buf) { AmitkRoi * roi; AmitkRoiType i_roi_type; gchar * temp_string; gchar * map_xml_filename=NULL; guint64 location, size; error_buf = AMITK_OBJECT_CLASS(parent_class)->object_read_xml(object, nodes, study_file, error_buf); roi = AMITK_ROI(object); /* figure out the type */ temp_string = xml_get_string(nodes, "type"); if (temp_string != NULL) for (i_roi_type=0; i_roi_type < AMITK_ROI_TYPE_NUM; i_roi_type++) if (g_ascii_strcasecmp(temp_string, amitk_roi_type_get_name(i_roi_type)) == 0) roi->type = i_roi_type; g_free(temp_string); amitk_roi_set_specify_color(roi, xml_get_boolean_with_default(nodes, "specify_color", AMITK_ROI_SPECIFY_COLOR(roi))); amitk_roi_set_color(roi, amitk_color_table_uint32_to_rgba(xml_get_uint_with_default(nodes, "color", AMITK_OBJECT_DEFAULT_COLOR))); /* freehand and isocontour specific stuff */ if (AMITK_ROI_TYPE_ISOCONTOUR(roi) | AMITK_ROI_TYPE_FREEHAND(roi)) { roi_set_voxel_size(roi, amitk_point_read_xml(nodes, "voxel_size", &error_buf)); /* check for old style entries */ if (xml_node_exists(nodes, "isocontour_center_of_mass_calculated")) roi->center_of_mass_calculated = xml_get_boolean(nodes, "isocontour_center_of_mass_calculated", &error_buf); else roi->center_of_mass_calculated = xml_get_boolean(nodes, "center_of_mass_calculated", &error_buf); /* check for old style entries */ if (xml_node_exists(nodes, "isocontour_center_of_mass")) roi->center_of_mass = amitk_point_read_xml(nodes, "isocontour_center_of_mass", &error_buf); else roi->center_of_mass = amitk_point_read_xml(nodes, "center_of_mass", &error_buf); /* check for old style entries */ if (xml_node_exists(nodes, "isocontour_file") || xml_node_exists(nodes, "isocontour_location_and_size")) { if (study_file == NULL) map_xml_filename = xml_get_string(nodes, "isocontour_file"); else xml_get_location_and_size(nodes, "isocontour_location_and_size", &location, &size, &error_buf); roi->map_data = amitk_raw_data_read_xml(map_xml_filename, study_file, location, size,&error_buf, NULL, NULL); /* if the ROI's never been drawn, it's possible for this not to exist */ } else if (xml_node_exists(nodes, "map_file") || xml_node_exists(nodes, "map_location_and_size")) { if (study_file == NULL) map_xml_filename = xml_get_string(nodes, "map_file"); else xml_get_location_and_size(nodes, "map_location_and_size", &location, &size, &error_buf); roi->map_data = amitk_raw_data_read_xml(map_xml_filename, study_file, location, size,&error_buf, NULL, NULL); } if (map_xml_filename != NULL) g_free(map_xml_filename); } /* isocontour specific stuff */ if (AMITK_ROI_TYPE_ISOCONTOUR(roi)) { /* check first if we're using the old isocontour_value and isocontour_inverse entries */ if (xml_node_exists(nodes, "isocontour_value")) { /* works, cause inverse=TRUE=1=AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX */ roi->isocontour_range = xml_get_boolean(nodes, "isocontour_inverse", &error_buf); if (roi->isocontour_range == AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX) roi->isocontour_min_value = xml_get_real(nodes, "isocontour_value", &error_buf); else roi->isocontour_max_value = xml_get_real(nodes, "isocontour_value", &error_buf); } else { /* how we currently store isocontour information */ roi->isocontour_range = xml_get_int(nodes, "isocontour_range", &error_buf); roi->isocontour_min_value = xml_get_real(nodes, "isocontour_min_value", &error_buf); roi->isocontour_max_value = xml_get_real(nodes, "isocontour_max_value", &error_buf); } } /* make sure to mark the roi as undrawn if needed */ if (AMITK_ROI_TYPE_ISOCONTOUR(roi)) { if (roi->map_data == NULL) AMITK_VOLUME(roi)->valid = FALSE; } else { if (POINT_EQUAL(AMITK_VOLUME_CORNER(roi), zero_point)) { AMITK_VOLUME(roi)->valid = FALSE; } } return error_buf; } static void roi_get_center(const AmitkVolume *volume, AmitkPoint * pcenter) { if (AMITK_ROI_TYPE_ISOCONTOUR(volume) || AMITK_ROI_TYPE_FREEHAND(volume)) { *pcenter = amitk_roi_get_center_of_mass(AMITK_ROI(volume)); } else { /* if geometric, just use the standard volume function */ AMITK_VOLUME_CLASS(parent_class)->volume_get_center(volume,pcenter); } return; } AmitkRoi * amitk_roi_new (AmitkRoiType type) { AmitkRoi * roi; roi = g_object_new(amitk_roi_get_type(), NULL); roi->type = type; return roi; } /* returns a singly linked list of intersection points between the roi and the given canvas slice. returned points are in the canvas's coordinate space. note: use this function for ELLIPSOID, CYLINDER, and BOX */ GSList * amitk_roi_get_intersection_line(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim) { GSList * return_points = NULL; g_return_val_if_fail(AMITK_IS_ROI(roi), NULL); if (AMITK_ROI_UNDRAWN(roi)) return NULL; switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ELLIPSOID: return_points = amitk_roi_ELLIPSOID_get_intersection_line(roi, canvas_slice, pixel_dim); break; case AMITK_ROI_TYPE_CYLINDER: return_points = amitk_roi_CYLINDER_get_intersection_line(roi, canvas_slice, pixel_dim); break; case AMITK_ROI_TYPE_BOX: return_points = amitk_roi_BOX_get_intersection_line(roi, canvas_slice, pixel_dim); break; default: g_error("roi type %d not implemented! file %s line %d", AMITK_ROI_TYPE(roi), __FILE__, __LINE__); break; } return return_points; } GSList * amitk_roi_free_points_list(GSList * list) { AmitkPoint * ppoint; if (list == NULL) return list; list->next = amitk_roi_free_points_list(list->next); /* recurse */ ppoint = (AmitkPoint *) list->data; list = g_slist_remove(list, ppoint); g_free(ppoint); return list; } /* whether we want to use the specified color or have the program choose a decent color */ void amitk_roi_set_specify_color(AmitkRoi * roi, gboolean specify_color) { g_return_if_fail(AMITK_IS_ROI(roi)); if (specify_color != AMITK_ROI_SPECIFY_COLOR(roi)) { roi->specify_color = specify_color; g_signal_emit(G_OBJECT(roi), roi_signals[ROI_CHANGED], 0); } return; } /* color to draw the roi in, if we choose specify_color */ void amitk_roi_set_color(AmitkRoi * roi, rgba_t new_color) { rgba_t old_color; g_return_if_fail(AMITK_IS_ROI(roi)); old_color = AMITK_ROI_COLOR(roi); if ((old_color.r != new_color.r) || (old_color.g != new_color.g) || (old_color.b != new_color.b) || (old_color.a != new_color.a)) { roi->color = new_color; g_signal_emit(G_OBJECT(roi), roi_signals[ROI_CHANGED], 0); } return; } /* this does not recalc the far corner, needs to be done separately */ static void roi_set_voxel_size(AmitkRoi * roi, AmitkPoint voxel_size) { if (!POINT_EQUAL(AMITK_ROI_VOXEL_SIZE(roi), voxel_size)) { roi->voxel_size = voxel_size; roi->center_of_mass_calculated = FALSE; g_signal_emit(G_OBJECT(roi), roi_signals[ROI_CHANGED], 0); } } /* only for isocontour and freehand roi's */ void amitk_roi_set_voxel_size(AmitkRoi * roi, AmitkPoint voxel_size) { GList * children; AmitkPoint ref_point; AmitkPoint scaling; AmitkPoint old_corner; g_return_if_fail(AMITK_IS_ROI(roi)); g_return_if_fail(AMITK_ROI_TYPE_ISOCONTOUR(roi) || AMITK_ROI_TYPE_FREEHAND(roi)); if (!POINT_EQUAL(AMITK_ROI_VOXEL_SIZE(roi), voxel_size)) { old_corner = AMITK_VOLUME_CORNER(roi); roi_set_voxel_size(roi, voxel_size); if (roi->map_data != NULL) amitk_roi_calc_far_corner(roi); scaling = point_div(AMITK_VOLUME_CORNER(roi), old_corner); scaling = amitk_space_s2b_dim(AMITK_SPACE(roi), scaling); ref_point = AMITK_SPACE_OFFSET(roi); /* propagate this scaling operation to the children */ children = AMITK_OBJECT_CHILDREN(roi); while (children != NULL) { amitk_space_scale(children->data, ref_point, scaling); children = children->next; } } } /* function to recalculate the far corner of an isocontour roi */ /* only for isocontour and freehand rois */ void amitk_roi_calc_far_corner(AmitkRoi * roi) { AmitkPoint new_point; g_return_if_fail(AMITK_IS_ROI(roi)); g_return_if_fail(AMITK_ROI_TYPE_ISOCONTOUR(roi) || AMITK_ROI_TYPE_FREEHAND(roi)); POINT_MULT(roi->map_data->dim, roi->voxel_size, new_point); amitk_volume_set_corner(AMITK_VOLUME(roi), new_point); return; } /* returns a slice (in a volume structure) containing a data set defining the edges of the roi in the given space. returned data set is in the given coord frame. */ AmitkDataSet * amitk_roi_get_intersection_slice(const AmitkRoi * roi, const AmitkVolume * canvas_volume, const amide_real_t pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA ,const gboolean fill_map_roi #endif ) { AmitkDataSet * intersection = NULL; g_return_val_if_fail(AMITK_IS_ROI(roi), NULL); if (AMITK_ROI_UNDRAWN(roi)) return NULL; switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ISOCONTOUR_2D: intersection = amitk_roi_ISOCONTOUR_2D_get_intersection_slice(roi, canvas_volume, pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA , fill_map_roi #endif ); break; case AMITK_ROI_TYPE_ISOCONTOUR_3D: intersection = amitk_roi_ISOCONTOUR_3D_get_intersection_slice(roi, canvas_volume, pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA , fill_map_roi #endif ); break; case AMITK_ROI_TYPE_FREEHAND_2D: intersection = amitk_roi_FREEHAND_2D_get_intersection_slice(roi, canvas_volume, pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA , fill_map_roi #endif ); break; case AMITK_ROI_TYPE_FREEHAND_3D: intersection = amitk_roi_FREEHAND_3D_get_intersection_slice(roi, canvas_volume, pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA , fill_map_roi #endif ); break; default: g_error("roi type %d not implemented! file %s line %d",AMITK_ROI_TYPE(roi), __FILE__, __LINE__); break; } return intersection; } /* sets/resets the isocontour value of an isocontour ROI based on the given volume and voxel note: vol should be a slice for the case of ISOCONTOUR_2D/FREEHAND_2D */ void amitk_roi_set_isocontour(AmitkRoi * roi, AmitkDataSet * ds, AmitkVoxel start_voxel, amide_data_t isocontour_min_value, amide_data_t isocontour_max_value, AmitkRoiIsocontourRange isocontour_range) { g_return_if_fail(AMITK_ROI_TYPE_ISOCONTOUR(roi)); switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ISOCONTOUR_2D: amitk_roi_ISOCONTOUR_2D_set_isocontour(roi, ds, start_voxel, isocontour_min_value, isocontour_max_value, isocontour_range); break; case AMITK_ROI_TYPE_ISOCONTOUR_3D: default: amitk_roi_ISOCONTOUR_3D_set_isocontour(roi, ds, start_voxel, isocontour_min_value, isocontour_max_value, isocontour_range); break; } roi->center_of_mass_calculated = FALSE; g_signal_emit(G_OBJECT(roi), roi_signals[ROI_CHANGED], 0); return; } /* sets an area in the roi to zero (if erase is TRUE) or in (if erase if FALSE) */ /* only works for isocontour and freehand roi's */ void amitk_roi_manipulate_area(AmitkRoi * roi, gboolean erase, AmitkVoxel voxel, gint area_size) { g_return_if_fail(AMITK_ROI_TYPE_ISOCONTOUR(roi) || AMITK_ROI_TYPE_FREEHAND(roi)); /* if we're drawing a single point, do a quick check to see if we're already done */ if (!AMITK_ROI_UNDRAWN(roi) && (area_size == 0)) { if (erase) { if (amitk_raw_data_includes_voxel(roi->map_data, voxel)) { if (AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data, voxel)==0) { return; } } } else { if (amitk_raw_data_includes_voxel(roi->map_data, voxel)) { if (AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data, voxel)) { return; } } } } switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ISOCONTOUR_2D: amitk_roi_ISOCONTOUR_2D_manipulate_area(roi, erase, voxel, area_size); break; case AMITK_ROI_TYPE_ISOCONTOUR_3D: amitk_roi_ISOCONTOUR_3D_manipulate_area(roi, erase, voxel, area_size); break; case AMITK_ROI_TYPE_FREEHAND_2D: amitk_roi_FREEHAND_2D_manipulate_area(roi, erase, voxel, area_size); break; case AMITK_ROI_TYPE_FREEHAND_3D: amitk_roi_FREEHAND_3D_manipulate_area(roi, erase, voxel, area_size); break; default: g_error("unexpected case in %s at line %d\n", __FILE__, __LINE__); break; } roi->center_of_mass_calculated = FALSE; g_signal_emit(G_OBJECT(roi), roi_signals[ROI_CHANGED], 0); return; } /* only for isocontour and freehand rois */ AmitkPoint amitk_roi_get_center_of_mass (AmitkRoi * roi) { g_return_val_if_fail(AMITK_IS_ROI(roi), zero_point); g_return_val_if_fail((AMITK_ROI_TYPE_ISOCONTOUR(roi) || AMITK_ROI_TYPE_FREEHAND(roi)), zero_point); if (!roi->center_of_mass_calculated) { switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ISOCONTOUR_2D: amitk_roi_ISOCONTOUR_2D_calc_center_of_mass(roi); break; case AMITK_ROI_TYPE_ISOCONTOUR_3D: amitk_roi_ISOCONTOUR_3D_calc_center_of_mass(roi); break; case AMITK_ROI_TYPE_FREEHAND_2D: amitk_roi_FREEHAND_2D_calc_center_of_mass(roi); break; case AMITK_ROI_TYPE_FREEHAND_3D: amitk_roi_FREEHAND_3D_calc_center_of_mass(roi); break; default: g_error("unexpected case in %s at line %d\n", __FILE__, __LINE__); break; } } return amitk_space_s2b(AMITK_SPACE(roi), roi->center_of_mass); } void amitk_roi_set_type(AmitkRoi * roi, AmitkRoiType new_type) { g_return_if_fail(AMITK_IS_ROI(roi)); if ((new_type == AMITK_ROI_TYPE_ISOCONTOUR_2D) || (new_type == AMITK_ROI_TYPE_ISOCONTOUR_3D) || AMITK_ROI_TYPE_ISOCONTOUR(roi) || (new_type == AMITK_ROI_TYPE_FREEHAND_2D) || (new_type == AMITK_ROI_TYPE_FREEHAND_3D) || AMITK_ROI_TYPE_FREEHAND(roi)) g_return_if_fail(new_type == AMITK_ROI_TYPE(roi)); if (AMITK_ROI_TYPE(roi) != new_type) { roi->type = new_type; g_signal_emit(G_OBJECT(roi), roi_signals[ROI_TYPE_CHANGED], 0); g_signal_emit(G_OBJECT(roi), roi_signals[ROI_CHANGED], 0); } return; } /* iterates over the voxels in the given data set that are inside the given roi, and performs the specified calculation function for those points */ /* if inverse is true, the calculation is done for the portion of the data set not in the roi */ /* if accurate is true, uses much slower but more accurate calculation */ /* calulation should be a function taking the following arguments: calculation(AmitkVoxel dataset_voxel, amide_data_t value, amide_real_t voxel_fraction, gpointer data) */ void amitk_roi_calculate_on_data_set(const AmitkRoi * roi, const AmitkDataSet * ds, const guint frame, const guint gate, const gboolean inverse, const gboolean accurate, void (*calculation)(), gpointer data) { g_return_if_fail(AMITK_IS_ROI(roi)); g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (AMITK_ROI_UNDRAWN(roi)) return; switch(AMITK_ROI_TYPE(roi)) { case AMITK_ROI_TYPE_ELLIPSOID: if (accurate) amitk_roi_ELLIPSOID_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_ELLIPSOID_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; case AMITK_ROI_TYPE_CYLINDER: if (accurate) amitk_roi_CYLINDER_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_CYLINDER_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; case AMITK_ROI_TYPE_BOX: if (accurate) amitk_roi_BOX_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_BOX_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; case AMITK_ROI_TYPE_ISOCONTOUR_2D: if (accurate) amitk_roi_ISOCONTOUR_2D_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_ISOCONTOUR_2D_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; case AMITK_ROI_TYPE_ISOCONTOUR_3D: if (accurate) amitk_roi_ISOCONTOUR_3D_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_ISOCONTOUR_3D_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; case AMITK_ROI_TYPE_FREEHAND_2D: if (accurate) amitk_roi_FREEHAND_2D_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_FREEHAND_2D_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; case AMITK_ROI_TYPE_FREEHAND_3D: if (accurate) amitk_roi_FREEHAND_3D_calculate_on_data_set_accurate(roi, ds, frame, gate, inverse, calculation, data); else amitk_roi_FREEHAND_3D_calculate_on_data_set_fast(roi, ds, frame, gate, inverse, calculation, data); break; default: g_error("roi type %d not implemented! file %s line %d",AMITK_ROI_TYPE(roi), __FILE__, __LINE__); break; } return; } static void erase_volume(AmitkVoxel voxel, amide_data_t value, amide_real_t voxel_fraction, gpointer ds) { amitk_data_set_set_value(AMITK_DATA_SET(ds), voxel, (value*(1.0-voxel_fraction)+ AMITK_DATA_SET_THRESHOLD_MIN(ds, 0)*voxel_fraction), FALSE); return; } /* sets the volume inside/or outside of the given data set that is enclosed by roi equal to zero */ void amitk_roi_erase_volume(const AmitkRoi * roi, AmitkDataSet * ds, const gboolean outside, AmitkUpdateFunc update_func, gpointer update_data) { guint i_frame; guint i_gate; for (i_frame=0; i_framedistribution = NULL; } /* this is a no-op to get a data_set_changed signal */ amitk_data_set_set_value(AMITK_DATA_SET(ds), zero_voxel, amitk_data_set_get_value(AMITK_DATA_SET(ds), zero_voxel), TRUE); return; } const gchar * amitk_roi_type_get_name(const AmitkRoiType roi_type) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_ROI_TYPE); enum_value = g_enum_get_value(enum_class, roi_type); g_type_class_unref(enum_class); return enum_value->value_nick; } /* returns the minimum dimensional width of the roi with the largest voxel size */ /* only operates on ISOCONTOUR roi's */ amide_real_t amitk_rois_get_max_min_voxel_size(GList * objects) { amide_real_t min_voxel_size, temp; if (objects == NULL) return -1.0; /* invalid */ /* first process the rest of the list */ min_voxel_size = amitk_rois_get_max_min_voxel_size(objects->next); /* now process and compare to the children */ temp = amitk_rois_get_max_min_voxel_size(AMITK_OBJECT_CHILDREN(objects->data)); if (temp > 0) { if (min_voxel_size < 0.0) min_voxel_size = temp; else if (temp > min_voxel_size) min_voxel_size = temp; } /* and process this guy */ if (AMITK_IS_ROI(objects->data)) if (AMITK_ROI_TYPE_ISOCONTOUR(objects->data) || AMITK_ROI_TYPE_FREEHAND(objects->data)) { temp = point_min_dim(AMITK_ROI_VOXEL_SIZE(objects->data)); if (min_voxel_size < 0.0) min_voxel_size = temp; else if (temp > min_voxel_size) min_voxel_size = temp; } return min_voxel_size; } amide-1.0.6/amide-current/src/amitk_roi.h000066400000000000000000000143631423227705100202640ustar00rootroot00000000000000/* amitk_roi.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_ROI_H__ #define __AMITK_ROI_H__ #include "amitk_volume.h" #include "amitk_data_set.h" G_BEGIN_DECLS #define AMITK_TYPE_ROI (amitk_roi_get_type ()) #define AMITK_ROI(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_ROI, AmitkRoi)) #define AMITK_ROI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_ROI, AmitkRoiClass)) #define AMITK_IS_ROI(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_ROI)) #define AMITK_IS_ROI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_ROI)) #define AMITK_ROI_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_ROI, AmitkRoiClass)) #define AMITK_ROI_TYPE(roi) (AMITK_ROI(roi)->type) #define AMITK_ROI_SPECIFY_COLOR(roi) (AMITK_ROI(roi)->specify_color) #define AMITK_ROI_COLOR(roi) (AMITK_ROI(roi)->color) #define AMITK_ROI_ISOCONTOUR_MIN_VALUE(roi) (AMITK_ROI(roi)->isocontour_min_value) #define AMITK_ROI_ISOCONTOUR_MAX_VALUE(roi) (AMITK_ROI(roi)->isocontour_max_value) #define AMITK_ROI_ISOCONTOUR_RANGE(roi) (AMITK_ROI(roi)->isocontour_range) #define AMITK_ROI_VOXEL_SIZE(roi) (AMITK_ROI(roi)->voxel_size) #define AMITK_ROI_UNDRAWN(roi) (!AMITK_VOLUME_VALID(roi)) #define AMITK_ROI_TYPE_ISOCONTOUR(roi) ((AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_ISOCONTOUR_2D) || \ (AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_ISOCONTOUR_3D)) #define AMITK_ROI_TYPE_FREEHAND(roi) ((AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_FREEHAND_2D) || \ (AMITK_ROI_TYPE(roi) == AMITK_ROI_TYPE_FREEHAND_3D)) /* for iterative algorithms, how many subvoxels should we break the problem up into */ #define AMITK_ROI_GRANULARITY 4 /* # subvoxels in one dimension, so 1/64 is grain size */ //#define AMITK_ROI_GRANULARITY 10 - takes way to long typedef enum { AMITK_ROI_TYPE_ELLIPSOID, AMITK_ROI_TYPE_CYLINDER, AMITK_ROI_TYPE_BOX, AMITK_ROI_TYPE_ISOCONTOUR_2D, AMITK_ROI_TYPE_ISOCONTOUR_3D, AMITK_ROI_TYPE_FREEHAND_2D, AMITK_ROI_TYPE_FREEHAND_3D, AMITK_ROI_TYPE_NUM } AmitkRoiType; typedef enum { AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN, AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX, AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX, AMITK_ROI_ISOCONTOUR_RANGE_NUM } AmitkRoiIsocontourRange; typedef struct _AmitkRoiClass AmitkRoiClass; typedef struct _AmitkRoi AmitkRoi; struct _AmitkRoi { AmitkVolume parent; AmitkRoiType type; gboolean specify_color; /* if false, program guesses a good color to use */ rgba_t color; /* isocontour and freehand specific stuff */ AmitkPoint voxel_size; AmitkRawData * map_data; /* raw data */ gboolean center_of_mass_calculated; AmitkPoint center_of_mass; /* isocontour specific stuff */ amide_data_t isocontour_min_value; /* note, min and max are what were specified for the isocontour */ amide_data_t isocontour_max_value; /* what the user draws may lie outside of this range */ AmitkRoiIsocontourRange isocontour_range; }; struct _AmitkRoiClass { AmitkVolumeClass parent_class; void (* roi_changed) (AmitkRoi * roi); void (* roi_type_changed) (AmitkRoi * roi); }; /* Application-level methods */ GType amitk_roi_get_type (void); AmitkRoi * amitk_roi_new (AmitkRoiType type); GSList * amitk_roi_get_intersection_line (const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim); GSList * amitk_roi_free_points_list (GSList * list); AmitkDataSet * amitk_roi_get_intersection_slice (const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA , const gboolean fill_map_roi #endif ); void amitk_roi_set_specify_color (AmitkRoi * roi, gboolean specify_color); void amitk_roi_set_color (AmitkRoi * roi, rgba_t color); void amitk_roi_set_voxel_size (AmitkRoi * roi, AmitkPoint voxel_size); void amitk_roi_calc_far_corner (AmitkRoi * roi); void amitk_roi_set_isocontour (AmitkRoi * roi, AmitkDataSet * ds, AmitkVoxel start_voxel, amide_data_t isocontour_min_value, amide_data_t isocontour_max_value, AmitkRoiIsocontourRange isocontour_range); void amitk_roi_manipulate_area (AmitkRoi * roi, gboolean erase, AmitkVoxel erase_voxel, gint area_size); AmitkPoint amitk_roi_get_center_of_mass (AmitkRoi * roi); void amitk_roi_set_type (AmitkRoi * roi, AmitkRoiType new_type); void amitk_roi_calculate_on_data_set (const AmitkRoi * roi, const AmitkDataSet * ds, const guint frame, const guint gate, const gboolean inverse, const gboolean accurate, void (* calculation)(), gpointer data); void amitk_roi_erase_volume (const AmitkRoi * roi, AmitkDataSet * ds, const gboolean outside, AmitkUpdateFunc update_func, gpointer update_data); const gchar * amitk_roi_type_get_name (const AmitkRoiType roi_type); amide_real_t amitk_rois_get_max_min_voxel_size (GList * objects); /* external variables */ extern gchar * amitk_roi_menu_names[]; extern gchar * amitk_roi_menu_explanation[]; G_END_DECLS #endif /* __AMITK_ROI_H__ */ amide-1.0.6/amide-current/src/amitk_roi_variable_type.c000066400000000000000000001211261423227705100231610ustar00rootroot00000000000000/* amitk_roi_variable_type.c - used to generate the different amitk_roi_*.c files * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include #include "amitk_roi_`'m4_Variable_Type`'.h" #define ROI_TYPE_`'m4_Variable_Type`' #if defined(ROI_TYPE_CYLINDER) || defined(ROI_TYPE_ELLIPSOID) || defined (ROI_TYPE_BOX) static GSList * append_intersection_point(GSList * points_list, AmitkPoint new_point); static GSList * prepend_intersection_point(GSList * points_list, AmitkPoint new_point); static GSList * append_intersection_point(GSList * points_list, AmitkPoint new_point) { AmitkPoint * ppoint; ppoint = g_try_new(AmitkPoint,1); if (ppoint != NULL) { *ppoint = new_point; return g_slist_append(points_list, ppoint); } else { g_warning(_("Out of Memory")); return points_list; } } static GSList * prepend_intersection_point(GSList * points_list, AmitkPoint new_point) { AmitkPoint * ppoint; ppoint = g_try_new(AmitkPoint,1); if (ppoint != NULL) { *ppoint = new_point; return g_slist_prepend(points_list, ppoint); } else { g_warning(_("Out of Memory")); return points_list; } } /* returns a singly linked list of intersection points between the roi and the given canvas slice. returned points are in the canvas's coordinate space. */ GSList * amitk_roi_`'m4_Variable_Type`'_get_intersection_line(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim) { GSList * return_points = NULL; AmitkPoint view_point,temp_point; AmitkCorners slice_corners; AmitkPoint canvas_corner; AmitkPoint * temp_pointp; AmitkVoxel i; AmitkVoxel canvas_dim; gboolean voxel_in=FALSE, prev_voxel_intersection, saved=TRUE; #if defined(ROI_TYPE_ELLIPSOID) || defined(ROI_TYPE_CYLINDER) AmitkPoint center, radius; #endif #if defined(ROI_TYPE_CYLINDER) amide_real_t height; #endif /* make sure we've already defined this guy */ g_return_val_if_fail(!AMITK_ROI_UNDRAWN(roi), NULL); #ifdef AMIDE_DEBUG // g_print("roi %s --------------------\n",AMITK_OBJECT_NAME(roi)); // point_print("\t\tcorner", AMITK_VOLUME_CORNER(roi)); #endif #if defined(ROI_TYPE_ELLIPSOID) || defined(ROI_TYPE_CYLINDER) radius = point_cmult(0.5, AMITK_VOLUME_CORNER(roi)); center = amitk_space_b2s(AMITK_SPACE(roi), amitk_volume_get_center(AMITK_VOLUME(roi))); #endif #ifdef ROI_TYPE_CYLINDER height = AMITK_VOLUME_Z_CORNER(roi); #endif /* get the corners of the canvas slice */ canvas_corner = AMITK_VOLUME_CORNER(canvas_slice); slice_corners[0] = amitk_space_b2s(AMITK_SPACE(canvas_slice), AMITK_SPACE_OFFSET(canvas_slice)); slice_corners[1] = canvas_corner; /* iterate through the slice, putting all edge points in the list */ i.t = i.g = i.z=0; view_point.z = (slice_corners[0].z+slice_corners[1].z)/2.0; view_point.y = slice_corners[0].y+pixel_dim/2.0; canvas_dim.t = 0; canvas_dim.z = ceil((canvas_corner.z)/AMITK_VOLUME_Z_CORNER(canvas_slice)); canvas_dim.y = ceil((canvas_corner.y)/pixel_dim); canvas_dim.x = ceil((canvas_corner.x)/pixel_dim); g_return_val_if_fail(canvas_dim.z == 1, NULL); for (i.y=0; i.y < canvas_dim.y ; i.y++) { view_point.x = slice_corners[0].x+pixel_dim/2.0; prev_voxel_intersection = FALSE; for (i.x=0; i.x < canvas_dim.x ; i.x++) { temp_point = amitk_space_s2s(AMITK_SPACE(canvas_slice), AMITK_SPACE(roi), view_point); #ifdef ROI_TYPE_BOX voxel_in = point_in_box(temp_point, AMITK_VOLUME_CORNER(roi)); #endif #ifdef ROI_TYPE_CYLINDER voxel_in = point_in_elliptic_cylinder(temp_point, center, height, radius); #endif #ifdef ROI_TYPE_ELLIPSOID voxel_in = point_in_ellipsoid(temp_point,center,radius); #endif /* is it an edge */ if (voxel_in != prev_voxel_intersection) { /* than save the point */ saved = TRUE; temp_point = view_point; if (voxel_in ) { return_points = prepend_intersection_point(return_points, temp_point); } else { /* previous voxel should be returned */ temp_point.x = view_point.x - pixel_dim; /* backup one voxel */ return_points = append_intersection_point(return_points, temp_point); } } else { saved = FALSE; } prev_voxel_intersection = voxel_in; view_point.x += pixel_dim; /* advance one voxel */ } /* check if the edge of this row is still in the roi, if it is, add it as a point */ if ((voxel_in) && !(saved)) return_points = append_intersection_point(return_points, view_point); view_point.y += pixel_dim; /* advance one row */ } /* make sure the two ends meet */ temp_pointp = g_slist_nth_data(return_points, 0); if (return_points != NULL) return_points = append_intersection_point(return_points, *temp_pointp); return return_points; } #endif #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_2D) || defined(ROI_TYPE_FREEHAND_3D) /* returns 0 for something not in the roi, returns 1 for an edge, and 2 for something in the roi */ static amitk_format_UBYTE_t map_roi_edge(AmitkRawData * map_roi_ds, AmitkVoxel voxel) { amitk_format_UBYTE_t edge_value=0; AmitkVoxel new_voxel; #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) gint z; #endif #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) for (z=-1; z<=1; z++) { #endif new_voxel = voxel; #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) new_voxel.z += z; if (z != 0) /* don't reconsider the original point */ if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; #endif new_voxel.x--; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.y--; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.x++; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.x++; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.y++; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.y++; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.x--; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; new_voxel.x--; if (amitk_raw_data_includes_voxel(map_roi_ds, new_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(map_roi_ds,new_voxel) != 0) edge_value++; #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) } #endif #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) if (edge_value == 26 ) edge_value = 2; else edge_value = 1; #else /* ROI_TYPE_ISOCONTOUR_2D or ROI_TYPE_FREEHAND_2D */ if (edge_value == 8 ) edge_value = 2; else edge_value = 1; #endif return edge_value; } #define FAST_INTERSECTION_SLICE 1 /* intersection data is returned in the form of a volume slice */ AmitkDataSet * amitk_roi_`'m4_Variable_Type`'_get_intersection_slice(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA ,const gboolean fill_map_roi #endif ) { AmitkVoxel i_voxel; AmitkVoxel roi_voxel; AmitkVoxel start, end, dim; AmitkPoint view_point; AmitkPoint roi_point; AmitkCorners slice_corners; AmitkCorners intersection_corners; AmitkDataSet * intersection; AmitkPoint temp_point; AmitkPoint canvas_voxel_size; amitk_format_UBYTE_t value; #if FAST_INTERSECTION_SLICE AmitkPoint alt, start_point; AmitkPoint stride[AMITK_AXIS_NUM], last_point; AmitkAxis i_axis; #endif g_return_val_if_fail(!AMITK_ROI_UNDRAWN(roi), NULL); /* figure out the intersection between the canvas slice and the roi */ if (!amitk_volume_volume_intersection_corners(canvas_slice, AMITK_VOLUME(roi), intersection_corners)) return NULL; /* no intersection */ /* translate the intersection into voxel space */ canvas_voxel_size.x = canvas_voxel_size.y = pixel_dim; canvas_voxel_size.z = AMITK_VOLUME_Z_CORNER(canvas_slice); POINT_TO_VOXEL(intersection_corners[0], canvas_voxel_size, 0, 0, start); POINT_TO_VOXEL(intersection_corners[1], canvas_voxel_size, 0, 0, end); dim = voxel_add(voxel_sub(end, start), one_voxel); intersection = amitk_data_set_new(NULL, -1); intersection->raw_data = amitk_raw_data_new_2D_with_data0(AMITK_FORMAT_UBYTE,dim.y, dim.x); /* get the corners of the view slice in view coordinate space */ slice_corners[0] = amitk_space_b2s(AMITK_SPACE(canvas_slice), AMITK_SPACE_OFFSET(canvas_slice)); slice_corners[1] = AMITK_VOLUME_CORNER(canvas_slice); view_point.z = (slice_corners[0].z+slice_corners[1].z)/2.0; view_point.y = slice_corners[0].y+((double) start.y + 0.5)*pixel_dim; #if FAST_INTERSECTION_SLICE view_point.x = slice_corners[0].x+((double) start.x + 0.5)*pixel_dim; /* figure out what point in the roi we're going to start at */ start_point = amitk_space_s2s(AMITK_SPACE(canvas_slice),AMITK_SPACE(roi), view_point); /* figure out what stepping one voxel in a given direction in our slice coresponds to in our roi */ for (i_axis = 0; i_axis <= AMITK_AXIS_Y; i_axis++) { alt.x = (i_axis == AMITK_AXIS_X) ? pixel_dim : 0.0; alt.y = (i_axis == AMITK_AXIS_Y) ? pixel_dim : 0.0; alt.z = 0.0; alt = point_add(point_sub(amitk_space_s2b(AMITK_SPACE(canvas_slice), alt), AMITK_SPACE_OFFSET(canvas_slice)), AMITK_SPACE_OFFSET(roi)); stride[i_axis] = amitk_space_b2s(AMITK_SPACE(roi), alt); } roi_point = start_point; #endif i_voxel.z = i_voxel.g = i_voxel.t = 0; for (i_voxel.y=0; i_voxel.yvoxel_size, 0, 0, roi_voxel); if (amitk_raw_data_includes_voxel(roi->map_data, roi_voxel)) { value = AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, roi_voxel); #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_FREEHAND_2D) if (value > 0) AMITK_RAW_DATA_UBYTE_SET_CONTENT(intersection->raw_data, i_voxel) = 1; #else /* ISOCONTOUR_3D or FREEHAND_3D */ #ifdef AMIDE_LIBGNOMECANVAS_AA if (value > 0) AMITK_RAW_DATA_UBYTE_SET_CONTENT(intersection->raw_data, i_voxel) = value; #else if ((value == 1) || ((value > 0) && fill_map_roi)) AMITK_RAW_DATA_UBYTE_SET_CONTENT(intersection->raw_data, i_voxel) = 1; #endif #endif } #if FAST_INTERSECTION_SLICE POINT_ADD(roi_point, stride[AMITK_AXIS_X], roi_point); #else view_point.x += pixel_dim; #endif } #if FAST_INTERSECTION_SLICE POINT_ADD(last_point, stride[AMITK_AXIS_Y], roi_point); #else view_point.y += pixel_dim; #endif } #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_FREEHAND_2D) #ifndef AMIDE_LIBGNOMECANVAS_AA if (!fill_map_roi) #endif { /* mark the edges as such on the 2D isocontour or freehand slices */ i_voxel.z = i_voxel.g = i_voxel.t = 0; for (i_voxel.y=0; i_voxel.yraw_data, i_voxel)) AMITK_RAW_DATA_UBYTE_SET_CONTENT(intersection->raw_data, i_voxel) = map_roi_edge(intersection->raw_data, i_voxel); } #endif amitk_space_copy_in_place(AMITK_SPACE(intersection), AMITK_SPACE(canvas_slice)); intersection->voxel_size = canvas_voxel_size; POINT_MULT(start, intersection->voxel_size, temp_point); amitk_space_set_offset(AMITK_SPACE(intersection), amitk_space_s2b(AMITK_SPACE(canvas_slice), temp_point)); temp_point = AMITK_SPACE_OFFSET(intersection); POINT_MULT(intersection->raw_data->dim, intersection->voxel_size, AMITK_VOLUME_CORNER(intersection)); return intersection; } #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) /* the data in temp_rd is setup as follows: bit 1 -> is the voxel in the isocontour bit 2 -> has the voxel been checked bit 3 -> increment x for backup bit 4 -> decrement x for backup bit 5 -> increment y for backup bit 6 -> decrement y for backup bit 7 -> increment z for backup bit 8 -> decrement z for backup */ static void isocontour_consider(const AmitkDataSet * ds, const AmitkRawData * temp_rd, AmitkVoxel ds_voxel, const amide_data_t iso_min_value, const amide_data_t iso_max_value, const AmitkRoiIsocontourRange iso_range) { AmitkVoxel i_voxel; AmitkVoxel roi_voxel; gboolean found; gboolean done; amide_data_t voxel_value; roi_voxel = ds_voxel; roi_voxel.t = roi_voxel.g = 0; i_voxel =roi_voxel; done=FALSE; /* the starting point is in by definition */ AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd, roi_voxel) |= 0x03; /* while we still have neighbor voxels to check */ while (!done) { found = FALSE; /* find a neighbor to check, consider the 8 adjoining voxels, or 26 in the case of 3D */ #ifdef ROI_TYPE_ISOCONTOUR_3D for (i_voxel.z = (roi_voxel.z >= 1) ? roi_voxel.z-1 : 0; (i_voxel.z < temp_rd->dim.z) && (i_voxel.z <= roi_voxel.z+1) && (!found); i_voxel.z++) #endif for (i_voxel.y = (roi_voxel.y >= 1) ? roi_voxel.y-1 : 0; (i_voxel.y < temp_rd->dim.y) && (i_voxel.y <= roi_voxel.y+1) && (!found); i_voxel.y++) for (i_voxel.x = (roi_voxel.x >= 1) ? roi_voxel.x-1 : 0; (i_voxel.x < temp_rd->dim.x) && (i_voxel.x <= roi_voxel.x+1) && (!found); i_voxel.x++) if (!(AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, i_voxel) & 0x02)) { /* don't recheck something we've already checked */ AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x02; /* it's been checked */ ds_voxel.z = i_voxel.z; ds_voxel.y = i_voxel.y; ds_voxel.x = i_voxel.x; voxel_value = amitk_data_set_get_value(ds, ds_voxel); if (((iso_range == AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN) && (voxel_value >= iso_min_value)) || ((iso_range == AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX) && (voxel_value <= iso_max_value)) || ((iso_range == AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX) && (voxel_value >= iso_min_value) && (voxel_value <= iso_max_value))) { AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x01; /* it's in */ /* store backup info */ #ifdef ROI_TYPE_ISOCONTOUR_3D if (i_voxel.z > roi_voxel.z) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x40; else if (i_voxel.z < roi_voxel.z) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x80; #endif if (i_voxel.y > roi_voxel.y) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x10; else if (i_voxel.y < roi_voxel.y) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x20; if (i_voxel.x > roi_voxel.x) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x04; else if (i_voxel.x < roi_voxel.x) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,i_voxel) |= 0x08; /* start next iteration at this voxel */ roi_voxel = i_voxel; found = TRUE; } } if (!found) { /* all neighbors exhaustively checked, backup */ /* backup to previous voxel */ i_voxel = roi_voxel; #ifdef ROI_TYPE_ISOCONTOUR_3D if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, roi_voxel) & 0x80) i_voxel.z++; else if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, roi_voxel) & 0x40) i_voxel.z--; #endif if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, roi_voxel) & 0x20) i_voxel.y++; else if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, roi_voxel) & 0x10) i_voxel.y--; if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, roi_voxel) & 0x08) i_voxel.x++; else if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, roi_voxel) & 0x04) i_voxel.x--; /* the inital voxel will backup to itself, which is why we get out of the loop */ if (VOXEL_EQUAL(roi_voxel, i_voxel)) done = TRUE; else roi_voxel = i_voxel; } } return; } void amitk_roi_`'m4_Variable_Type`'_set_isocontour(AmitkRoi * roi, AmitkDataSet * ds, AmitkVoxel iso_voxel, amide_data_t iso_min_value, amide_data_t iso_max_value, AmitkRoiIsocontourRange iso_range) { AmitkRawData * temp_rd; AmitkPoint temp_point; AmitkVoxel min_voxel, max_voxel, i_voxel; amide_data_t temp_min_value, temp_max_value; g_return_if_fail(roi->type == AMITK_ROI_TYPE_`'m4_Variable_Type`'); /* what we're setting the isocontour too */ roi->isocontour_min_value = iso_min_value; roi->isocontour_max_value = iso_max_value; roi->isocontour_range = iso_range; /* we first make a raw data set the size of the data set to record the in/out values */ #if defined(ROI_TYPE_ISOCONTOUR_2D) temp_rd = amitk_raw_data_new_2D_with_data0(AMITK_FORMAT_UBYTE, ds->raw_data->dim.y, ds->raw_data->dim.x); #elif defined(ROI_TYPE_ISOCONTOUR_3D) temp_rd = amitk_raw_data_new_3D_with_data0(AMITK_FORMAT_UBYTE, ds->raw_data->dim.z, ds->raw_data->dim.y, ds->raw_data->dim.x); #endif /* epsilon guards for floating point rounding */ temp_min_value = roi->isocontour_min_value-EPSILON*fabs(roi->isocontour_min_value); temp_max_value = roi->isocontour_max_value+EPSILON*fabs(roi->isocontour_max_value); /* fill in the data set */ isocontour_consider(ds, temp_rd, iso_voxel, temp_min_value, temp_max_value, iso_range); /* figure out the min and max dimensions */ min_voxel = max_voxel = iso_voxel; i_voxel.t = i_voxel.g = 0; for (i_voxel.z=0; i_voxel.z < temp_rd->dim.z; i_voxel.z++) { for (i_voxel.y=0; i_voxel.y < temp_rd->dim.y; i_voxel.y++) { for (i_voxel.x=0; i_voxel.x < temp_rd->dim.x; i_voxel.x++) { if (AMITK_RAW_DATA_UBYTE_CONTENT(temp_rd, i_voxel) & 0x1) { if (min_voxel.x > i_voxel.x) min_voxel.x = i_voxel.x; if (max_voxel.x < i_voxel.x) max_voxel.x = i_voxel.x; if (min_voxel.y > i_voxel.y) min_voxel.y = i_voxel.y; if (max_voxel.y < i_voxel.y) max_voxel.y = i_voxel.y; #ifdef ROI_TYPE_ISOCONTOUR_3D if (min_voxel.z > i_voxel.z) min_voxel.z = i_voxel.z; if (max_voxel.z < i_voxel.z) max_voxel.z = i_voxel.z; #endif } } } } /* transfer the subset of the data set that contains positive information */ if (roi->map_data != NULL) g_object_unref(roi->map_data); #if defined(ROI_TYPE_ISOCONTOUR_2D) roi->map_data = amitk_raw_data_new_2D_with_data0(AMITK_FORMAT_UBYTE, max_voxel.y-min_voxel.y+1, max_voxel.x-min_voxel.x+1); #elif defined(ROI_TYPE_ISOCONTOUR_3D) roi->map_data = amitk_raw_data_new_3D_with_data0(AMITK_FORMAT_UBYTE, max_voxel.z-min_voxel.z+1, max_voxel.y-min_voxel.y+1, max_voxel.x-min_voxel.x+1); #endif i_voxel.t = i_voxel.g = 0; for (i_voxel.z=0; i_voxel.zmap_data->dim.z; i_voxel.z++) for (i_voxel.y=0; i_voxel.ymap_data->dim.y; i_voxel.y++) for (i_voxel.x=0; i_voxel.xmap_data->dim.x; i_voxel.x++) { #if defined(ROI_TYPE_ISOCONTOUR_2D) AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data, i_voxel) = 0x01 & AMITK_RAW_DATA_UBYTE_2D_CONTENT(temp_rd, i_voxel.y+min_voxel.y, i_voxel.x+min_voxel.x); #elif defined(ROI_TYPE_ISOCONTOUR_3D) AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data, i_voxel) = 0x01 & AMITK_RAW_DATA_UBYTE_3D_CONTENT(temp_rd, i_voxel.z+min_voxel.z,i_voxel.y+min_voxel.y, i_voxel.x+min_voxel.x); #endif } g_object_unref(temp_rd); /* mark the edges as such */ i_voxel.t = i_voxel.g = 0; for (i_voxel.z=0; i_voxel.zmap_data->dim.z; i_voxel.z++) for (i_voxel.y=0; i_voxel.ymap_data->dim.y; i_voxel.y++) for (i_voxel.x=0; i_voxel.xmap_data->dim.x; i_voxel.x++) if (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, i_voxel)) AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data, i_voxel) = map_roi_edge(roi->map_data, i_voxel); /* and set the rest of the important info for the data set */ amitk_space_copy_in_place(AMITK_SPACE(roi), AMITK_SPACE(ds)); roi->voxel_size = ds->voxel_size; POINT_MULT(min_voxel, ds->voxel_size, temp_point); temp_point = amitk_space_s2b(AMITK_SPACE(ds), temp_point); amitk_space_set_offset(AMITK_SPACE(roi), temp_point); amitk_roi_calc_far_corner(roi); return; } #endif void amitk_roi_`'m4_Variable_Type`'_manipulate_area(AmitkRoi * roi, gboolean erase, AmitkVoxel voxel, gint area_size) { AmitkVoxel i_voxel, j_voxel; AmitkVoxel new_dim; AmitkVoxel offset; AmitkVoxel map_data_dim; AmitkPoint new_offset; AmitkRawData * temp_rd; gboolean dim_changed=FALSE; #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) g_return_if_fail(roi->map_data != NULL); #endif j_voxel = zero_voxel; i_voxel = zero_voxel; /* check if we need to increase the size of the roi */ if (!erase || (roi->map_data == NULL)) { /* never need to do for an erase, unless map_data hasn't yet been allocated */ if (roi->map_data != NULL) { new_dim = roi->map_data->dim; map_data_dim = roi->map_data->dim; } else { new_dim = zero_voxel; map_data_dim = zero_voxel; } offset = zero_voxel; #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) if ((voxel.z-area_size) < 0) { offset.z = -(voxel.z-area_size); new_dim.z += offset.z; dim_changed = TRUE; } if ((voxel.z+area_size) > (map_data_dim.z-1)) { new_dim.z += (voxel.z-(map_data_dim.z-1))+area_size; dim_changed = TRUE; } #endif if ((voxel.y-area_size) < 0) { offset.y = -(voxel.y-area_size); new_dim.y += offset.y; dim_changed = TRUE; } if ((voxel.y+area_size) > (map_data_dim.y-1)) { new_dim.y += (voxel.y-(map_data_dim.y-1))+area_size; dim_changed = TRUE; } if ((voxel.x-area_size) < 0) { offset.x = -(voxel.x-area_size); new_dim.x += offset.x; dim_changed = TRUE; } if ((voxel.x+area_size) > (map_data_dim.x-1)) { new_dim.x += (voxel.x-(map_data_dim.x-1))+area_size; dim_changed = TRUE; } if (dim_changed) { #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_FREEHAND_2D) temp_rd = amitk_raw_data_new_2D_with_data0(AMITK_FORMAT_UBYTE, new_dim.y, new_dim.x); #else /* ROI_TYPE_ISOCONTOUR_3D or ROI_TYPE_FREEHAND_3D */ temp_rd = amitk_raw_data_new_3D_with_data0(AMITK_FORMAT_UBYTE, new_dim.z, new_dim.y, new_dim.x); #endif /* copy the old map data over */ if (roi->map_data != NULL) { #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) for (i_voxel.z = 0, j_voxel.z=offset.z; i_voxel.z < map_data_dim.z; i_voxel.z++, j_voxel.z++) #endif for (i_voxel.y = 0, j_voxel.y=offset.y; i_voxel.y < map_data_dim.y; i_voxel.y++, j_voxel.y++) for (i_voxel.x = 0, j_voxel.x=offset.x; i_voxel.x < map_data_dim.x; i_voxel.x++, j_voxel.x++) AMITK_RAW_DATA_UBYTE_SET_CONTENT(temp_rd,j_voxel)= AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data,i_voxel); g_object_unref(roi->map_data); } roi->map_data = temp_rd; /* shift the offset to account for the large ROI */ POINT_MULT(offset, roi->voxel_size, new_offset); new_offset = point_cmult(-(1.0+EPSILON), new_offset); new_offset = amitk_space_s2b(AMITK_SPACE(roi), new_offset); amitk_space_set_offset(AMITK_SPACE(roi), new_offset); amitk_roi_calc_far_corner(roi); } } /* sanity check */ g_return_if_fail(roi->map_data != NULL); /* do the erase or drawing */ #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) for (i_voxel.z = voxel.z-area_size; i_voxel.z <= voxel.z+area_size; i_voxel.z++) #endif for (i_voxel.y = voxel.y-area_size; i_voxel.y <= voxel.y+area_size; i_voxel.y++) for (i_voxel.x = voxel.x-area_size; i_voxel.x <= voxel.x+area_size; i_voxel.x++) if (erase) { if (amitk_raw_data_includes_voxel(roi->map_data, i_voxel)) AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data,i_voxel)=0; } else { if (amitk_raw_data_includes_voxel(roi->map_data, i_voxel)) AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data,i_voxel)=1; } /* re edge the neighboring points */ #if defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_3D) for (i_voxel.z = voxel.z-1-area_size; i_voxel.z <= voxel.z+1+area_size; i_voxel.z++) #endif for (i_voxel.y = voxel.y-1-area_size; i_voxel.y <= voxel.y+1+area_size; i_voxel.y++) for (i_voxel.x = voxel.x-1-area_size; i_voxel.x <= voxel.x+1+area_size; i_voxel.x++) if (amitk_raw_data_includes_voxel(roi->map_data, i_voxel)) if (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, i_voxel)) AMITK_RAW_DATA_UBYTE_SET_CONTENT(roi->map_data, i_voxel) = map_roi_edge(roi->map_data, i_voxel); return; } void amitk_roi_`'m4_Variable_Type`'_calc_center_of_mass(AmitkRoi * roi) { AmitkVoxel i_voxel; guint voxels=0; AmitkPoint center_of_mass; AmitkPoint roi_voxel_size; AmitkPoint current_point; roi_voxel_size = AMITK_ROI_VOXEL_SIZE(roi); center_of_mass = zero_point; i_voxel.t = i_voxel.g = 0; for (i_voxel.z=0; i_voxel.zmap_data->dim.z; i_voxel.z++) for (i_voxel.y=0; i_voxel.ymap_data->dim.y; i_voxel.y++) for (i_voxel.x=0; i_voxel.xmap_data->dim.x; i_voxel.x++) if (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, i_voxel)) { voxels++; VOXEL_TO_POINT(i_voxel, roi_voxel_size, current_point); POINT_ADD(current_point, center_of_mass, center_of_mass); } roi->center_of_mass = point_cmult(1.0/((gdouble) voxels), center_of_mass); roi->center_of_mass_calculated=TRUE; } #endif /* iterates over the voxels in the given data set that are inside the given roi, and performs the specified calculation function for those points */ /* calulation should be a function taking the following arguments: calculation(AmitkVoxel dataset_voxel, amide_data_t value, amide_real_t voxel_fraction, gpointer data) */ void amitk_roi_`'m4_Variable_Type`'_calculate_on_data_set_fast(const AmitkRoi * roi, const AmitkDataSet * ds, const guint frame, const guint gate, const gboolean inverse, void (* calculation)(), gpointer data) { AmitkPoint roi_pt_corner, roi_pt_center, fine_roi_pt; AmitkPoint fine_ds_pt, far_ds_pt, center_ds_pt; amide_data_t value; amide_real_t voxel_fraction; AmitkVoxel i,j, k; AmitkVoxel start, dim, ds_dim; gboolean corner_in, center_in; AmitkRawData * next_plane_in; AmitkRawData * curr_plane_in; gboolean small_dimensions; AmitkCorners intersection_corners; AmitkPoint ds_voxel_size; AmitkPoint sub_voxel_size; amide_real_t grain_size; #if defined (ROI_TYPE_BOX) AmitkPoint box_corner; box_corner = AMITK_VOLUME_CORNER(roi); #endif #if defined(ROI_TYPE_ELLIPSOID) || defined(ROI_TYPE_CYLINDER) AmitkPoint center; AmitkPoint radius; #if defined(ROI_TYPE_CYLINDER) amide_real_t height; height = AMITK_VOLUME_Z_CORNER(roi); #endif center = amitk_space_b2s(AMITK_SPACE(roi), amitk_volume_get_center(AMITK_VOLUME(roi))); radius = point_cmult(0.5, AMITK_VOLUME_CORNER(roi)); #endif #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_2D) || defined(ROI_TYPE_FREEHAND_3D) AmitkPoint roi_voxel_size; AmitkVoxel roi_voxel; roi_voxel_size = AMITK_ROI_VOXEL_SIZE(roi); #endif ds_voxel_size = AMITK_DATA_SET_VOXEL_SIZE(ds); sub_voxel_size = point_cmult(1.0/AMITK_ROI_GRANULARITY, ds_voxel_size); ds_dim = AMITK_DATA_SET_DIM(ds); grain_size = 1.0/(AMITK_ROI_GRANULARITY*AMITK_ROI_GRANULARITY*AMITK_ROI_GRANULARITY); /* figure out the intersection between the data set and the roi */ if (inverse) { start = zero_voxel; dim = ds_dim; } else { if (!amitk_volume_volume_intersection_corners(AMITK_VOLUME(ds), AMITK_VOLUME(roi), intersection_corners)) { dim = zero_voxel; /* no intersection */ start = zero_voxel; } else { /* translate the intersection into voxel space */ POINT_TO_VOXEL(intersection_corners[0], ds_voxel_size, 0, 0, start); POINT_TO_VOXEL(intersection_corners[1], ds_voxel_size, 0, 0, dim); dim = voxel_add(voxel_sub(dim, start), one_voxel); } } /* check if we're done already */ if ((dim.x == 0) || (dim.y == 0) || (dim.z == 0)) { return; } /* if we have any small dimensions, make sure we always iterate over sub voxels */ if ((dim.x == 1) || (dim.y == 1) || (dim.z == 1) || (ds_dim.x == 1) || (ds_dim.y == 1) || (ds_dim.z == 1)) small_dimensions = TRUE; else small_dimensions = FALSE; /* over-iterate, as our initial edges will always be considered out of the roi */ start.x -= 1; start.y -= 1; start.z -= 1; dim.x += 1; dim.y += 1; dim.z += 1; /* check all dimensions */ if (start.x < 0) start.x = 0; if (start.y < 0) start.y = 0; if (start.z < 0) start.z = 0; if (dim.x+start.x > ds_dim.x) dim.x = ds_dim.x-start.x; if (dim.y+start.y > ds_dim.y) dim.y = ds_dim.y-start.y; if (dim.z+start.z > ds_dim.z) dim.z = ds_dim.z-start.z; /* start and dim specify (in the data set's voxel space) the voxels in the volume we should be iterating over */ /* these two arrays are used to store whether the voxel vertices are in the ROI or not */ next_plane_in = amitk_raw_data_new_2D_with_data0(AMITK_FORMAT_UBYTE, dim.y+1, dim.x+1); curr_plane_in = amitk_raw_data_new_2D_with_data0(AMITK_FORMAT_UBYTE, dim.y+1, dim.x+1); j.t = frame; j.g = gate; i.t = k.t = i.g = k.g = 0; for (i.z = 0; i.z < dim.z; i.z++) { j.z = i.z+start.z; far_ds_pt.z = (j.z+1)*ds_voxel_size.z; center_ds_pt.z = (j.z+0.5)*ds_voxel_size.z; for (i.y = 0; i.y < dim.y; i.y++) { j.y = i.y+start.y; far_ds_pt.y = (j.y+1)*ds_voxel_size.y; center_ds_pt.y = (j.y+0.5)*ds_voxel_size.y; for (i.x = 0; i.x < dim.x; i.x++) { j.x = i.x+start.x; far_ds_pt.x = (j.x+1)*ds_voxel_size.x; center_ds_pt.x = (j.x+0.5)*ds_voxel_size.x; /* figure out if the center and the next far corner is in the roi or not */ /* get the corresponding roi points */ roi_pt_corner = amitk_space_s2s(AMITK_SPACE(ds), AMITK_SPACE(roi), far_ds_pt); roi_pt_center = amitk_space_s2s(AMITK_SPACE(ds), AMITK_SPACE(roi), center_ds_pt); /* calculate the one corner of the voxel "box" to determine if it's in or not */ /* along with the center of the voxel */ #if defined (ROI_TYPE_BOX) corner_in = point_in_box(roi_pt_corner, box_corner); center_in = point_in_box(roi_pt_center, box_corner); #endif #if defined(ROI_TYPE_CYLINDER) corner_in = point_in_elliptic_cylinder(roi_pt_corner, center, height, radius); center_in = point_in_elliptic_cylinder(roi_pt_center, center, height, radius); #endif #if defined(ROI_TYPE_ELLIPSOID) corner_in = point_in_ellipsoid(roi_pt_corner,center,radius); center_in = point_in_ellipsoid(roi_pt_center,center,radius); #endif #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_2D) || defined(ROI_TYPE_FREEHAND_3D) POINT_TO_VOXEL(roi_pt_corner, roi_voxel_size, 0, 0,roi_voxel); corner_in = (amitk_raw_data_includes_voxel(roi->map_data, roi_voxel) && (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, roi_voxel) != 0)); POINT_TO_VOXEL(roi_pt_center, roi_voxel_size, 0, 0,roi_voxel); center_in = (amitk_raw_data_includes_voxel(roi->map_data, roi_voxel) && (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, roi_voxel) != 0)); #endif AMITK_RAW_DATA_UBYTE_2D_SET_CONTENT(next_plane_in,i.y+1,i.x+1)=corner_in; if (AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y,i.x) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y,i.x+1) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y+1,i.x) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y+1,i.x+1) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y,i.x) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y,i.x+1) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y+1,i.x) && AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y+1,i.x+1) && center_in) { /* this voxel is entirely in the ROI */ if (!inverse) { value = amitk_data_set_get_value(ds,j); (*calculation)(j, value, 1.0, data); } } else if (AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y,i.x) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y,i.x+1) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y+1,i.x) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(curr_plane_in,i.y+1,i.x+1) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y,i.x) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y,i.x+1) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y+1,i.x) || AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,i.y+1,i.x+1) || center_in || small_dimensions) { /* this voxel is partially in the ROI, will need to do subvoxel analysis */ value = amitk_data_set_get_value(ds,j); voxel_fraction=0; for (k.z = 0;k.zmap_data, roi_voxel) && (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, roi_voxel) != 0)) voxel_fraction += grain_size; #endif } /* k.x loop */ } /* k.y loop */ } /* k.z loop */ if (!inverse) { (*calculation)(j, value, voxel_fraction, data); } else { (*calculation)(j, value, 1.0-voxel_fraction, data); } } else { /* this voxel is outside the ROI */ if (inverse) { value = amitk_data_set_get_value(ds,j); (*calculation)(j, value, 1.0, data); } } } /* i.x loop */ } /* i.y loop */ /* need to copy over the info on which voxel corners are in the roi */ for (k.y=0;k.y < next_plane_in->dim.y; k.y++) for (k.x=0;k.x < next_plane_in->dim.x; k.x++) AMITK_RAW_DATA_UBYTE_2D_SET_CONTENT(curr_plane_in,k.y,k.x) = AMITK_RAW_DATA_UBYTE_2D_CONTENT(next_plane_in,k.y,k.x); } /* i.z loop */ /* trash collection */ g_object_unref(curr_plane_in); g_object_unref(next_plane_in); return; } /* iterates over the voxels in the given data set that are inside the given roi, and performs the specified calculation function for those points */ /* calulation should be a function taking the following arguments: calculation(AmitkVoxel dataset_voxel, amide_data_t value, amide_real_t voxel_fraction, gpointer data) */ void amitk_roi_`'m4_Variable_Type`'_calculate_on_data_set_accurate(const AmitkRoi * roi, const AmitkDataSet * ds, const guint frame, const guint gate, const gboolean inverse, void (* calculation)(), gpointer data) { AmitkPoint fine_roi_pt, fine_ds_pt; amide_data_t value; amide_real_t voxel_fraction; AmitkVoxel j, k; AmitkVoxel start, end, ds_dim; AmitkCorners intersection_corners; AmitkPoint ds_voxel_size; AmitkPoint sub_voxel_size; amide_real_t grain_size; #if defined (ROI_TYPE_BOX) AmitkPoint box_corner; box_corner = AMITK_VOLUME_CORNER(roi); #endif #if defined(ROI_TYPE_ELLIPSOID) || defined(ROI_TYPE_CYLINDER) AmitkPoint center; AmitkPoint radius; #if defined(ROI_TYPE_CYLINDER) amide_real_t height; height = AMITK_VOLUME_Z_CORNER(roi); #endif center = amitk_space_b2s(AMITK_SPACE(roi), amitk_volume_get_center(AMITK_VOLUME(roi))); radius = point_cmult(0.5, AMITK_VOLUME_CORNER(roi)); #endif #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_2D) || defined(ROI_TYPE_FREEHAND_3D) AmitkPoint roi_voxel_size; AmitkVoxel roi_voxel; roi_voxel_size = AMITK_ROI_VOXEL_SIZE(roi); #endif ds_voxel_size = AMITK_DATA_SET_VOXEL_SIZE(ds); sub_voxel_size = point_cmult(1.0/AMITK_ROI_GRANULARITY, ds_voxel_size); ds_dim = AMITK_DATA_SET_DIM(ds); grain_size = 1.0/(AMITK_ROI_GRANULARITY*AMITK_ROI_GRANULARITY*AMITK_ROI_GRANULARITY); /* figure out the intersection between the data set and the roi */ if (inverse) { start = zero_voxel; end = voxel_sub(ds_dim, one_voxel); } else { if (!amitk_volume_volume_intersection_corners(AMITK_VOLUME(ds), AMITK_VOLUME(roi), intersection_corners)) { end = zero_voxel; /* no intersection */ start = one_voxel; } else { /* translate the intersection into voxel space */ POINT_TO_VOXEL(intersection_corners[0], ds_voxel_size, 0, 0, start); POINT_TO_VOXEL(intersection_corners[1], ds_voxel_size, 0, 0, end); } } /* check if we're done already */ if ((start.x > end.x) || (start.y > end.y) || (start.z > end.z)) return; /* check all dimensions */ if (start.x < 0) start.x = 0; if (start.y < 0) start.y = 0; if (start.z < 0) start.z = 0; if (end.x >= ds_dim.x) end.x = ds_dim.x-1; if (end.y >= ds_dim.y) end.y = ds_dim.y-1; if (end.z >= ds_dim.z) end.z = ds_dim.z-1; /* start and end specify (in the data set's voxel space) the voxels in the volume we should be iterating over */ j.t = frame; j.g = gate; k.t = k.g = 0; for (j.z = start.z; j.z <= end.z; j.z++) { for (j.y = start.y; j.y <= end.y; j.y++) { for (j.x = start.x; j.x <= end.x; j.x++) { value = amitk_data_set_get_value(ds,j); voxel_fraction=0; for (k.z = 0;k.zmap_data, roi_voxel) && (AMITK_RAW_DATA_UBYTE_CONTENT(roi->map_data, roi_voxel) != 0)) voxel_fraction+=grain_size; #endif fine_ds_pt.x += sub_voxel_size.x; } /* k.x loop */ } /* k.y loop */ } /* k.z loop */ if (!inverse) { if (voxel_fraction > 0.0) { (*calculation)(j, value, voxel_fraction, data); } } else { if (voxel_fraction < 1.0) { (*calculation)(j, value, 1.0-voxel_fraction, data); } } } /* i.x loop */ } /* i.y loop */ } /* i.z loop */ return; } amide-1.0.6/amide-current/src/amitk_roi_variable_type.h000066400000000000000000000057001423227705100231650ustar00rootroot00000000000000/* amitk_roi_variable_type.h - used to generate the different amitk_roi_*.h files * * Part of amide - Amide's a Medical Image Data Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_ROI_`'m4_Internal_Data_Format`'_H__ #define __AMITK_ROI_`'m4_Variable_Type`'_H__ /* header files that are always needed with this file */ #include "amitk_roi.h" #include "amitk_data_set.h" /* function declarations */ #define ROI_TYPE_`'m4_Variable_Type`' #if defined(ROI_TYPE_ELLIPSOID) || defined(ROI_TYPE_CYLINDER) || defined(ROI_TYPE_BOX) GSList * amitk_roi_`'m4_Variable_Type`'_get_intersection_line(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim); #endif #if defined(ROI_TYPE_ISOCONTOUR_2D) || defined(ROI_TYPE_ISOCONTOUR_3D) || defined(ROI_TYPE_FREEHAND_2D) || defined(ROI_TYPE_FREEHAND_3D) AmitkDataSet * amitk_roi_`'m4_Variable_Type`'_get_intersection_slice(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_dim #ifndef AMIDE_LIBGNOMECANVAS_AA ,const gboolean fill_roi #endif ); void amitk_roi_`'m4_Variable_Type`'_set_isocontour(AmitkRoi * roi, AmitkDataSet * ds, AmitkVoxel iso_vp, amide_data_t iso_min_value, amide_data_t iso_max_value, AmitkRoiIsocontourRange iso_range); void amitk_roi_`'m4_Variable_Type`'_manipulate_area(AmitkRoi * roi, gboolean erase, AmitkVoxel voxel, gint area_size); void amitk_roi_`'m4_Variable_Type`'_calc_center_of_mass(AmitkRoi * roi); #endif void amitk_roi_`'m4_Variable_Type`'_calculate_on_data_set_fast(const AmitkRoi * roi, const AmitkDataSet * ds, const guint frame, const guint gate, const gboolean inverse, void (*calculation)(), gpointer data); void amitk_roi_`'m4_Variable_Type`'_calculate_on_data_set_accurate(const AmitkRoi * roi, const AmitkDataSet * ds, const guint frame, const guint gate, const gboolean inverse, void (*calculation)(), gpointer data); #undef ROI_TYPE_`'m4_Variable_Type`' #endif /* __AMITK_ROI_`'m4_Variable_Type`'_H__ */ amide-1.0.6/amide-current/src/amitk_space.c000066400000000000000000000556171423227705100205700ustar00rootroot00000000000000/* amitk_space.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_space.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" enum { SPACE_SHIFT, SPACE_ROTATE, SPACE_INVERT, SPACE_TRANSFORM, SPACE_TRANSFORM_AXES, SPACE_SCALE, SPACE_CHANGED, LAST_SIGNAL }; /* local functions */ static void space_class_init (AmitkSpaceClass *klass); static void space_init (AmitkSpace *object); static void space_shift (AmitkSpace * space, AmitkPoint * shift); static void space_rotate_on_vector (AmitkSpace * space, AmitkPoint * vector, amide_real_t theta, AmitkPoint * center_of_rotation); static void space_invert_axis (AmitkSpace * space, AmitkAxis which_axis, AmitkPoint * center_of_inversion); static void space_transform (AmitkSpace * space, AmitkSpace * transform_space); static void space_transform_axes (AmitkSpace * space, AmitkAxes axes, AmitkPoint * center_of_rotation); static void space_scale (AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling); static GObjectClass * parent_class; static guint space_signals[LAST_SIGNAL]; GType amitk_space_get_type(void) { static GType space_type = 0; if (!space_type) { static const GTypeInfo space_info = { sizeof (AmitkSpaceClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) space_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkSpace), 0, /* n_preallocs */ (GInstanceInitFunc) space_init, NULL /* value table */ }; space_type = g_type_register_static (G_TYPE_OBJECT, "AmitkSpace", &space_info, 0); } return space_type; } static void space_class_init (AmitkSpaceClass * class) { // GObjectClass *gobject_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent(class); class->space_shift = space_shift; class->space_rotate = space_rotate_on_vector; class->space_invert = space_invert_axis; class->space_transform = space_transform; class->space_transform_axes = space_transform_axes; class->space_scale = space_scale; space_signals[SPACE_SHIFT] = g_signal_new ("space_shift", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_shift), NULL, NULL, amitk_marshal_VOID__BOXED, G_TYPE_NONE,1, AMITK_TYPE_POINT); space_signals[SPACE_ROTATE] = g_signal_new ("space_rotate", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_rotate), NULL, NULL, amitk_marshal_VOID__BOXED_DOUBLE_BOXED, G_TYPE_NONE,3, AMITK_TYPE_POINT, AMITK_TYPE_REAL, AMITK_TYPE_POINT); space_signals[SPACE_INVERT] = g_signal_new ("space_invert", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_invert), NULL, NULL, amitk_marshal_VOID__ENUM_BOXED, G_TYPE_NONE,2, AMITK_TYPE_AXIS, AMITK_TYPE_POINT); space_signals[SPACE_TRANSFORM] = g_signal_new ("space_transform", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_transform), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE,1, AMITK_TYPE_SPACE); space_signals[SPACE_TRANSFORM_AXES] = g_signal_new ("space_transform_axes", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_transform_axes), NULL, NULL, amitk_marshal_VOID__BOXED_BOXED, G_TYPE_NONE,2, AMITK_TYPE_AXES, AMITK_TYPE_POINT); space_signals[SPACE_SCALE] = g_signal_new ("space_scale", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_scale), NULL, NULL, amitk_marshal_VOID__BOXED_BOXED, G_TYPE_NONE,2, AMITK_TYPE_POINT, AMITK_TYPE_POINT); space_signals[SPACE_CHANGED] = g_signal_new ("space_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkSpaceClass, space_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); } static void space_init (AmitkSpace * space) { AmitkAxis i_axis; space->offset = zero_point; for (i_axis=0; i_axisaxes[i_axis] = base_axes[i_axis]; } static void space_shift(AmitkSpace * space, AmitkPoint * shift) { space->offset = point_add(space->offset, *shift); /* get around some bizarre compiler bug */ if (isnan(space->offset.x) || isnan(space->offset.y) || isnan(space->offset.z)) { g_warning("inappropriate offset, possibly an internalization problem, or a compiler bug from libecat, working around"); space->offset = zero_point; } return; } static void space_invert_axis (AmitkSpace * space, AmitkAxis which_axis, AmitkPoint * center_of_inversion) { AmitkPoint shift; shift = amitk_space_b2s(space, *center_of_inversion); space->axes[which_axis] = point_neg(space->axes[which_axis]); shift = point_sub(*center_of_inversion, amitk_space_s2b(space, shift)); space->offset = point_add(space->offset, shift); return; } /*center of rotation should be in base coordinate frame */ static void space_rotate_on_vector(AmitkSpace * space, AmitkPoint * vector, amide_real_t theta, AmitkPoint * center_of_rotation) { AmitkPoint shift; shift = amitk_space_b2s(space, *center_of_rotation); amitk_axes_rotate_on_vector(space->axes, *vector, theta); amitk_axes_make_orthonormal(space->axes); /* make sure the result is orthonomal */ shift = point_sub(*center_of_rotation, amitk_space_s2b(space, shift)); space->offset = point_add(space->offset, shift); return; } static void space_transform(AmitkSpace * space, AmitkSpace * transform_space) { space->offset = point_add(space->offset, transform_space->offset); amitk_axes_mult(transform_space->axes, space->axes, space->axes); amitk_axes_make_orthonormal(space->axes); /* make sure the result is orthonomal */ /* get around some bizarre compiler bug */ if (isnan(space->axes[AMITK_AXIS_X].x) || isnan(space->axes[AMITK_AXIS_X].y) || isnan(space->axes[AMITK_AXIS_X].z) || isnan(space->axes[AMITK_AXIS_Y].x) || isnan(space->axes[AMITK_AXIS_Y].y) || isnan(space->axes[AMITK_AXIS_Y].z) || isnan(space->axes[AMITK_AXIS_Z].x) || isnan(space->axes[AMITK_AXIS_Z].y) || isnan(space->axes[AMITK_AXIS_Z].z)) { AmitkAxis i_axis; g_warning("inappropriate offset: compiler bug? internalization problem? Working around"); for (i_axis=0;i_axisaxes[i_axis]=base_axes[i_axis]; } return; } static void space_transform_axes(AmitkSpace * space, AmitkAxes transform_axes, AmitkPoint * center_of_rotation) { AmitkPoint shift; shift = amitk_space_b2s(space, *center_of_rotation); amitk_axes_mult(transform_axes, space->axes, space->axes); amitk_axes_make_orthonormal(space->axes); /* make sure the result is orthonomal */ shift = point_sub(*center_of_rotation, amitk_space_s2b(space, shift)); space->offset = point_add(space->offset, shift); return; } /* scaling and ref_point need to be wrt the base reference frame */ static void space_scale(AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling) { AmitkPoint shift; shift = point_sub(AMITK_SPACE_OFFSET(space), *ref_point); shift = point_mult(*scaling, shift); space->offset = point_add(shift, *ref_point); return; } AmitkSpace * amitk_space_new (void) { AmitkSpace * space; space = g_object_new(amitk_space_get_type(), NULL); return space; } void amitk_space_write_xml(xmlNodePtr node, gchar * descriptor, AmitkSpace * space) { gchar * temp_string; AmitkAxis i_axis; temp_string = g_strdup_printf("%s_offset", descriptor); amitk_point_write_xml(node,temp_string, AMITK_SPACE_OFFSET(space)); g_free(temp_string); for (i_axis=0;i_axisoffset); amitk_space_shift_offset(space, shift); return; } void amitk_space_shift_offset(AmitkSpace * space, const AmitkPoint shift ){ g_return_if_fail(AMITK_IS_SPACE(space)); if (!POINT_EQUAL(shift, zero_point)) { g_signal_emit(G_OBJECT(space), space_signals[SPACE_SHIFT], 0, &shift); g_signal_emit(G_OBJECT(space), space_signals[SPACE_CHANGED], 0); } return; } void amitk_space_set_axes(AmitkSpace * space, const AmitkAxes new_axes, const AmitkPoint center_of_rotation) { AmitkAxes transform_axes; g_return_if_fail(AMITK_IS_SPACE(space)); amitk_axes_copy_in_place(transform_axes, space->axes); /* since the axes matrix is orthogonal, the transpose is the same as the inverse */ amitk_axes_transpose(transform_axes); amitk_axes_mult(new_axes, transform_axes, transform_axes); /* now transform_space->axes incodes the rotation of the original coordinate space that will result in the new coordinate space */ amitk_space_transform_axes(space, transform_axes, center_of_rotation); return; } /* given two spaces, calculate the transform space that when applied to src_space will make it equal to dest_space. */ AmitkSpace * amitk_space_calculate_transform(const AmitkSpace * dest_space, const AmitkSpace * src_space) { AmitkSpace * transform_space; g_return_val_if_fail(AMITK_IS_SPACE(src_space), NULL); g_return_val_if_fail(AMITK_IS_SPACE(dest_space), NULL); /* transform_space will encode the shift and rotation of the coordinate space */ transform_space = amitk_space_new(); transform_space->offset = point_sub(src_space->offset, dest_space->offset); amitk_axes_copy_in_place(transform_space->axes, dest_space->axes); /* since the axes matrix is orthogonal, the transpose is the same as the inverse */ amitk_axes_transpose(transform_space->axes); amitk_axes_mult(src_space->axes, transform_space->axes, transform_space->axes); /* now transform_space->axes incodes the rotation of the original coordinate space that will result in the new coordinate space */ return transform_space; } void amitk_space_copy_in_place(AmitkSpace * dest_space, const AmitkSpace * src_space) { AmitkSpace * transform_space; g_return_if_fail(AMITK_IS_SPACE(src_space)); g_return_if_fail(AMITK_IS_SPACE(dest_space)); transform_space = amitk_space_calculate_transform(dest_space, src_space); g_return_if_fail(transform_space != NULL); amitk_space_transform(dest_space, transform_space); g_object_unref(transform_space); return; } void amitk_space_transform(AmitkSpace * space, const AmitkSpace * transform_space) { g_return_if_fail(AMITK_IS_SPACE(space)); g_return_if_fail(AMITK_IS_SPACE(transform_space)); g_signal_emit(G_OBJECT(space), space_signals[SPACE_TRANSFORM], 0, transform_space); g_signal_emit(G_OBJECT(space), space_signals[SPACE_CHANGED], 0); return; } void amitk_space_transform_axes(AmitkSpace * space, const AmitkAxes transform_axes, AmitkPoint center_of_rotation) { g_return_if_fail(AMITK_IS_SPACE(space)); g_signal_emit(G_OBJECT(space), space_signals[SPACE_TRANSFORM_AXES], 0, transform_axes, ¢er_of_rotation); g_signal_emit(G_OBJECT(space), space_signals[SPACE_CHANGED], 0); return; } /* scaling and ref_point need to be wrt the base reference frame */ /* note, this doesn't actually scale the coordinate axis, as we always leave those as orthonormal. instead, it shifts the offset of the space appropriately giving the ref_point, and leaves further scaling operations to objects that inherit from this class */ void amitk_space_scale(AmitkSpace * space, AmitkPoint ref_point, AmitkPoint scaling) { g_return_if_fail(AMITK_IS_SPACE(space)); g_signal_emit(G_OBJECT(space), space_signals[SPACE_SCALE], 0, &ref_point, &scaling); g_signal_emit(G_OBJECT(space), space_signals[SPACE_CHANGED], 0); } AmitkPoint amitk_space_get_axis(const AmitkSpace * space, const AmitkAxis which_axis) { g_return_val_if_fail(AMITK_IS_SPACE(space), one_point); return space->axes[which_axis]; } /* given the ordered corners[] (i.e corner[0].x < corner[1].x, etc.) of a box in the input coordinate space, this function will return an ordered set of corners for the box in the new coordinate space that completely encloses the given box */ void amitk_space_get_enclosing_corners(const AmitkSpace * in_space, const AmitkCorners in_corners, const AmitkSpace * out_space, AmitkCorners out_corners) { AmitkPoint temp_point; guint corner; g_return_if_fail(AMITK_IS_SPACE(in_space)); g_return_if_fail(AMITK_IS_SPACE(out_space)); for (corner=0; corner<8 ; corner++) { temp_point.x = in_corners[(corner & 0x1) ? 1 : 0].x; temp_point.y = in_corners[(corner & 0x2) ? 1 : 0].y; temp_point.z = in_corners[(corner & 0x4) ? 1 : 0].z; temp_point = amitk_space_s2s(in_space, out_space, temp_point); if (corner==0) out_corners[0]=out_corners[1]=temp_point; else { if (temp_point.x < out_corners[0].x) out_corners[0].x=temp_point.x; if (temp_point.x > out_corners[1].x) out_corners[1].x=temp_point.x; if (temp_point.y < out_corners[0].y) out_corners[0].y=temp_point.y; if (temp_point.y > out_corners[1].y) out_corners[1].y=temp_point.y; if (temp_point.z < out_corners[0].z) out_corners[0].z=temp_point.z; if (temp_point.z > out_corners[1].z) out_corners[1].z=temp_point.z; } } return; } AmitkSpace * amitk_space_copy(const AmitkSpace * space) { AmitkSpace * new_space; g_return_val_if_fail(AMITK_IS_SPACE(space), NULL); new_space = amitk_space_new(); amitk_space_copy_in_place(new_space, space); return new_space; } gboolean amitk_space_axes_equal(const AmitkSpace * space1, const AmitkSpace * space2) { gboolean inner = TRUE; AmitkAxis i_axis; g_return_val_if_fail(AMITK_IS_SPACE(space1), FALSE); g_return_val_if_fail(AMITK_IS_SPACE(space2), FALSE); for (i_axis=0;i_axisaxes[i_axis], space2->axes[i_axis]); return inner; } gboolean amitk_space_axes_close(const AmitkSpace * space1, const AmitkSpace * space2) { gboolean inner = TRUE; AmitkAxis i_axis; g_return_val_if_fail(AMITK_IS_SPACE(space1), FALSE); g_return_val_if_fail(AMITK_IS_SPACE(space2), FALSE); for (i_axis=0;i_axisaxes[i_axis], space2->axes[i_axis]); return inner; } gboolean amitk_space_equal(const AmitkSpace * space1, const AmitkSpace * space2) { g_return_val_if_fail(AMITK_IS_SPACE(space1), FALSE); g_return_val_if_fail(AMITK_IS_SPACE(space2), FALSE); if (POINT_EQUAL(space1->offset, space2->offset)) return amitk_space_axes_equal(space1, space2); else return FALSE; } void amitk_space_invert_axis (AmitkSpace * space, const AmitkAxis which_axis, const AmitkPoint center_of_inversion) { g_return_if_fail(AMITK_IS_SPACE(space)); g_signal_emit(G_OBJECT(space), space_signals[SPACE_INVERT], 0, which_axis, ¢er_of_inversion); g_signal_emit(G_OBJECT(space), space_signals[SPACE_CHANGED], 0); return; } /* rotate the entire coordinate space around the given vector */ void amitk_space_rotate_on_vector(AmitkSpace * space, const AmitkPoint vector, const amide_real_t theta, const AmitkPoint center_of_rotation) { g_return_if_fail(AMITK_IS_SPACE(space)); g_signal_emit(G_OBJECT(space), space_signals[SPACE_ROTATE], 0, &vector, theta, ¢er_of_rotation); g_signal_emit(G_OBJECT(space), space_signals[SPACE_CHANGED], 0); return; } /* given a view, and the layout, return the appropriate coordinate frame */ AmitkSpace * amitk_space_get_view_space(const AmitkView view, const AmitkLayout layout) { AmitkSpace * view_space; AmitkAxis i_axis; view_space = amitk_space_new(); for (i_axis=0;i_axisaxes[i_axis] = amitk_axes_get_orthogonal_axis(base_axes, view, layout, i_axis); amitk_axes_make_orthonormal(view_space->axes); /* safety */ return view_space; } /* given a coordinate frame, and a view, and the layout, sets the space to the appropriate coordinate space */ void amitk_space_set_view_space(AmitkSpace * set_space, const AmitkView view, const AmitkLayout layout) { AmitkSpace * temp_space; g_return_if_fail(AMITK_IS_SPACE(set_space)); temp_space = amitk_space_get_view_space(view, layout); amitk_space_copy_in_place(set_space, temp_space); g_object_unref(temp_space); return; } /* convert a point from the base coordinate frame to the given coordinate space */ AmitkPoint amitk_space_b2s(const AmitkSpace * space, AmitkPoint in_point) { AmitkPoint return_point; /* compensate the inpoint for the offset of the new coordinate frame */ POINT_SUB(in_point, space->offset, in_point); /* instead of multiplying by inv(A), we multiple by transpose(A), this is the same thing, as A is orthogonal */ return_point.x = in_point.x * space->axes[AMITK_AXIS_X].x + in_point.y * space->axes[AMITK_AXIS_X].y + in_point.z * space->axes[AMITK_AXIS_X].z; return_point.y = in_point.x * space->axes[AMITK_AXIS_Y].x + in_point.y * space->axes[AMITK_AXIS_Y].y + in_point.z * space->axes[AMITK_AXIS_Y].z; return_point.z = in_point.x * space->axes[AMITK_AXIS_Z].x + in_point.y * space->axes[AMITK_AXIS_Z].y + in_point.z * space->axes[AMITK_AXIS_Z].z; return return_point; } /* convert a point from the given coordinate space to the base coordinate frame */ AmitkPoint amitk_space_s2b(const AmitkSpace * space, const AmitkPoint in_point) { AmitkPoint return_point; return_point.x = in_point.x * space->axes[AMITK_AXIS_X].x + in_point.y * space->axes[AMITK_AXIS_Y].x + in_point.z * space->axes[AMITK_AXIS_Z].x; return_point.y = in_point.x * space->axes[AMITK_AXIS_X].y + in_point.y * space->axes[AMITK_AXIS_Y].y + in_point.z * space->axes[AMITK_AXIS_Z].y; return_point.z = in_point.x * space->axes[AMITK_AXIS_X].z + in_point.y * space->axes[AMITK_AXIS_Y].z + in_point.z * space->axes[AMITK_AXIS_Z].z; POINT_ADD(return_point, space->offset, return_point); return return_point; } /* converts a "dimensional" quantity (i.e. the size of a voxel) from a given space to the base coordinate system */ AmitkPoint amitk_space_s2b_dim(const AmitkSpace * space, const AmitkPoint in_point) { AmitkPoint return_point; AmitkPoint temp[AMITK_AXIS_NUM]; AmitkPoint temp_point; /* all the fabs/point_abs are 'cause dim's should always be positive */ temp_point.x = fabs(in_point.x); temp_point.y = temp_point.z = 0.0; temp[AMITK_AXIS_X]=point_abs(point_sub(amitk_space_s2b(space, temp_point), space->offset)); temp_point.y = fabs(in_point.y); temp_point.x = temp_point.z = 0.0; temp[AMITK_AXIS_Y]=point_abs(point_sub(amitk_space_s2b(space, temp_point), space->offset)); temp_point.z = fabs(in_point.z); temp_point.x = temp_point.y = 0.0; temp[AMITK_AXIS_Z]=point_abs(point_sub(amitk_space_s2b(space, temp_point), space->offset)); return_point.x = temp[AMITK_AXIS_X].x+temp[AMITK_AXIS_Y].x+temp[AMITK_AXIS_Z].x; return_point.y = temp[AMITK_AXIS_X].y+temp[AMITK_AXIS_Y].y+temp[AMITK_AXIS_Z].y; return_point.z = temp[AMITK_AXIS_X].z+temp[AMITK_AXIS_Y].z+temp[AMITK_AXIS_Z].z; return return_point; } /* converts a "dimensional" quantity (i.e. the size of a voxel) from the base coordinate space to the given coordinate space */ AmitkPoint amitk_space_b2s_dim(const AmitkSpace * space, const AmitkPoint in_point) { AmitkPoint return_point; AmitkPoint temp[AMITK_AXIS_NUM]; AmitkPoint temp_point; /* all the fabs/point_abs are 'cause dim's should always be positive */ temp_point.x = fabs(in_point.x); temp_point.y = temp_point.z = 0.0; temp[AMITK_AXIS_X]=point_abs(amitk_space_b2s(space, point_add(temp_point, space->offset))); temp_point.y = fabs(in_point.y); temp_point.x = temp_point.z = 0.0; temp[AMITK_AXIS_Y]=point_abs(amitk_space_b2s(space, point_add(temp_point, space->offset))); temp_point.z = fabs(in_point.z); temp_point.x = temp_point.y = 0.0; temp[AMITK_AXIS_Z]=point_abs(amitk_space_b2s(space, point_add(temp_point,space->offset))); return_point.x = temp[AMITK_AXIS_X].x+temp[AMITK_AXIS_Y].x+temp[AMITK_AXIS_Z].x; return_point.y = temp[AMITK_AXIS_X].y+temp[AMITK_AXIS_Y].y+temp[AMITK_AXIS_Z].y; return_point.z = temp[AMITK_AXIS_X].z+temp[AMITK_AXIS_Y].z+temp[AMITK_AXIS_Z].z; return return_point; } /* little utility function for debugging */ void amitk_space_print(AmitkSpace * space, gchar * message) { g_print("%s\n", message); g_print("\toffset:\t% 5.5f\t% 5.5f\t% 5.5f\n", space->offset.x, space->offset.y, space->offset.z); g_print("\taxis x:\t% 5.5f\t% 5.5f\t% 5.5f\n", space->axes[AMITK_AXIS_X].x,space->axes[AMITK_AXIS_X].y, space->axes[AMITK_AXIS_X].z); g_print("\taxis y:\t% 5.5f\t% 5.5f\t% 5.5f\n", space->axes[AMITK_AXIS_Y].x,space->axes[AMITK_AXIS_Y].y, space->axes[AMITK_AXIS_Y].z); g_print("\taxis z:\t% 5.5f\t% 5.5f\t% 5.5f\n", space->axes[AMITK_AXIS_Z].x,space->axes[AMITK_AXIS_Z].y, space->axes[AMITK_AXIS_Z].z); return; } amide-1.0.6/amide-current/src/amitk_space.h000066400000000000000000000146751423227705100205740ustar00rootroot00000000000000/* amitk_space.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_SPACE_H__ #define __AMITK_SPACE_H__ #include "amitk_point.h" G_BEGIN_DECLS #define AMITK_TYPE_SPACE (amitk_space_get_type ()) #define AMITK_SPACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_SPACE, AmitkSpace)) #define AMITK_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_SPACE, AmitkSpaceClass)) #define AMITK_IS_SPACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_SPACE)) #define AMITK_IS_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_SPACE)) #define AMITK_SPACE_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_SPACE, AmitkSpaceClass)) #define AMITK_SPACE_AXES(space) (AMITK_SPACE(space)->axes) #define AMITK_SPACE_OFFSET(space) (AMITK_SPACE(space)->offset) typedef struct _AmitkSpaceClass AmitkSpaceClass; typedef struct _AmitkSpace AmitkSpace; #define AMITK_UNDO_LEVEL 10 /* The AmitkSpace structure is the base of the Amitk objects hierarchy. * It describes an euclidean reference frame with respect to the * base coordinate space. Offset is in the base coordinate frame. */ struct _AmitkSpace { GObject parent; /* private info */ AmitkPoint offset; /* with respect to the base coordinate frame */ AmitkAxes axes; }; struct _AmitkSpaceClass { GObjectClass parent_class; void (* space_shift) (AmitkSpace * space, AmitkPoint * shift); void (* space_rotate) (AmitkSpace * space, AmitkPoint * vector, amide_real_t theta, AmitkPoint * center_of_rotation); void (* space_invert) (AmitkSpace * space, AmitkAxis which_axis, AmitkPoint * center_of_inversion); void (* space_transform) (AmitkSpace * space, AmitkSpace * transform_space); void (* space_transform_axes) (AmitkSpace * space, AmitkAxes transform_axes, AmitkPoint * center_of_rotation); void (* space_scale) (AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling); void (* space_changed) (AmitkSpace * space); }; /* Application-level methods */ GType amitk_space_get_type (void); AmitkSpace* amitk_space_new (void); void amitk_space_write_xml (xmlNodePtr node, gchar * descriptor, AmitkSpace * space); AmitkSpace * amitk_space_read_xml (xmlNodePtr nodes, gchar * descriptor, gchar ** perror_buf); void amitk_space_set_offset (AmitkSpace * space, const AmitkPoint new_offset); void amitk_space_shift_offset (AmitkSpace * space, const AmitkPoint shift); void amitk_space_set_axes (AmitkSpace * space, const AmitkAxes new_axes, const AmitkPoint center_of_rotation); AmitkSpace * amitk_space_calculate_transform (const AmitkSpace * dest_space, const AmitkSpace * src_space); void amitk_space_transform (AmitkSpace * space, const AmitkSpace * transform_space); void amitk_space_transform_axes (AmitkSpace * space, const AmitkAxes transform_axes, AmitkPoint center_of_rotation); void amitk_space_scale (AmitkSpace * space, AmitkPoint ref_point, AmitkPoint scaling); AmitkPoint amitk_space_get_axis (const AmitkSpace * space, const AmitkAxis which_axis); void amitk_space_get_enclosing_corners (const AmitkSpace * in_space, const AmitkCorners in_corners, const AmitkSpace * out_space, AmitkCorners out_corners); AmitkSpace * amitk_space_copy (const AmitkSpace * space); void amitk_space_copy_in_place (AmitkSpace * dest_space, const AmitkSpace * src_space); gboolean amitk_space_axes_equal (const AmitkSpace * space1, const AmitkSpace * space2); gboolean amitk_space_axes_close (const AmitkSpace * space1, const AmitkSpace * space2); gboolean amitk_space_equal (const AmitkSpace * space1, const AmitkSpace * space2); void amitk_space_invert_axis (AmitkSpace * space, const AmitkAxis which_axis, const AmitkPoint center_of_inversion); void amitk_space_rotate_on_vector (AmitkSpace * space, const AmitkPoint vector, const amide_real_t theta, const AmitkPoint center_of_rotation); AmitkSpace * amitk_space_get_view_space (const AmitkView view, const AmitkLayout layout); void amitk_space_set_view_space (AmitkSpace * set_space, const AmitkView view, const AmitkLayout layout); /* functions that need to be fast, they do no error checking */ AmitkPoint amitk_space_b2s (const AmitkSpace * space, AmitkPoint in_rp); AmitkPoint amitk_space_s2b (const AmitkSpace * space, const AmitkPoint in_rp); #define amitk_space_s2s(in_space, out_space, in) (amitk_space_b2s((out_space), amitk_space_s2b((in_space), (in)))) AmitkPoint amitk_space_s2b_dim (const AmitkSpace * space, const AmitkPoint in_rp); AmitkPoint amitk_space_b2s_dim (const AmitkSpace * space, const AmitkPoint in_rp); #define amitk_space_s2s_dim(in_space, out_space, in) (amitk_space_b2s_dim((out_space), amitk_space_s2b_dim((in_space), (in)))) /* debugging functions */ void amitk_space_print(AmitkSpace * space, gchar * message); G_END_DECLS #endif /* __AMITK_SPACE_H__ */ amide-1.0.6/amide-current/src/amitk_space_edit.c000066400000000000000000000342371423227705100215700ustar00rootroot00000000000000/* amitk_space_edit.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "amitk_space_edit.h" #include "amitk_study.h" #define DEFAULT_ENTRY_WIDTH 100 static void space_edit_class_init (AmitkSpaceEditClass *klass); static void space_edit_init (AmitkSpaceEdit *space_edit); static void space_edit_destroy(GtkObject * object); static void space_edit_update_entries(AmitkSpaceEdit * space_edit); static void space_edit_rotate_axis(GtkAdjustment * adjustment, gpointer data); static gboolean space_edit_prompt(AmitkSpaceEdit * space_edit, const gchar * message); static void space_edit_apply_entries(GtkWidget * button, gpointer space_edit); static void space_edit_reset_axis(GtkWidget * button, gpointer data); static void space_edit_invert_axis(GtkWidget * button, gpointer data); #if 0 static void space_edit_apply_air(GtkWidget * button, gpointer data); static void space_edit_export_air(GtkWidget * button, gpointer data); #endif static GtkVBoxClass *parent_class; GType amitk_space_edit_get_type (void) { static GType space_edit_type = 0; if (!space_edit_type) { static const GTypeInfo space_edit_info = { sizeof (AmitkSpaceEditClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) space_edit_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkSpaceEdit), 0, /* # preallocs */ (GInstanceInitFunc) space_edit_init, NULL /* value table */ }; space_edit_type = g_type_register_static(GTK_TYPE_VBOX, "AmitkSpaceEdit", &space_edit_info, 0); } return space_edit_type; } static void space_edit_class_init (AmitkSpaceEditClass *klass) { /* GObjectClass *gobject_class; GtkWidgetClass *widget_class; */ GtkObjectClass *gtkobject_class; /* gobject_class = (GObjectClass *) klass; widget_class = (GtkWidgetClass*) klass; */ gtkobject_class = (GtkObjectClass*) klass; parent_class = g_type_class_peek_parent(klass); gtkobject_class->destroy = space_edit_destroy; } static void space_edit_init (AmitkSpaceEdit *space_edit) { GtkWidget * table; GtkWidget * slider; GtkWidget * label; GtkWidget * button; GtkWidget * hseparator; guint row=0; AmitkView i_view; GtkObject * adjustment; AmitkAxis i_axis, j_axis; /* initialize some critical stuff */ space_edit->object = NULL; table = gtk_table_new(14,5, FALSE); gtk_container_add(GTK_CONTAINER(space_edit), table); gtk_widget_show(table); /* the sliders to spin on a view */ for (i_view=0;i_view< AMITK_VIEW_NUM;i_view++) { /* label */ label = gtk_label_new(amitk_view_get_name(i_view)); gtk_table_attach(GTK_TABLE(table), label, 0,1, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); /* the slider */ adjustment = gtk_adjustment_new(0,-45.0,45.5,0.5,0.5,0.5); g_object_set_data(G_OBJECT(adjustment), "view", GINT_TO_POINTER(i_view)); slider = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); gtk_range_set_update_policy(GTK_RANGE(slider), GTK_UPDATE_DISCONTINUOUS); gtk_table_attach(GTK_TABLE(table), slider, 1,5, row, row+1, X_PACKING_OPTIONS | GTK_FILL,FALSE, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(adjustment), "value_changed", G_CALLBACK(space_edit_rotate_axis), space_edit); gtk_widget_show(slider); row++; } /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0, 5, row, row+1,GTK_FILL, 0, X_PADDING, Y_PADDING); row++; gtk_widget_show(hseparator); /* and a display of the current axis */ label = gtk_label_new(_("i")); gtk_table_attach(GTK_TABLE(table), label, 1,2, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); label = gtk_label_new(_("j")); gtk_table_attach(GTK_TABLE(table), label, 2,3, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); label = gtk_label_new(_("k")); gtk_table_attach(GTK_TABLE(table), label, 3,4, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); row++; for (i_axis=0;i_axisentry[i_axis][j_axis] = gtk_entry_new(); gtk_widget_set_size_request(space_edit->entry[i_axis][j_axis], DEFAULT_ENTRY_WIDTH,-1); gtk_editable_set_editable(GTK_EDITABLE(space_edit->entry[i_axis][j_axis]), TRUE); gtk_table_attach(GTK_TABLE(table), space_edit->entry[i_axis][j_axis],j_axis+1, j_axis+2, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(space_edit->entry[i_axis][j_axis]); } /* the invert button */ button = gtk_button_new_with_label("invert axis"); gtk_table_attach(GTK_TABLE(table), button, 4,5, row, row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(button), "axis", GINT_TO_POINTER(i_axis)); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(space_edit_invert_axis), space_edit); gtk_widget_show(button); row++; } label = gtk_label_new(_("data set axis:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); /* button to apply entries */ button = gtk_button_new_with_label(_("apply manual entries")); gtk_table_attach(GTK_TABLE(table), button, 1,2, row, row+1, 0, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(space_edit_apply_entries), space_edit); gtk_widget_show(button); /* button to reset the axis */ button = gtk_button_new_with_label(_("reset to identity")); gtk_table_attach(GTK_TABLE(table), button, 2,3, row, row+1, 0, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(space_edit_reset_axis), space_edit); gtk_widget_show(button); row++; #if 0 /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0, 5, row, row+1,GTK_FILL, 0, X_PADDING, Y_PADDING); row++; gtk_widget_show(hseparator); /* our AIR buttons */ label = gtk_label_new(_("AIR Files:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, row, row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); button = gtk_button_new_with_label(_("Apply .AIR")); gtk_table_attach(GTK_TABLE(table), button, 1,2, row, row+1, 0, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(space_edit_apply_air), space_edit); gtk_widget_show(button); button = gtk_button_new_with_label(_("Export .AIR")); gtk_table_attach(GTK_TABLE(table), button, 2,3, row, row+1, 0, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(space_edit_export_air), space_edit); gtk_widget_show(button); row++; #endif } static void space_edit_destroy (GtkObject * gtkobject) { AmitkSpaceEdit * space_edit; g_return_if_fail (gtkobject != NULL); g_return_if_fail (AMITK_IS_SPACE_EDIT (gtkobject)); space_edit = AMITK_SPACE_EDIT(gtkobject); if (space_edit->object != NULL) { g_signal_handlers_disconnect_by_func(G_OBJECT(space_edit->object), space_edit_update_entries, space_edit); amitk_object_unref(space_edit->object); space_edit->object = NULL; } if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (gtkobject); } /* function to update the entry widgets */ static void space_edit_update_entries(AmitkSpaceEdit * space_edit) { AmitkAxis i_axis, j_axis; gchar * temp_string; AmitkPoint one_axis; g_return_if_fail(AMITK_IS_SPACE_EDIT(space_edit)); for (i_axis=0;i_axisobject), i_axis); for (j_axis=0; j_axisentry[i_axis][j_axis]), temp_string); g_free(temp_string); } } return; } static void space_edit_rotate_axis(GtkAdjustment * adjustment, gpointer data) { AmitkSpaceEdit * space_edit = data; AmitkView i_view; amide_real_t rotation; AmitkPoint center; /* figure out which scale widget called me */ i_view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adjustment),"view")); rotation = (adjustment->value/180)*M_PI; /* get rotation in radians */ /* compensate for sagittal being a left-handed coordinate frame */ if (i_view == AMITK_VIEW_SAGITTAL) rotation = -rotation; if (AMITK_IS_VOLUME(space_edit->object)) center = amitk_volume_get_center(AMITK_VOLUME(space_edit->object)); else if (AMITK_IS_STUDY(space_edit->object)) center = AMITK_STUDY_VIEW_CENTER(space_edit->object); else center = AMITK_SPACE_OFFSET(space_edit->object); /* rotate the axis */ amitk_space_rotate_on_vector(AMITK_SPACE(space_edit->object), amitk_axes_get_normal_axis(base_axes, i_view), rotation, center); /* return adjustment back to normal */ adjustment->value = 0.0; gtk_adjustment_changed(adjustment); return; } static gboolean space_edit_prompt(AmitkSpaceEdit * space_edit, const gchar * message) { GtkWidget * question; gint return_val; GtkWidget *toplevel; GtkWindow *window; toplevel = gtk_widget_get_toplevel (GTK_WIDGET(space_edit)); if (toplevel != NULL) window = GTK_WINDOW(toplevel); else window = NULL; question = gtk_message_dialog_new(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, "%s", message); return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val != GTK_RESPONSE_OK) return FALSE; else return TRUE; } static void space_edit_apply_entries(GtkWidget * entry, gpointer data) { AmitkSpaceEdit * space_edit = data; AmitkAxis i_axis, j_axis; const gchar * text; AmitkAxes axes; gdouble temp_real; AmitkPoint center; gint error; /* first double check that we really want to do this */ if (!space_edit_prompt(space_edit, _("Do you really wish to manual set the axis?\nThis may flip left/right relationships"))) return; for (i_axis=0;i_axisentry[i_axis][j_axis])); error = sscanf(text, "%lf", &temp_real); if (error != EOF) point_set_component(&(axes[i_axis]), j_axis, temp_real); } } amitk_axes_make_orthonormal(axes); if (AMITK_IS_VOLUME(space_edit->object)) center = amitk_volume_get_center(AMITK_VOLUME(space_edit->object)); else center = AMITK_SPACE_OFFSET(space_edit->object); amitk_space_set_axes(AMITK_SPACE(space_edit->object), axes, center); return; } static void space_edit_reset_axis(GtkWidget * button, gpointer data) { AmitkSpaceEdit * space_edit = data; AmitkPoint center; /* first double check that we really want to do this */ if (!space_edit_prompt(space_edit, _("Do you really wish to reset the axis to identity?\nThis may flip left/right relationships"))) return; /* shift the coord frame to the center of rotation, and save the old offset */ if (AMITK_IS_VOLUME(space_edit->object)) center = amitk_volume_get_center(AMITK_VOLUME(space_edit->object)); else if (AMITK_IS_STUDY(space_edit->object)) center = AMITK_STUDY_VIEW_CENTER(space_edit->object); else center = AMITK_SPACE_OFFSET(space_edit->object); /* reset the axis */ amitk_space_set_axes(AMITK_SPACE(space_edit->object), base_axes, center); return; } static void space_edit_invert_axis(GtkWidget * button, gpointer data) { AmitkSpaceEdit * space_edit = data; AmitkAxis i_axis; AmitkPoint center; /* first double check that we really want to do this */ if (!space_edit_prompt(space_edit, _("Do you really wish to invert?\nThis will flip left/right relationships"))) return; i_axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "axis")); /* shift the coord frame to the center of rotation, and save the old offset */ if (AMITK_IS_VOLUME(space_edit->object)) center = amitk_volume_get_center(AMITK_VOLUME(space_edit->object)); else if (AMITK_IS_STUDY(space_edit->object)) center = AMITK_STUDY_VIEW_CENTER(space_edit->object); else center = AMITK_SPACE_OFFSET(space_edit->object); /* invert the axis */ amitk_space_invert_axis(AMITK_SPACE(space_edit->object), i_axis, center); return; } #if 0 static void space_edit_apply_air(GtkWidget * button, gpointer data) { AmitkSpaceEdit * space_edit = data; g_warning("not yet implemented\n"); return; } static void space_edit_export_air(GtkWidget * button, gpointer data) { AmitkSpaceEdit * space_edit = data; g_warning("not yet implemented\n"); return; } #endif GtkWidget * amitk_space_edit_new(AmitkObject * object) { AmitkSpaceEdit * space_edit; g_return_val_if_fail(AMITK_IS_OBJECT(object), NULL); space_edit = g_object_new(amitk_space_edit_get_type (), NULL); space_edit->object = amitk_object_ref(object); g_signal_connect_swapped(G_OBJECT(object), "space_changed", G_CALLBACK(space_edit_update_entries), space_edit); space_edit_update_entries(space_edit); return GTK_WIDGET (space_edit); } amide-1.0.6/amide-current/src/amitk_space_edit.h000066400000000000000000000040141423227705100215630ustar00rootroot00000000000000/* amitk_space_edit.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_SPACE_EDIT_H__ #define __AMITK_SPACE_EDIT_H__ /* includes we always need with this widget */ #include #include "amitk_object.h" G_BEGIN_DECLS #define AMITK_TYPE_SPACE_EDIT (amitk_space_edit_get_type ()) #define AMITK_SPACE_EDIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_SPACE_EDIT, AmitkSpaceEdit)) #define AMITK_SPACE_EDIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_SPACE_EDIT, AmitkSpaceEditClass)) #define AMITK_IS_SPACE_EDIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_SPACE_EDIT)) #define AMITK_IS_SPACE_EDIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_SPACE_EDIT)) typedef struct _AmitkSpaceEdit AmitkSpaceEdit; typedef struct _AmitkSpaceEditClass AmitkSpaceEditClass; struct _AmitkSpaceEdit { GtkVBox vbox; GtkWidget * entry[AMITK_AXIS_NUM][AMITK_AXIS_NUM]; AmitkObject * object; }; struct _AmitkSpaceEditClass { GtkVBoxClass parent_class; }; GType amitk_space_edit_get_type (void); GtkWidget* amitk_space_edit_new (AmitkObject * object); G_END_DECLS #endif /* __AMITK_SPACE_EDIT_H__ */ amide-1.0.6/amide-current/src/amitk_study.c000066400000000000000000001202641423227705100206340ustar00rootroot00000000000000/* amitk_study.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include #include #include #include /* for g_mkdir */ #include "amitk_study.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "legacy.h" enum { FILENAME_CHANGED, THICKNESS_CHANGED, TIME_CHANGED, CANVAS_VISIBLE_CHANGED, VIEW_MODE_CHANGED, CANVAS_TARGET_CHANGED, VOXEL_DIM_OR_ZOOM_CHANGED, FOV_CHANGED, FUSE_TYPE_CHANGED, VIEW_CENTER_CHANGED, CANVAS_ROI_PREFERENCE_CHANGED, CANVAS_GENERAL_PREFERENCE_CHANGED, CANVAS_TARGET_PREFERENCE_CHANGED, CANVAS_LAYOUT_PREFERENCE_CHANGED, PANEL_LAYOUT_PREFERENCE_CHANGED, LAST_SIGNAL }; static gchar * blank_name = N_("new"); static void study_class_init (AmitkStudyClass *klass); static void study_init (AmitkStudy *study); static void study_finalize (GObject *object); static AmitkObject * study_copy (const AmitkObject *object); static void study_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); static void study_write_xml (const AmitkObject *object, xmlNodePtr nodes, FILE *study_file); static gchar * study_read_xml (AmitkObject *object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf); static void study_recalc_voxel_dim (AmitkStudy *study); static void study_add_child (AmitkObject *object, AmitkObject *child); static void study_remove_child (AmitkObject *object, AmitkObject *child); static AmitkObjectClass * parent_class; static guint study_signals[LAST_SIGNAL]; GType amitk_study_get_type(void) { static GType study_type = 0; if (!study_type) { static const GTypeInfo study_info = { sizeof (AmitkStudyClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) study_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkStudy), 0, /* n_preallocs */ (GInstanceInitFunc) study_init, NULL /* value table */ }; study_type = g_type_register_static (AMITK_TYPE_OBJECT, "AmitkStudy", &study_info, 0); } return study_type; } static void study_class_init (AmitkStudyClass * class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); AmitkObjectClass * object_class = AMITK_OBJECT_CLASS(class); parent_class = g_type_class_peek_parent(class); object_class->object_copy = study_copy; object_class->object_copy_in_place = study_copy_in_place; object_class->object_write_xml = study_write_xml; object_class->object_read_xml = study_read_xml; object_class->object_add_child = study_add_child; object_class->object_remove_child = study_remove_child; gobject_class->finalize = study_finalize; study_signals[FILENAME_CHANGED] = g_signal_new ("filename_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, filename_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[THICKNESS_CHANGED] = g_signal_new ("thickness_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, thickness_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[TIME_CHANGED] = g_signal_new ("time_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, time_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[CANVAS_VISIBLE_CHANGED] = g_signal_new ("canvas_visible_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, canvas_visible_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[VIEW_MODE_CHANGED] = g_signal_new ("view_mode_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, view_mode_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[CANVAS_TARGET_CHANGED] = g_signal_new ("canvas_target_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, canvas_target_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[VOXEL_DIM_OR_ZOOM_CHANGED] = g_signal_new ("voxel_dim_or_zoom_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, voxel_dim_or_zoom_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[FOV_CHANGED] = g_signal_new ("fov_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, fov_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[FUSE_TYPE_CHANGED] = g_signal_new ("fuse_type_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, fuse_type_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[VIEW_CENTER_CHANGED] = g_signal_new ("view_center_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, view_center_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[CANVAS_ROI_PREFERENCE_CHANGED] = g_signal_new ("canvas_roi_preference_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, canvas_roi_preference_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[CANVAS_GENERAL_PREFERENCE_CHANGED] = g_signal_new ("canvas_general_preference_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, canvas_general_preference_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[CANVAS_TARGET_PREFERENCE_CHANGED] = g_signal_new ("canvas_target_preference_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, canvas_target_preference_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[CANVAS_LAYOUT_PREFERENCE_CHANGED] = g_signal_new ("canvas_layout_preference_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, canvas_layout_preference_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); study_signals[PANEL_LAYOUT_PREFERENCE_CHANGED] = g_signal_new ("panel_layout_preference_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkStudyClass, panel_layout_preference_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); } static void study_init (AmitkStudy * study) { time_t current_time; AmitkView i_view; study->filename = NULL; /* view parameters */ study->view_center = zero_point; study->view_thickness = 1.0; study->view_start_time = 0.0; study->view_duration = 1.0; study->zoom = 1.0; study->fov = 100.0; study->fuse_type = AMITK_FUSE_TYPE_BLEND; study->view_mode = AMITK_VIEW_MODE_SINGLE; study->voxel_dim = 1.0; study->voxel_dim_valid=FALSE; for (i_view=0; i_viewcanvas_visible[i_view] = TRUE; study->canvas_target = FALSE; /* preferences for the canvas */ study->canvas_roi_width = AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_WIDTH; #ifdef AMIDE_LIBGNOMECANVAS_AA study->canvas_roi_transparency = AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_TRANSPARENCY; #else study->canvas_line_style = AMITK_PREFERENCES_DEFAULT_CANVAS_LINE_STYLE; study->canvas_fill_roi = AMITK_PREFERENCES_DEFAULT_CANVAS_FILL_ROI; #endif study->canvas_layout = AMITK_PREFERENCES_DEFAULT_CANVAS_LAYOUT; study->canvas_maintain_size = AMITK_PREFERENCES_DEFAULT_CANVAS_LAYOUT; study->canvas_target_empty_area = AMITK_PREFERENCES_DEFAULT_CANVAS_TARGET_EMPTY_AREA; study->panel_layout = AMITK_PREFERENCES_DEFAULT_PANEL_LAYOUT; /* line profile stuff */ study->line_profile = amitk_line_profile_new(); /* set the creation date as today */ study->creation_date = NULL; time(¤t_time); amitk_study_set_creation_date(study, ctime(¤t_time)); g_strdelimit(study->creation_date, "\n", ' '); /* turns newlines to white space */ g_strstrip(study->creation_date); /* removes trailing and leading white space */ return; } static void study_finalize (GObject * object) { AmitkStudy * study = AMITK_STUDY(object); if (study->creation_date != NULL) { g_free(study->creation_date); study->creation_date = NULL; } if (study->filename != NULL) { g_free(study->filename); study->filename = NULL; } if (study->line_profile != NULL) { g_object_unref(study->line_profile); study->line_profile = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); } static AmitkObject * study_copy (const AmitkObject * object) { AmitkStudy * copy; g_return_val_if_fail(AMITK_IS_STUDY(object), NULL); copy = amitk_study_new(NULL); amitk_object_copy_in_place(AMITK_OBJECT(copy), object); return AMITK_OBJECT(copy); } static void study_copy_in_place(AmitkObject * dest_object, const AmitkObject * src_object) { AmitkStudy * dest_study; AmitkView i_view; g_return_if_fail(AMITK_IS_STUDY(src_object)); g_return_if_fail(AMITK_IS_STUDY(dest_object)); dest_study = AMITK_STUDY(dest_object); amitk_study_set_creation_date(dest_study, AMITK_STUDY_CREATION_DATE(src_object)); dest_study->view_center = AMITK_STUDY(src_object)->view_center; amitk_study_set_view_thickness(dest_study, AMITK_STUDY_VIEW_THICKNESS(src_object)); dest_study->view_start_time = AMITK_STUDY_VIEW_START_TIME(src_object); dest_study->view_duration = AMITK_STUDY_VIEW_DURATION(src_object); dest_study->zoom = AMITK_STUDY_ZOOM(src_object); dest_study->fov = AMITK_STUDY_FOV(src_object); dest_study->fuse_type = AMITK_STUDY_FUSE_TYPE(src_object); dest_study->view_mode = AMITK_STUDY_VIEW_MODE(src_object); dest_study->canvas_target = AMITK_STUDY_CANVAS_TARGET(src_object); for (i_view=0; i_viewcanvas_visible[i_view] = AMITK_STUDY_CANVAS_VISIBLE(src_object, i_view); /* preferences */ dest_study->canvas_roi_width = AMITK_STUDY_CANVAS_ROI_WIDTH(src_object); #ifdef AMIDE_LIBGNOMECANVAS_AA dest_study->canvas_roi_transparency = AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(src_object); #else dest_study->canvas_line_style = AMITK_STUDY_CANVAS_LINE_STYLE(src_object); dest_study->canvas_fill_roi = AMITK_STUDY_CANVAS_FILL_ROI(src_object); #endif dest_study->canvas_layout = AMITK_STUDY_CANVAS_LAYOUT(src_object); dest_study->canvas_maintain_size = AMITK_STUDY_CANVAS_MAINTAIN_SIZE(src_object); dest_study->canvas_target_empty_area = AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(src_object); dest_study->panel_layout = AMITK_STUDY_PANEL_LAYOUT(src_object); /* line profile */ amitk_line_profile_copy_in_place(dest_study->line_profile, AMITK_STUDY_LINE_PROFILE(src_object)); /* make a separate copy in memory of the study's name and filename */ amitk_study_set_filename(dest_study, AMITK_STUDY_FILENAME(src_object)); AMITK_OBJECT_CLASS (parent_class)->object_copy_in_place (dest_object, src_object); } static void study_write_xml(const AmitkObject * object,xmlNodePtr nodes, FILE *study_file) { AmitkStudy * study; AmitkView i_view; gchar * temp_string; AMITK_OBJECT_CLASS(parent_class)->object_write_xml(object, nodes, study_file); study = AMITK_STUDY(object); xml_save_string(nodes, "creation_date", AMITK_STUDY_CREATION_DATE(study)); amitk_point_write_xml(nodes, "view_center", AMITK_STUDY_VIEW_CENTER(study)); xml_save_real(nodes, "view_thickness", AMITK_STUDY_VIEW_THICKNESS(study)); xml_save_time(nodes, "view_start_time", AMITK_STUDY_VIEW_START_TIME(study)); xml_save_time(nodes, "view_duration", AMITK_STUDY_VIEW_DURATION(study)); xml_save_real(nodes, "zoom", AMITK_STUDY_ZOOM(study)); xml_save_real(nodes, "fov", AMITK_STUDY_FOV(study)); xml_save_string(nodes, "fuse_type", amitk_fuse_type_get_name(AMITK_STUDY_FUSE_TYPE(study))); xml_save_string(nodes, "view_mode", amitk_view_mode_get_name(AMITK_STUDY_VIEW_MODE(study))); for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { temp_string = g_strdup_printf("%s_canvas_visible", amitk_view_get_name(i_view)); xml_save_boolean(nodes, temp_string, AMITK_STUDY_CANVAS_VISIBLE(study, i_view)); g_free(temp_string); } xml_save_boolean(nodes, "canvas_target", AMITK_STUDY_CANVAS_TARGET(study)); /* preferences */ xml_save_int(nodes, "canvas_roi_width", AMITK_STUDY_CANVAS_ROI_WIDTH(study)); #ifdef AMIDE_LIBGNOMECANVAS_AA xml_save_real(nodes, "canvas_roi_transparency", AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(study)); #else xml_save_int(nodes, "canvas_line_style", AMITK_STUDY_CANVAS_LINE_STYLE(study)); xml_save_int(nodes, "canvas_fill_roi", AMITK_STUDY_CANVAS_FILL_ROI(study)); #endif xml_save_string(nodes, "canvas_layout", amitk_layout_get_name(AMITK_STUDY_CANVAS_LAYOUT(study))); xml_save_boolean(nodes, "canvas_maintain_size", AMITK_STUDY_CANVAS_MAINTAIN_SIZE(study)); xml_save_int(nodes, "canvas_target_empty_area", AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(study)); xml_save_string(nodes, "panel_layout", amitk_panel_layout_get_name(AMITK_STUDY_PANEL_LAYOUT(study))); return; } static gchar * study_read_xml(AmitkObject * object, xmlNodePtr nodes, FILE * study_file, gchar * error_buf) { AmitkStudy * study; gchar * creation_date; AmitkFuseType i_fuse_type; AmitkViewMode i_view_mode; gchar * temp_string; AmitkView i_view; AmitkLayout i_layout; AmitkPanelLayout i_panel_layout; gboolean all_false; error_buf = AMITK_OBJECT_CLASS(parent_class)->object_read_xml(object, nodes, study_file, error_buf); study = AMITK_STUDY(object); creation_date = xml_get_string(nodes, "creation_date"); amitk_study_set_creation_date(study, creation_date); g_free(creation_date); /* get our view parameters */ amitk_study_set_view_center(study, amitk_point_read_xml(nodes, "view_center", &error_buf)); amitk_study_set_view_thickness(study, xml_get_real(nodes, "view_thickness", &error_buf)); amitk_study_set_view_start_time(study, xml_get_time(nodes, "view_start_time", &error_buf)); amitk_study_set_view_duration(study, xml_get_time(nodes, "view_duration", &error_buf)); amitk_study_set_zoom(study, xml_get_real(nodes, "zoom", &error_buf)); if (xml_node_exists(nodes, "fov")) amitk_study_set_fov(study, xml_get_real(nodes, "fov", &error_buf)); amitk_study_set_canvas_target(study, xml_get_boolean(nodes, "canvas_target", &error_buf)); /* preferences */ amitk_study_set_canvas_roi_width(study, xml_get_int_with_default(nodes, "canvas_roi_width", AMITK_STUDY_CANVAS_ROI_WIDTH(study))); #ifdef AMIDE_LIBGNOMECANVAS_AA amitk_study_set_canvas_roi_transparency(study, xml_get_real_with_default(nodes, "canvas_roi_transparency", AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(study))); #else amitk_study_set_canvas_line_style(study, xml_get_int_with_default(nodes, "canvas_line_style", AMITK_STUDY_CANVAS_LINE_STYLE(study))); if (xml_node_exists(nodes, "canvas_fill_isocontour")) /* legacy */ amitk_study_set_canvas_fill_roi(study, xml_get_int_with_default(nodes, "canvas_fill_isocontour", AMITK_STUDY_CANVAS_FILL_ROI(study))); else amitk_study_set_canvas_fill_roi(study, xml_get_int_with_default(nodes, "canvas_fill_roi", AMITK_STUDY_CANVAS_FILL_ROI(study))); #endif amitk_study_set_canvas_maintain_size(study, xml_get_boolean_with_default(nodes, "canvas_maintain_size", AMITK_STUDY_CANVAS_MAINTAIN_SIZE(study))); amitk_study_set_canvas_target_empty_area(study, xml_get_int_with_default(nodes, "canvas_target_empty_area", AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(study))); /* get layout */ temp_string = xml_get_string(nodes, "canvas_layout"); if (temp_string != NULL) { for (i_layout=0; i_layout < AMITK_LAYOUT_NUM; i_layout++) if (g_ascii_strcasecmp(temp_string, amitk_layout_get_name(i_layout)) == 0) amitk_study_set_canvas_layout(study, i_layout); g_free(temp_string); } /* get panel layout */ temp_string = xml_get_string(nodes, "panel_layout"); if (temp_string != NULL) { for (i_panel_layout=0; i_panel_layout < AMITK_PANEL_LAYOUT_NUM; i_panel_layout++) if (g_ascii_strcasecmp(temp_string, amitk_panel_layout_get_name(i_panel_layout)) == 0) amitk_study_set_panel_layout(study, i_panel_layout); g_free(temp_string); } /* sanity check */ if (AMITK_STUDY_ZOOM(study) < EPSILON) { amitk_append_str_with_newline(&error_buf,_("inappropriate zoom (%5.3f) for study, reseting to 1.0"), AMITK_STUDY_ZOOM(study)); amitk_study_set_zoom(study, 1.0); } /* figure out the fuse type */ temp_string = xml_get_string(nodes, "fuse_type"); if (temp_string != NULL) { for (i_fuse_type=0; i_fuse_type < AMITK_FUSE_TYPE_NUM; i_fuse_type++) if (g_ascii_strcasecmp(temp_string, amitk_fuse_type_get_name(i_fuse_type)) == 0) amitk_study_set_fuse_type(study, i_fuse_type); g_free(temp_string); } /* figure out the view mode */ temp_string = xml_get_string(nodes, "view_mode"); if (temp_string != NULL) { for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) if (g_ascii_strcasecmp(temp_string, amitk_view_mode_get_name(i_view_mode)) == 0) amitk_study_set_view_mode(study, i_view_mode); g_free(temp_string); } /* figure out which canvases are visible */ for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { temp_string = g_strdup_printf("%s_canvas_visible", amitk_view_get_name(i_view)); study->canvas_visible[i_view] = xml_get_boolean(nodes, temp_string, &error_buf); g_free(temp_string); } /* ---- legacy cruft ---- */ /* canvas_"view"_visible added previous to amide 0.7.7, set all to TRUE if none set */ all_false = TRUE; for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { all_false = all_false && !AMITK_STUDY_CANVAS_VISIBLE(study, i_view); } if (all_false) for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) study->canvas_visible[i_view] = TRUE; return error_buf; } static void set_voxel_dim_and_zoom(AmitkStudy * study, amide_real_t voxel_dim, amide_real_t zoom) { study->zoom = zoom; study->voxel_dim = voxel_dim; study->voxel_dim_valid=TRUE; g_signal_emit(G_OBJECT(study), study_signals[VOXEL_DIM_OR_ZOOM_CHANGED], 0); } static void study_recalc_voxel_dim(AmitkStudy * study) { amide_real_t voxel_dim; amide_real_t zoom; if (AMITK_OBJECT_CHILDREN(study) == NULL) return; /* no children, no voxel dim to recalculate */ voxel_dim = amitk_data_sets_get_max_min_voxel_size(AMITK_OBJECT_CHILDREN(study)); if (AMITK_STUDY_VOXEL_DIM_VALID(study) && !REAL_EQUAL(voxel_dim,AMITK_STUDY_VOXEL_DIM(study))) { /* update the zoom conservatively, so the canvas pixel size stays equal or gets smaller */ if (voxel_dim < AMITK_STUDY_VOXEL_DIM(study)) zoom = AMITK_STUDY_ZOOM(study)*voxel_dim/AMITK_STUDY_VOXEL_DIM(study); else zoom = AMITK_STUDY_ZOOM(study); set_voxel_dim_and_zoom(study, voxel_dim, zoom); } else { set_voxel_dim_and_zoom(study, voxel_dim,AMITK_STUDY_ZOOM(study)); } return; } static void study_add_child(AmitkObject *object, AmitkObject *child) { if (AMITK_IS_DATA_SET(child)) { /* if this is for the first dataset added, get a reasonable view center */ if (!amitk_objects_has_type(AMITK_OBJECT_CHILDREN(object), AMITK_OBJECT_TYPE_DATA_SET, TRUE)) amitk_study_set_view_center(AMITK_STUDY(object), amitk_volume_get_center(AMITK_VOLUME(child))); } /* run the parent class function so added child is in the object's child list */ AMITK_OBJECT_CLASS(parent_class)->object_add_child (object, child); /* keep the minimum voxel dimension accurate */ if (AMITK_IS_DATA_SET(child)) { study_recalc_voxel_dim(AMITK_STUDY(object)); g_signal_connect_swapped(G_OBJECT(child), "voxel_size_changed", G_CALLBACK(study_recalc_voxel_dim), object); } return; } static void study_remove_child(AmitkObject *object, AmitkObject *child) { gboolean data_set = FALSE; if (AMITK_IS_DATA_SET(child)) { data_set = TRUE; /* need to know now, child might get unrefed before recalc */ g_signal_handlers_disconnect_by_func(G_OBJECT(child), G_CALLBACK(study_recalc_voxel_dim), object); } AMITK_OBJECT_CLASS(parent_class)->object_remove_child (object, child); if (data_set) study_recalc_voxel_dim(AMITK_STUDY(object)); return; } AmitkStudy * amitk_study_new (AmitkPreferences * preferences) { AmitkStudy * study; study = g_object_new(amitk_study_get_type(), NULL); amitk_object_set_name(AMITK_OBJECT(study), blank_name); if (preferences != NULL) { study->canvas_roi_width = AMITK_PREFERENCES_CANVAS_ROI_WIDTH(preferences); #ifdef AMIDE_LIBGNOMECANVAS_AA study->canvas_roi_transparency = AMITK_PREFERENCES_CANVAS_ROI_TRANSPARENCY(preferences); #else study->canvas_line_style = AMITK_PREFERENCES_CANVAS_LINE_STYLE(preferences); study->canvas_fill_roi = AMITK_PREFERENCES_CANVAS_FILL_ROI(preferences); #endif study->canvas_layout = AMITK_PREFERENCES_CANVAS_LAYOUT(preferences); study->canvas_maintain_size = AMITK_PREFERENCES_CANVAS_MAINTAIN_SIZE(preferences); study->canvas_target_empty_area = AMITK_PREFERENCES_CANVAS_TARGET_EMPTY_AREA(preferences); study->panel_layout = AMITK_PREFERENCES_PANEL_LAYOUT(preferences); } return study; } /* sets the filename of a study */ void amitk_study_set_filename(AmitkStudy * study, const gchar * new_filename) { gchar * temp_string; g_return_if_fail(AMITK_IS_STUDY(study)); g_free(study->filename); /* free up the memory used by the old filename */ study->filename = NULL; if (new_filename == NULL) return; temp_string = g_strdup(new_filename); /* and assign the new name */ /* and remove any trailing slashes */ g_strreverse(temp_string); if (strchr(temp_string, '/') == temp_string) { study->filename = g_strdup(temp_string+1); g_free(temp_string); } else { study->filename=temp_string; } g_strreverse(study->filename); g_signal_emit(G_OBJECT(study), study_signals[FILENAME_CHANGED], 0); return; } void amitk_study_suggest_name(AmitkStudy * study, const gchar * suggested_name) { g_return_if_fail(AMITK_IS_STUDY(study)); if (suggested_name == 0) return; if (strlen(suggested_name) == 0) return; if ((AMITK_OBJECT_NAME(study) == NULL) || (g_strcmp0(AMITK_OBJECT_NAME(study), "") == 0) || (g_ascii_strncasecmp(blank_name, AMITK_OBJECT_NAME(study), strlen(AMITK_OBJECT_NAME(study))) == 0)) amitk_object_set_name(AMITK_OBJECT(study), suggested_name); return; } /* sets the date of a study note: no error checking of the date is currently done. */ void amitk_study_set_creation_date(AmitkStudy * study, const gchar * new_date) { g_return_if_fail(AMITK_IS_STUDY(study)); g_free(study->creation_date); /* free up the memory used by the old creation date */ study->creation_date = g_strdup(new_date); /* and assign the new name */ return; } /* new_center should be in the base coordinate space */ void amitk_study_set_view_center(AmitkStudy * study, const AmitkPoint new_center) { AmitkPoint temp; g_return_if_fail(AMITK_IS_STUDY(study)); temp = amitk_space_b2s(AMITK_SPACE(study), new_center); if (!POINT_EQUAL(study->view_center, temp)) { study->view_center = temp; g_signal_emit(G_OBJECT(study), study_signals[VIEW_CENTER_CHANGED], 0); } return; } /* refuses bad choices for thickness */ void amitk_study_set_view_thickness(AmitkStudy * study, const amide_real_t new_thickness) { amide_real_t min_voxel_size; amide_real_t temp; g_return_if_fail(AMITK_IS_STUDY(study)); min_voxel_size = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(study)); if (min_voxel_size < 0) temp = new_thickness; else if (new_thickness < min_voxel_size) temp = min_voxel_size; else temp = new_thickness; if (!REAL_EQUAL(study->view_thickness, temp)) { study->view_thickness = temp; g_signal_emit(G_OBJECT(study), study_signals[THICKNESS_CHANGED], 0); } return; } void amitk_study_set_view_start_time (AmitkStudy * study, const amide_time_t new_start) { g_return_if_fail(AMITK_IS_STUDY(study)); if (!REAL_EQUAL(study->view_start_time, new_start)) { study->view_start_time = new_start; g_signal_emit(G_OBJECT(study), study_signals[TIME_CHANGED], 0); } return; } void amitk_study_set_view_duration (AmitkStudy * study, const amide_time_t new_duration) { g_return_if_fail(AMITK_IS_STUDY(study)); if (!REAL_EQUAL(study->view_duration, new_duration)) { study->view_duration = new_duration; g_signal_emit(G_OBJECT(study), study_signals[TIME_CHANGED], 0); } return; } void amitk_study_set_fuse_type(AmitkStudy * study, const AmitkFuseType new_fuse_type) { g_return_if_fail(AMITK_IS_STUDY(study)); if (study->fuse_type != new_fuse_type) { study->fuse_type = new_fuse_type; g_signal_emit(G_OBJECT(study), study_signals[FUSE_TYPE_CHANGED], 0); } return; } void amitk_study_set_view_mode(AmitkStudy * study, const AmitkViewMode new_view_mode) { g_return_if_fail(AMITK_IS_STUDY(study)); if (study->view_mode != new_view_mode) { study->view_mode = new_view_mode; g_signal_emit(G_OBJECT(study), study_signals[VIEW_MODE_CHANGED], 0); } return; } /* note, at least one canvas has to remain visible at all times, function won't set visible to FALSE for a canvas if this condition will not be met */ void amitk_study_set_canvas_visible(AmitkStudy * study, const AmitkView view, const gboolean visible) { AmitkView i_view; gboolean one_visible; g_return_if_fail(AMITK_IS_STUDY(study)); /* make sure one canvas will remain visible */ one_visible = FALSE; for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view ++) { if (i_view == view) one_visible = one_visible || visible; else one_visible = one_visible || AMITK_STUDY_CANVAS_VISIBLE(study, i_view); } if (!one_visible) return; if (AMITK_STUDY_CANVAS_VISIBLE(study, view) != visible) { study->canvas_visible[view] = visible; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_VISIBLE_CHANGED], 0); } return; } void amitk_study_set_zoom(AmitkStudy * study, const amide_real_t new_zoom) { g_return_if_fail(AMITK_IS_STUDY(study)); if (!REAL_EQUAL(AMITK_STUDY_ZOOM(study), new_zoom)) set_voxel_dim_and_zoom(study, AMITK_STUDY_VOXEL_DIM(study), new_zoom); return; } void amitk_study_set_fov(AmitkStudy * study, const amide_real_t new_fov) { g_return_if_fail(AMITK_IS_STUDY(study)); if (!REAL_EQUAL(AMITK_STUDY_FOV(study), new_fov)) { study->fov = new_fov; g_signal_emit(G_OBJECT(study), study_signals[FOV_CHANGED],0); } return; } void amitk_study_set_canvas_target(AmitkStudy * study, const gboolean always_on) { g_return_if_fail(AMITK_IS_STUDY(study)); if (AMITK_STUDY_CANVAS_TARGET(study) != always_on) { study->canvas_target = always_on; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_TARGET_CHANGED], 0); } return; } void amitk_study_set_canvas_roi_width(AmitkStudy * study, gint roi_width) { g_return_if_fail(AMITK_IS_STUDY(study)); if (roi_width < AMITK_PREFERENCES_MIN_ROI_WIDTH) roi_width = AMITK_PREFERENCES_MIN_ROI_WIDTH; if (roi_width > AMITK_PREFERENCES_MAX_ROI_WIDTH) roi_width = AMITK_PREFERENCES_MAX_ROI_WIDTH; if (AMITK_STUDY_CANVAS_ROI_WIDTH(study) != roi_width) { study->canvas_roi_width = roi_width; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_ROI_PREFERENCE_CHANGED], 0); } return; } #ifdef AMIDE_LIBGNOMECANVAS_AA void amitk_study_set_canvas_roi_transparency(AmitkStudy * study, const gdouble transparency) { g_return_if_fail(AMITK_IS_STUDY(study)); g_return_if_fail(transparency >= 0.0); g_return_if_fail(transparency <= 1.0); if (AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(study) != transparency) { study->canvas_roi_transparency = transparency; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_ROI_PREFERENCE_CHANGED], 0); } return; } #else void amitk_study_set_canvas_line_style(AmitkStudy * study, const GdkLineStyle line_style){ g_return_if_fail(AMITK_IS_STUDY(study)); if (AMITK_STUDY_CANVAS_LINE_STYLE(study) != line_style) { study->canvas_line_style = line_style; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_ROI_PREFERENCE_CHANGED], 0); } return; } void amitk_study_set_canvas_fill_roi(AmitkStudy * study, const gboolean fill_roi){ g_return_if_fail(AMITK_IS_STUDY(study)); if (AMITK_STUDY_CANVAS_FILL_ROI(study) != fill_roi) { study->canvas_fill_roi = fill_roi; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_ROI_PREFERENCE_CHANGED], 0); } return; } #endif void amitk_study_set_canvas_layout(AmitkStudy * study, const AmitkLayout layout) { g_return_if_fail(AMITK_IS_STUDY(study)); if (AMITK_STUDY_CANVAS_LAYOUT(study) != layout) { study->canvas_layout = layout; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_LAYOUT_PREFERENCE_CHANGED], 0); } return; } void amitk_study_set_canvas_maintain_size(AmitkStudy * study, const gboolean maintain_size){ g_return_if_fail(AMITK_IS_STUDY(study)); if (AMITK_STUDY_CANVAS_MAINTAIN_SIZE(study) != maintain_size) { study->canvas_maintain_size = maintain_size; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_GENERAL_PREFERENCE_CHANGED], 0); } return; } void amitk_study_set_canvas_target_empty_area(AmitkStudy * study, gint target_empty_area){ g_return_if_fail(AMITK_IS_STUDY(study)); /* sanity checks */ if (target_empty_area < AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA) target_empty_area = AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA; if (target_empty_area > AMITK_PREFERENCES_MAX_TARGET_EMPTY_AREA) target_empty_area = AMITK_PREFERENCES_MAX_TARGET_EMPTY_AREA; if (AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(study) != target_empty_area) { study->canvas_target_empty_area = target_empty_area; g_signal_emit(G_OBJECT(study), study_signals[CANVAS_TARGET_PREFERENCE_CHANGED], 0); } return; } void amitk_study_set_panel_layout(AmitkStudy * study, const AmitkPanelLayout panel_layout) { g_return_if_fail(AMITK_IS_STUDY(study)); if (AMITK_STUDY_PANEL_LAYOUT(study) != panel_layout) { study->panel_layout = panel_layout; g_signal_emit(G_OBJECT(study), study_signals[PANEL_LAYOUT_PREFERENCE_CHANGED], 0); } return; } /* try to recover a corrupted file */ AmitkStudy * amitk_study_recover_xml(const gchar * study_filename, AmitkPreferences * preferences) { AmitkStudy * study = NULL; AmitkObject * recovered_object; gchar * error_buf=NULL; FILE * study_file=NULL; guint64 size, counter, start_location=0, end_location=0; gint returned_char; gboolean have_start_location; if (amitk_is_xif_directory(study_filename, NULL, NULL)) { g_warning("Recover function only works with XIF flat files, not XIF directories"); return NULL; } /* open her on up */ if ((study_file = fopen(study_filename, "rb")) == NULL) { g_warning(_("Couldn't open file %s\n"), study_filename); return NULL; } have_start_location = FALSE; counter = 0; while ((returned_char = fgetc(study_file)) != EOF) { /* find the start of the amide xml object */ if (!have_start_location) { if (returned_char == amide_data_file_xml_start_tag[counter]) { if (counter == 0) start_location = ftell(study_file)-1; counter++; if (counter == strlen(amide_data_file_xml_start_tag)) { /* we've got the start of an object */ counter = 0; have_start_location = TRUE; } } else { counter = 0; } /* work on finding the end of the amide xml object */ } else { if (returned_char == amide_data_file_xml_end_tag[counter]) { counter++; if (counter == strlen(amide_data_file_xml_end_tag)) { counter = 0; /* back the start location to include the xml tag*/ start_location -= strlen(amide_data_file_xml_tag)+3; /* read in object */ end_location = ftell(study_file); size = end_location-start_location+1; recovered_object = amitk_object_read_xml(NULL, study_file, start_location, size, &error_buf); if (recovered_object != NULL) { if (!AMITK_IS_STUDY(recovered_object)) { if (study == NULL) study = amitk_study_new(preferences); amitk_object_add_child(AMITK_OBJECT(study), recovered_object); } amitk_object_unref(recovered_object); } /* return to the current spot in the file */ fseek(study_file, end_location,SEEK_SET); have_start_location = FALSE; } } else { counter = 0; } } } /* display accumulated warning messages */ if (error_buf != NULL) { amitk_append_str_with_newline(&error_buf, ""); amitk_append_str_with_newline(&error_buf, _("The above warnings may arise because portions of the XIF")); amitk_append_str_with_newline(&error_buf, _("file were corrupted.")); g_warning("%s",error_buf); g_free(error_buf); } /* remember the name of the file/directory for convience */ if (study != NULL) amitk_study_set_filename(study, study_filename); return study; } /* function to load in a study from disk in xml format */ AmitkStudy * amitk_study_load_xml(const gchar * study_filename) { AmitkStudy * study; gchar * old_dir=NULL; gchar * load_filename=NULL; gchar * error_buf=NULL; gboolean xif_directory=FALSE; gboolean legacy1=FALSE; FILE * study_file=NULL; guint64 location_le, size_le; guint64 location, size; /* are we dealing with a xif directory */ if (amitk_is_xif_directory(study_filename, &legacy1, &load_filename)) { xif_directory=TRUE; /* switch into our new directory */ old_dir = g_get_current_dir(); if (chdir(study_filename) != 0) { g_warning(_("Couldn't change directories in loading study")); return NULL; } } else if (amitk_is_xif_flat_file(study_filename, &location_le, &size_le)){ /* flat file */ if ((study_file = fopen(study_filename, "rb")) == NULL) { g_warning(_("Couldn't open file %s\n"), study_filename); return NULL; } } else { g_warning("Not a XIF study file: %s\n", study_filename); return NULL; } location = GUINT64_FROM_LE(location_le); size = GUINT64_FROM_LE(size_le); /* sanity check */ if ((((location == 0) || (size == 0))) && !xif_directory) { g_warning(_("File is corrupt. The file may have been incompletely saved. You can attempt recovering the file by using the recover function under the file menu.")); return NULL; } /* load in the study */ if (legacy1) study = legacy_load_xml(&error_buf); else study = AMITK_STUDY(amitk_object_read_xml(load_filename, study_file, location, size, &error_buf)); if (load_filename != NULL) g_free(load_filename); if (study_file != NULL) fclose(study_file); /* display accumulated warning messages */ if (error_buf != NULL) { amitk_append_str_with_newline(&error_buf, ""); amitk_append_str_with_newline(&error_buf, _("The above warnings most likely indicate changes to the")); amitk_append_str_with_newline(&error_buf, _("XIF file format, please resave the data as soon as possible.")); g_warning("%s",error_buf); g_free(error_buf); } /* remember the name of the file/directory for convience */ if (study != NULL) amitk_study_set_filename(study, study_filename); if (xif_directory) { /* and return to the old directory */ if (chdir(old_dir) != 0) { g_warning(_("Couldn't return to previous directory in load study")); if (study != NULL) study = amitk_object_unref(study); } g_free(old_dir); } return study; } /* function to writeout the study to disk in an xif file */ gboolean amitk_study_save_xml(AmitkStudy * study, const gchar * study_filename, gboolean save_as_directory) { gchar * old_dir=NULL; struct stat file_info; gchar * temp_string; DIR * directory; struct dirent * directory_entry; guint64 location, size; guint64 location_le, size_le; FILE * study_file=NULL; /* see if the filename already exists, remove stuff if needed */ if (stat(study_filename, &file_info) == 0) { /* and start deleting everything in the filename/directory */ if (S_ISDIR(file_info.st_mode)) { directory = opendir(study_filename); while ((directory_entry = readdir(directory)) != NULL) { temp_string = g_strdup_printf("%s%s%s", study_filename,G_DIR_SEPARATOR_S, directory_entry->d_name); if ((g_pattern_match_simple("*.xml",directory_entry->d_name)) || (g_pattern_match_simple("*.dat",directory_entry->d_name))) if (unlink(temp_string) != 0) g_warning(_("Couldn't unlink file: %s"),temp_string); g_free(temp_string); } if (!save_as_directory) /* get rid of the directory too if we're overwriting with a file*/ if (rmdir(study_filename) != 0) { g_warning(_("Couldn't remove directory: %s"), study_filename); return FALSE; } } else if (S_ISREG(file_info.st_mode)) { if (unlink(study_filename) != 0) { g_warning(_("Couldn't unlink file: %s"),study_filename); return FALSE; } } else { g_warning(_("Unrecognized file type for file: %s, couldn't delete"),study_filename); return FALSE; } } if (save_as_directory) { if (stat(study_filename, &file_info) != 0) { /* make the directory if needed */ if (g_mkdir(study_filename, 0766) != 0) { g_warning(_("Couldn't create amide directory: %s"),study_filename); return FALSE; } } } /* remember the name of the xif file/directory of this study */ amitk_study_set_filename(study, study_filename); /* get into the output directory/create output file */ if (save_as_directory) { old_dir = g_get_current_dir(); if (chdir(study_filename) != 0) { g_warning(_("Couldn't change directories in writing study, study not saved")); return FALSE; } } else { /* flat file */ if ((study_file = fopen(study_filename, "wb")) == NULL) { g_warning(_("Couldn't open file %s\n"), study_filename); return FALSE; } fprintf(study_file, "%s Version %s", AMITK_FLAT_FILE_MAGIC_STRING, AMITK_FILE_VERSION); fseek(study_file, 64+2*sizeof(guint64), SEEK_SET); } /* save the study */ amitk_object_write_xml(AMITK_OBJECT(study), study_file, NULL, &location, &size); if (save_as_directory) { if (chdir(old_dir) != 0) { g_warning(_("Couldn't return to previous directory in load study")); study = amitk_object_unref(study); } } else { /* flat file */ /* record location of study object xml, always little endian */ fseek(study_file, 64, SEEK_SET); location_le = GUINT64_TO_LE(location); size_le = GUINT64_TO_LE(size); fwrite(&location_le, 1, sizeof(guint64), study_file); fwrite(&size_le, 1, sizeof(guint64), study_file); fclose(study_file); } return TRUE; } const gchar * amitk_fuse_type_get_name(const AmitkFuseType fuse_type) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_FUSE_TYPE); enum_value = g_enum_get_value(enum_class, fuse_type); g_type_class_unref(enum_class); return enum_value->value_nick; } const gchar * amitk_view_mode_get_name(const AmitkViewMode view_mode) { GEnumClass * enum_class; GEnumValue * enum_value; enum_class = g_type_class_ref(AMITK_TYPE_VIEW_MODE); enum_value = g_enum_get_value(enum_class, view_mode); g_type_class_unref(enum_class); return enum_value->value_nick; } amide-1.0.6/amide-current/src/amitk_study.h000066400000000000000000000217141423227705100206410ustar00rootroot00000000000000/* amitk_study.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_STUDY_H__ #define __AMITK_STUDY_H__ #include "amitk_object.h" #include "amitk_data_set.h" #include "amitk_roi.h" #include "amitk_fiducial_mark.h" #include "amitk_preferences.h" #include "amitk_line_profile.h" G_BEGIN_DECLS #define AMITK_TYPE_STUDY (amitk_study_get_type ()) #define AMITK_STUDY(study) (G_TYPE_CHECK_INSTANCE_CAST ((study), AMITK_TYPE_STUDY, AmitkStudy)) #define AMITK_STUDY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_STUDY, AmitkStudyClass)) #define AMITK_IS_STUDY(study) (G_TYPE_CHECK_INSTANCE_TYPE ((study), AMITK_TYPE_STUDY)) #define AMITK_IS_STUDY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_STUDY)) #define AMITK_STUDY_GET_CLASS(study) (G_TYPE_CHECK_GET_CLASS ((study), AMITK_TYPE_STUDY, AmitkStudyClass)) #define AMITK_STUDY_VIEW_CENTER(stu) (amitk_space_s2b(AMITK_SPACE(stu), AMITK_STUDY(stu)->view_center)) #define AMITK_STUDY_VIEW_THICKNESS(stu) (AMITK_STUDY(stu)->view_thickness) #define AMITK_STUDY_ZOOM(stu) (AMITK_STUDY(stu)->zoom) #define AMITK_STUDY_FOV(stu) (AMITK_STUDY(stu)->fov) #define AMITK_STUDY_VIEW_START_TIME(stu) (AMITK_STUDY(stu)->view_start_time) #define AMITK_STUDY_VIEW_DURATION(stu) (AMITK_STUDY(stu)->view_duration) #define AMITK_STUDY_CREATION_DATE(stu) (AMITK_STUDY(stu)->creation_date) #define AMITK_STUDY_FILENAME(stu) (AMITK_STUDY(stu)->filename) #define AMITK_STUDY_VOXEL_DIM(stu) (AMITK_STUDY(stu)->voxel_dim) #define AMITK_STUDY_VOXEL_DIM_VALID(stu) (AMITK_STUDY(stu)->voxel_dim_valid) #define AMITK_STUDY_FUSE_TYPE(stu) (AMITK_STUDY(stu)->fuse_type) #define AMITK_STUDY_VIEW_MODE(stu) (AMITK_STUDY(stu)->view_mode) #define AMITK_STUDY_CANVAS_VISIBLE(stu, canvas) (AMITK_STUDY(stu)->canvas_visible[canvas]) #define AMITK_STUDY_CANVAS_TARGET(stu) (AMITK_STUDY(stu)->canvas_target) #define AMITK_STUDY_CANVAS_ROI_WIDTH(stu) (AMITK_STUDY(stu)->canvas_roi_width) #ifdef AMIDE_LIBGNOMECANVAS_AA #define AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(stu) (AMITK_STUDY(stu)->canvas_roi_transparency) #else #define AMITK_STUDY_CANVAS_LINE_STYLE(stu) (AMITK_STUDY(stu)->canvas_line_style) #define AMITK_STUDY_CANVAS_FILL_ROI(stu) (AMITK_STUDY(stu)->canvas_fill_roi) #endif #define AMITK_STUDY_CANVAS_LAYOUT(stu) (AMITK_STUDY(stu)->canvas_layout) #define AMITK_STUDY_CANVAS_MAINTAIN_SIZE(stu) (AMITK_STUDY(stu)->canvas_maintain_size) #define AMITK_STUDY_CANVAS_TARGET_EMPTY_AREA(stu) (AMITK_STUDY(stu)->canvas_target_empty_area) #define AMITK_STUDY_PANEL_LAYOUT(stu) (AMITK_STUDY(stu)->panel_layout) #define AMITK_STUDY_LINE_PROFILE(stu) (AMITK_STUDY(stu)->line_profile) typedef enum { AMITK_FUSE_TYPE_BLEND, AMITK_FUSE_TYPE_OVERLAY, AMITK_FUSE_TYPE_NUM } AmitkFuseType; typedef struct _AmitkStudyClass AmitkStudyClass; typedef struct _AmitkStudy AmitkStudy; struct _AmitkStudy { AmitkObject parent; gchar * creation_date; /* when this study was created */ /* canvas view parameters */ AmitkPoint view_center; /* wrt the study coordinate space */ amide_real_t view_thickness; amide_time_t view_start_time; amide_time_t view_duration; amide_real_t zoom; amide_real_t fov; /* field of view, in percent */ AmitkFuseType fuse_type; AmitkViewMode view_mode; gboolean canvas_visible[AMITK_VIEW_NUM]; gboolean canvas_target; /* target on/off */ /* canvas preferences */ gint canvas_roi_width; #ifdef AMIDE_LIBGNOMECANVAS_AA gdouble canvas_roi_transparency; #else GdkLineStyle canvas_line_style; gboolean canvas_fill_roi; #endif AmitkLayout canvas_layout; gboolean canvas_maintain_size; gint canvas_target_empty_area; /* in pixels */ AmitkPanelLayout panel_layout; /* stuff calculated when file is loaded and stored */ amide_real_t voxel_dim; /* prefered voxel/pixel dim, canvas wants this info */ gboolean voxel_dim_valid; /* stuff that doesn't need to be saved */ AmitkLineProfile * line_profile; gchar * filename; /* file name of the study */ }; struct _AmitkStudyClass { AmitkObjectClass parent_class; void (* filename_changed) (AmitkStudy * study); void (* thickness_changed) (AmitkStudy * study); void (* time_changed) (AmitkStudy * study); void (* canvas_visible_changed) (AmitkStudy * study); void (* view_mode_changed) (AmitkStudy * study); void (* canvas_target_changed) (AmitkStudy * study); void (* voxel_dim_or_zoom_changed) (AmitkStudy * study); void (* fov_changed) (AmitkStudy * study); void (* fuse_type_changed) (AmitkStudy * study); void (* view_center_changed) (AmitkStudy * study); void (* canvas_roi_preference_changed) (AmitkStudy * study); void (* canvas_general_preference_changed) (AmitkStudy * study); void (* canvas_target_preference_changed) (AmitkStudy * study); void (* canvas_layout_preference_changed) (AmitkStudy * study); void (* panel_layout_preference_changed) (AmitkStudy * study); }; /* Application-level methods */ GType amitk_study_get_type (void); AmitkStudy * amitk_study_new (AmitkPreferences * preferences); void amitk_study_set_filename (AmitkStudy * study, const gchar * new_filename); void amitk_study_suggest_name (AmitkStudy * study, const gchar * suggested_name); void amitk_study_set_creation_date (AmitkStudy * study, const gchar * new_date); void amitk_study_set_view_thickness (AmitkStudy * study, const amide_real_t new_thickness); void amitk_study_set_view_center (AmitkStudy * study, const AmitkPoint new_center); void amitk_study_set_view_start_time (AmitkStudy * study, const amide_time_t new_start); void amitk_study_set_view_duration (AmitkStudy * study, const amide_time_t new_duration); void amitk_study_set_fuse_type (AmitkStudy * study, const AmitkFuseType new_fuse_type); void amitk_study_set_view_mode (AmitkStudy * study, const AmitkViewMode new_view_mode); void amitk_study_set_canvas_visible (AmitkStudy * study, const AmitkView view, const gboolean visible); void amitk_study_set_zoom (AmitkStudy * study, const amide_real_t new_zoom); void amitk_study_set_fov (AmitkStudy * study, const amide_real_t new_fov); void amitk_study_set_canvas_target (AmitkStudy * study, const gboolean always_on); void amitk_study_set_canvas_roi_width (AmitkStudy * study, gint roi_width); #ifdef AMIDE_LIBGNOMECANVAS_AA void amitk_study_set_canvas_roi_transparency(AmitkStudy * study, const gdouble transparency); #else void amitk_study_set_canvas_line_style (AmitkStudy * study, const GdkLineStyle line_style); void amitk_study_set_canvas_fill_roi (AmitkStudy * study, const gboolean fill_roi); #endif void amitk_study_set_canvas_layout (AmitkStudy * study, const AmitkLayout layout); void amitk_study_set_canvas_maintain_size(AmitkStudy * study, const gboolean maintain_size); void amitk_study_set_canvas_target_empty_area(AmitkStudy * study, gint target_empty_area); void amitk_study_set_panel_layout (AmitkStudy * study, const AmitkPanelLayout panel_layout); AmitkStudy * amitk_study_recover_xml (const gchar * study_filename, AmitkPreferences * preferences); AmitkStudy * amitk_study_load_xml (const gchar * study_filename); gboolean amitk_study_save_xml (AmitkStudy * study, const gchar * study_filename, const gboolean save_as_directory); const gchar * amitk_fuse_type_get_name (const AmitkFuseType fuse_type); const gchar * amitk_view_mode_get_name (const AmitkViewMode view_mode); G_END_DECLS #endif /* __AMITK_STUDY_H__ */ amide-1.0.6/amide-current/src/amitk_threshold.c000066400000000000000000002517311423227705100214640ustar00rootroot00000000000000/* amitk_threshold.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapted from gtkcolorsel.c */ #include "amide_config.h" #include "amitk_common.h" #include "amitk_progress_dialog.h" #include "amitk_threshold.h" #include "pixmaps.h" #include "image.h" #include "amitk_marshal.h" #include "amitk_color_table_menu.h" #define THRESHOLD_COLOR_SCALE_SEPARATION 30.0 #define THRESHOLD_COLOR_SCALE_WIDTH 16.0 #define THRESHOLD_COLOR_SCALES_WIDTH (2.0*THRESHOLD_COLOR_SCALE_WIDTH+THRESHOLD_COLOR_SCALE_SEPARATION) #define THRESHOLD_COLOR_SCALE_HEIGHT (gdouble) AMITK_DATA_SET_DISTRIBUTION_SIZE #define THRESHOLD_HISTOGRAM_WIDTH (gdouble) IMAGE_DISTRIBUTION_WIDTH #define THRESHOLD_TRIANGLE_WIDTH 16.0 #define THRESHOLD_TRIANGLE_HEIGHT 12.0 /* internal variables */ static gchar * thresholding_names[] = { N_("per slice"), N_("per frame"), N_("interpolated between frames"), N_("global") }; /* thresholding explanations: per slice - threshold the images based on the max and min values in the current slice per frame - threshold the images based on the max and min values in the current frame interpolated between frames - threshold the images based on max and min values interpolated from the reference frame thresholds global - threshold the images based on the max and min values of the entire data set */ static gchar * threshold_style_names[] = { N_("Min/Max"), N_("Center/Width") }; /* threshold style explanations Min/Max - threshold by setting min and max values - Nuclear Medicine Style Center/Width - theshold by setting a window center and width - Radiology Style */ static void threshold_class_init (AmitkThresholdClass *klass); static void threshold_init (AmitkThreshold *threshold); static void threshold_destroy (GtkObject *object); static void threshold_show_all (GtkWidget * widget); static void threshold_construct(AmitkThreshold * threshold, AmitkThresholdLayout layout); static void threshold_add_data_set(AmitkThreshold * threshold, AmitkDataSet * ds); static void threshold_remove_data_set(AmitkThreshold * threshold); static gint threshold_visible_refs(AmitkDataSet * data_set); static void threshold_update_histogram(AmitkThreshold * threshold); static void threshold_update_spin_buttons(AmitkThreshold * threshold); static void threshold_update_arrow(AmitkThreshold * threshold, AmitkThresholdArrow arrow); static void threshold_update_color_scale(AmitkThreshold * threshold, AmitkThresholdScale scale); static void threshold_update_connector_lines(AmitkThreshold * threshold, AmitkThresholdScale scale); static void threshold_update_color_scales(AmitkThreshold * threshold); static void threshold_update_layout(AmitkThreshold * threshold); static void threshold_update_style(AmitkThreshold * threshold); static void threshold_update_type(AmitkThreshold * threshold); static void threshold_update_absolute_label(AmitkThreshold * threshold); static void threshold_update_windowing(AmitkThreshold * threshold); static void threshold_update_ref_frames(AmitkThreshold * threshold); static void threshold_update_color_table(AmitkThreshold * threshold, AmitkViewMode view_mode); static void threshold_update_color_tables(AmitkThreshold * threshold); static void ds_scale_factor_changed_cb(AmitkDataSet * ds, AmitkThreshold* threshold); static void ds_color_table_changed_cb(AmitkDataSet * ds, AmitkViewMode view_mode, AmitkThreshold* threshold); static void ds_thresholding_changed_cb(AmitkDataSet * ds, AmitkThreshold* threshold); static void ds_threshold_style_changed_cb(AmitkDataSet * ds, AmitkThreshold* threshold); static void ds_thresholds_changed_cb(AmitkDataSet * ds, AmitkThreshold* threshold); static void ds_conversion_changed_cb(AmitkDataSet * ds, AmitkThreshold* threshold); static void ds_modality_changed_cb(AmitkDataSet * ds, AmitkThreshold* threshold); static void study_view_mode_changed_cb(AmitkStudy * study, AmitkThreshold * threshold); static gint threshold_arrow_cb(GtkWidget* widget, GdkEvent * event, gpointer AmitkThreshold); static void color_table_cb(GtkWidget * widget, gpointer data); static void color_table_independent_cb(GtkWidget * widget, gpointer AmitkThreshold); static void threshold_ref_frame_cb(GtkWidget* widget, gpointer data); static void threshold_spin_button_cb(GtkWidget* widget, gpointer data); static void thresholding_cb(GtkWidget * widget, gpointer data); static void threshold_style_cb(GtkWidget * widget, gpointer data); static void windowing_cb(GtkWidget * widget, gpointer data); static void init_common(GtkWindow * threshold_dialog); static void threshold_dialog_class_init (AmitkThresholdDialogClass *klass); static void threshold_dialog_init (AmitkThresholdDialog *threshold_dialog); static void threshold_dialog_construct(AmitkThresholdDialog * dialog, GtkWindow * parent, AmitkDataSet * data_set); static void thresholds_dialog_class_init (AmitkThresholdsDialogClass *klass); static void thresholds_dialog_init (AmitkThresholdsDialog *thresholds_dialog); static void thresholds_dialog_construct(AmitkThresholdsDialog * thresholds_dialog, GtkWindow * parent, GList * data_sets); static GtkVBoxClass *threshold_parent_class; static GtkDialogClass *threshold_dialog_parent_class; static GtkDialogClass *thresholds_dialog_parent_class; static GdkCursor * threshold_cursor = NULL; GType amitk_threshold_get_type (void) { static GType threshold_type = 0; if (!threshold_type) { static const GTypeInfo threshold_info = { sizeof (AmitkThresholdClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) threshold_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkThreshold), 0, /* # preallocs */ (GInstanceInitFunc) threshold_init, NULL /* value table */ }; threshold_type = g_type_register_static(GTK_TYPE_VBOX, "AmitkThreshold", &threshold_info, 0); } return threshold_type; } static void threshold_class_init (AmitkThresholdClass *klass) { GtkObjectClass *gtkobject_class; GtkWidgetClass *widget_class; gtkobject_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; threshold_parent_class = g_type_class_peek_parent(klass); gtkobject_class->destroy = threshold_destroy; widget_class->show_all = threshold_show_all; } static void threshold_init (AmitkThreshold *threshold) { AmitkThresholdScale i_scale; AmitkThresholdLine i_line; guint i_ref; /* initialize some critical stuff */ for (i_ref=0; i_ref<2; i_ref++) { for (i_scale=0;i_scalecolor_scale_image[i_ref][i_scale] = NULL; } for (i_line=0;i_lineconnector_line[i_ref][i_line] = NULL; } threshold->histogram_image = NULL; if (threshold_cursor == NULL) threshold_cursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW); } static void threshold_destroy (GtkObject * object) { AmitkThreshold * threshold; g_return_if_fail (object != NULL); g_return_if_fail (AMITK_IS_THRESHOLD (object)); threshold = AMITK_THRESHOLD (object); threshold_remove_data_set(threshold); if (GTK_OBJECT_CLASS (threshold_parent_class)->destroy) (* GTK_OBJECT_CLASS (threshold_parent_class)->destroy) (object); } /* this is used to catch the show_all signal, which would show the widgets that we're currently might be hiding */ static void threshold_show_all (GtkWidget * widget) { /* AmitkThreshold * threshold; */ g_return_if_fail (widget != NULL); g_return_if_fail (AMITK_IS_THRESHOLD(widget)); /* threshold = AMITK_THRESHOLD(widget); */ gtk_widget_show(widget); } void amitk_threshold_style_widgets(GtkWidget ** radio_buttons, GtkWidget * hbox) { AmitkThresholdStyle i_threshold_style; GtkWidget * image; for (i_threshold_style = 0; i_threshold_style < AMITK_THRESHOLD_STYLE_NUM; i_threshold_style++) { radio_buttons[i_threshold_style] = gtk_radio_button_new(NULL); switch(i_threshold_style) { case AMITK_THRESHOLD_STYLE_MIN_MAX: image = gtk_image_new_from_stock("amide_icon_threshold_style_min_max",GTK_ICON_SIZE_LARGE_TOOLBAR); break; case AMITK_THRESHOLD_STYLE_CENTER_WIDTH: image = gtk_image_new_from_stock("amide_icon_threshold_style_center_width",GTK_ICON_SIZE_LARGE_TOOLBAR); break; default: image = NULL; g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } gtk_button_set_image(GTK_BUTTON(radio_buttons[i_threshold_style]), image); gtk_box_pack_start(GTK_BOX(hbox), radio_buttons[i_threshold_style], FALSE, FALSE, 3); gtk_widget_show(radio_buttons[i_threshold_style]); gtk_widget_set_tooltip_text(radio_buttons[i_threshold_style], threshold_style_names[i_threshold_style]); g_object_set_data(G_OBJECT(radio_buttons[i_threshold_style]), "threshold_style", GINT_TO_POINTER(i_threshold_style)); if (i_threshold_style != 0) gtk_radio_button_set_group(GTK_RADIO_BUTTON(radio_buttons[i_threshold_style]), gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_buttons[0]))); } } /* this gets called after we have a data set */ static void threshold_construct(AmitkThreshold * threshold, AmitkThresholdLayout layout) { GtkWidget * right_table; GtkWidget * left_table; GtkWidget * main_box; GtkWidget * hbox; guint right_row; guint left_row; gchar * temp_string; GtkWidget * label; GtkWidget * button; GtkWidget * image; AmitkThresholding i_thresholding; AmitkWindow i_window; guint i_ref; AmitkThresholdEntry i_entry; AmitkThresholdStyle i_threshold_style; AmitkLimit i_limit; AmitkViewMode i_view_mode; div_t x; /* we're using two tables packed into a box */ if (layout == AMITK_THRESHOLD_BOX_LAYOUT) main_box = gtk_hbox_new(FALSE,0); else /* layout == AMITK_THRESHOLD_LINEAR_LAYOUT */ main_box = gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(threshold), main_box); /*--------------------------------------- left table --------------------------------------- */ left_table = gtk_table_new(8,5,FALSE); left_row=0; gtk_box_pack_start(GTK_BOX(main_box), left_table, TRUE,TRUE,0); if (!threshold->minimal) { for (i_ref=0; i_ref<2; i_ref++) { threshold->percent_label[i_ref] = gtk_label_new(_("Percent")); gtk_table_attach(GTK_TABLE(left_table), threshold->percent_label[i_ref], 1+2*i_ref,2+2*i_ref,left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ threshold->absolute_label[i_ref] = gtk_label_new(""); gtk_table_attach(GTK_TABLE(left_table), threshold->absolute_label[i_ref], 2+2*i_ref,3+2*i_ref,left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ } left_row++; for (i_limit=0; i_limit < AMITK_LIMIT_NUM; i_limit++) { threshold->min_max_label[i_limit] = gtk_label_new(NULL); gtk_table_attach(GTK_TABLE(left_table), threshold->min_max_label[i_limit], 0,1,left_row+1-i_limit,left_row+2-i_limit, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(threshold->min_max_label[i_limit]); } for (i_ref=0; i_ref<2; i_ref++) { threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_PERCENT] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_PERCENT] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); g_signal_connect(G_OBJECT(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_PERCENT]), 1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_PERCENT]), 1); for (i_entry=0; i_entry< AMITK_THRESHOLD_ENTRY_NUM_ENTRIES; i_entry++) { gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][i_entry]), FALSE); g_object_set_data(G_OBJECT(threshold->spin_button[i_ref][i_entry]), "type", GINT_TO_POINTER(i_entry)); g_object_set_data(G_OBJECT(threshold->spin_button[i_ref][i_entry]), "which_ref", GINT_TO_POINTER(i_ref)); g_signal_connect(G_OBJECT(threshold->spin_button[i_ref][i_entry]), "value_changed", G_CALLBACK(threshold_spin_button_cb), threshold); } gtk_table_attach(GTK_TABLE(left_table), threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_PERCENT], 1+2*i_ref,2+2*i_ref, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_table_attach(GTK_TABLE(left_table), threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE], 2+2*i_ref,3+2*i_ref, left_row,left_row+1,X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_table_attach(GTK_TABLE(left_table), threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_PERCENT], 1+2*i_ref,2+2*i_ref, left_row+1,left_row+2, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_table_attach(GTK_TABLE(left_table), threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE], 2+2*i_ref,3+2*i_ref, left_row+1, left_row+2, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ } left_row+=2; } /* color table selectors */ for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { if (i_view_mode == AMITK_VIEW_MODE_SINGLE) threshold->color_table_label[i_view_mode] = gtk_label_new(_("Color Table:")); else { temp_string = g_strdup_printf(_("Color Table %d:"), i_view_mode+1); threshold->color_table_label[i_view_mode] = gtk_label_new(temp_string); g_free(temp_string); } gtk_table_attach(GTK_TABLE(left_table), threshold->color_table_label[i_view_mode], 0,1, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); threshold->color_table_hbox[i_view_mode] = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(left_table), threshold->color_table_hbox[i_view_mode], 1,5, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); if (i_view_mode == AMITK_VIEW_MODE_SINGLE) { threshold->color_table_independent[i_view_mode] = NULL; } else { threshold->color_table_independent[i_view_mode] = gtk_check_button_new(); g_object_set_data(G_OBJECT(threshold->color_table_independent[i_view_mode]), "view_mode", GINT_TO_POINTER(i_view_mode)); g_signal_connect(G_OBJECT(threshold->color_table_independent[i_view_mode]), "toggled", G_CALLBACK(color_table_independent_cb), threshold); gtk_box_pack_start(GTK_BOX(threshold->color_table_hbox[i_view_mode]), threshold->color_table_independent[i_view_mode], FALSE, FALSE, 0); gtk_widget_set_tooltip_text(threshold->color_table_independent[i_view_mode], _("if not enabled, the primary color table will be used for this set of views")); gtk_widget_show(threshold->color_table_independent[i_view_mode]); } threshold->color_table_menu[i_view_mode] = amitk_color_table_menu_new(); g_object_set_data(G_OBJECT(threshold->color_table_menu[i_view_mode]), "view_mode", GINT_TO_POINTER(i_view_mode)); g_signal_connect(G_OBJECT(threshold->color_table_menu[i_view_mode]), "changed", G_CALLBACK(color_table_cb), threshold); gtk_box_pack_start(GTK_BOX(threshold->color_table_hbox[i_view_mode]), threshold->color_table_menu[i_view_mode], TRUE, TRUE, 0); gtk_widget_show(threshold->color_table_menu[i_view_mode]); left_row++; } if (!threshold->minimal) { /* threshold type selection */ label = gtk_label_new(_("Threshold Type")); gtk_table_attach(GTK_TABLE(left_table), label, 0,1, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(left_table), hbox, 1,5, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); left_row++; for (i_thresholding = 0; i_thresholding < AMITK_THRESHOLDING_NUM; i_thresholding++) { threshold->type_button[i_thresholding] = gtk_radio_button_new(NULL); switch(i_thresholding) { case AMITK_THRESHOLDING_PER_SLICE: image = gtk_image_new_from_stock("amide_icon_thresholding_per_slice",GTK_ICON_SIZE_LARGE_TOOLBAR); break; case AMITK_THRESHOLDING_PER_FRAME: image = gtk_image_new_from_stock("amide_icon_thresholding_per_frame",GTK_ICON_SIZE_LARGE_TOOLBAR); break; case AMITK_THRESHOLDING_INTERPOLATE_FRAMES: image = gtk_image_new_from_stock("amide_icon_thresholding_interpolate_frames",GTK_ICON_SIZE_LARGE_TOOLBAR); break; case AMITK_THRESHOLDING_GLOBAL: image = gtk_image_new_from_stock("amide_icon_thresholding_global",GTK_ICON_SIZE_LARGE_TOOLBAR); break; default: image = NULL; g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } gtk_button_set_image(GTK_BUTTON(threshold->type_button[i_thresholding]), image); gtk_box_pack_start(GTK_BOX(hbox), threshold->type_button[i_thresholding], FALSE, FALSE, 3); gtk_widget_show(threshold->type_button[i_thresholding]); gtk_widget_set_tooltip_text(threshold->type_button[i_thresholding], thresholding_names[i_thresholding]); g_object_set_data(G_OBJECT(threshold->type_button[i_thresholding]), "thresholding", GINT_TO_POINTER(i_thresholding)); if (i_thresholding != 0) gtk_radio_button_set_group(GTK_RADIO_BUTTON(threshold->type_button[i_thresholding]), gtk_radio_button_get_group(GTK_RADIO_BUTTON(threshold->type_button[0]))); g_signal_connect(G_OBJECT(threshold->type_button[i_thresholding]), "clicked", G_CALLBACK(thresholding_cb), threshold); } } /* windowing buttons */ if (!threshold->minimal) { /* threshold type selection */ label = gtk_label_new(_("Threshold Style")); gtk_table_attach(GTK_TABLE(left_table), label, 0,1, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); hbox = gtk_hbox_new(FALSE, 0); amitk_threshold_style_widgets(threshold->style_button, hbox); gtk_table_attach(GTK_TABLE(left_table), hbox, 1,5, left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); for (i_threshold_style = 0; i_threshold_style < AMITK_THRESHOLD_STYLE_NUM; i_threshold_style++) g_signal_connect(G_OBJECT(threshold->style_button[i_threshold_style]), "clicked", G_CALLBACK(threshold_style_cb), threshold); gtk_widget_show(hbox); left_row++; threshold->window_label = gtk_label_new("Apply Window"); gtk_table_attach(GTK_TABLE(left_table), threshold->window_label, 0,1,left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_window */ threshold->window_vbox = gtk_vbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(left_table), threshold->window_vbox, 1,5,left_row,left_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_window */ for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) { x = div(i_window, 5); if (x.rem == 0) { hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(threshold->window_vbox), hbox, FALSE, FALSE, 3); gtk_widget_show(hbox); } button = gtk_button_new(); image = gtk_image_new_from_stock(windowing_icons[i_window],GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_button_set_image(GTK_BUTTON(button), image); g_object_set_data(G_OBJECT(button), "which_window",GINT_TO_POINTER(i_window)); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 3); gtk_widget_show(button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(windowing_cb), threshold); gtk_widget_set_tooltip_text(button, _(amitk_window_names[i_window])); } left_row++; } /*--------------------------------------- right table --------------------------------------- */ right_table = gtk_table_new(4,5,FALSE); right_row=0; gtk_box_pack_start(GTK_BOX(main_box), right_table, TRUE,TRUE,0); /* color table selector */ threshold->ref_frame_label[0] = gtk_label_new(_("ref. frame 0:")); gtk_table_attach(GTK_TABLE(right_table), threshold->ref_frame_label[0], 1,2, right_row,right_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ threshold->ref_frame_label[1] = gtk_label_new(_("ref. frame 1:")); gtk_table_attach(GTK_TABLE(right_table), threshold->ref_frame_label[1], 3,4, right_row,right_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ for (i_ref=0; i_ref<2; i_ref++) { threshold->threshold_ref_frame_menu[i_ref] = gtk_combo_box_new_text(); gtk_table_attach(GTK_TABLE(right_table), threshold->threshold_ref_frame_menu[i_ref], 2+i_ref*2,3+i_ref*2, right_row,right_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_set_size_request(threshold->threshold_ref_frame_menu[i_ref], 50, -1); g_object_set_data(G_OBJECT(threshold->threshold_ref_frame_menu[i_ref]), "which_ref", GINT_TO_POINTER(i_ref)); g_signal_connect(G_OBJECT(threshold->threshold_ref_frame_menu[i_ref]), "changed", G_CALLBACK(threshold_ref_frame_cb), threshold); /* show/hide taken care of by threshold_update_layout */ } /* puts these labels on bottom for a linear layout */ if (layout == AMITK_THRESHOLD_LINEAR_LAYOUT) right_row = 3; else right_row++; if (!threshold->minimal) { threshold->histogram_label = gtk_label_new(_("distribution")); gtk_table_attach(GTK_TABLE(right_table), threshold->histogram_label, 0,1, right_row, right_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ } for (i_ref=0; i_ref<2; i_ref++) { threshold->full_label[i_ref] = gtk_label_new(_("full")); gtk_table_attach(GTK_TABLE(right_table), threshold->full_label[i_ref], 1+2*i_ref,2+2*i_ref, right_row, right_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ threshold->scaled_label[i_ref] = gtk_label_new(_("scaled")); gtk_table_attach(GTK_TABLE(right_table), threshold->scaled_label[i_ref], 2+2*i_ref,3+2*i_ref, right_row, right_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* show/hide taken care of by threshold_update_layout */ } if (layout == AMITK_THRESHOLD_LINEAR_LAYOUT) right_row = 1; else right_row++; /* the histogram */ if (!threshold->minimal) { #ifdef AMIDE_LIBGNOMECANVAS_AA threshold->histogram = gnome_canvas_new_aa(); #else threshold->histogram = gnome_canvas_new(); #endif gtk_table_attach(GTK_TABLE(right_table), threshold->histogram, 0,1,right_row,right_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_set_size_request(threshold->histogram, IMAGE_DISTRIBUTION_WIDTH, AMITK_DATA_SET_DISTRIBUTION_SIZE + 2*THRESHOLD_TRIANGLE_HEIGHT); gnome_canvas_set_scroll_region(GNOME_CANVAS(threshold->histogram), 0.0, THRESHOLD_TRIANGLE_WIDTH/2.0, IMAGE_DISTRIBUTION_WIDTH, (THRESHOLD_TRIANGLE_WIDTH/2.0 + AMITK_DATA_SET_DISTRIBUTION_SIZE)); /* show/hide taken care of by threshold_update_layout */ } /* the color scale */ for (i_ref=0; i_ref<2; i_ref++) { #ifdef AMIDE_LIBGNOMECANVAS_AA threshold->color_scales[i_ref] = gnome_canvas_new_aa(); #else threshold->color_scales[i_ref] = gnome_canvas_new(); #endif gtk_table_attach(GTK_TABLE(right_table), threshold->color_scales[i_ref], 1+2*i_ref,3+2*i_ref,right_row,right_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); gnome_canvas_set_scroll_region(GNOME_CANVAS(threshold->color_scales[i_ref]), 0.0, 0.0, THRESHOLD_COLOR_SCALES_WIDTH+2* THRESHOLD_TRIANGLE_WIDTH, THRESHOLD_COLOR_SCALE_HEIGHT + 2*THRESHOLD_TRIANGLE_HEIGHT + 1); gtk_widget_set_size_request(threshold->color_scales[i_ref], THRESHOLD_COLOR_SCALES_WIDTH+2* THRESHOLD_TRIANGLE_WIDTH, THRESHOLD_COLOR_SCALE_HEIGHT + 2*THRESHOLD_TRIANGLE_HEIGHT + 1); /* show/hide taken care of by threshold_update_layout */ } right_row++; gtk_widget_show(left_table); gtk_widget_show(right_table); gtk_widget_show(main_box); return; } static void threshold_add_data_set(AmitkThreshold * threshold, AmitkDataSet * ds) { gint i; AmitkStudy * study; g_return_if_fail(threshold->data_set == NULL); threshold->data_set = amitk_object_ref(ds); /* explicitly make sure the min/max values have been calculated on the new data set, this is to make sure a progress box gets pushed up if these haven't been calculated eyt */ amitk_data_set_calc_min_max_if_needed(threshold->data_set, amitk_progress_dialog_update, threshold->progress_dialog); for (i=0; i<2; i++) { threshold->threshold_max[i] = AMITK_DATA_SET_THRESHOLD_MAX(ds, i); threshold->threshold_min[i] = AMITK_DATA_SET_THRESHOLD_MIN(ds, i); } study = AMITK_STUDY(amitk_object_get_parent_of_type(AMITK_OBJECT(ds), AMITK_OBJECT_TYPE_STUDY)); /* unreferenced pointer */ if (study != NULL) threshold->view_mode = AMITK_STUDY_VIEW_MODE(study); else threshold->view_mode = AMITK_VIEW_MODE_SINGLE; g_signal_connect(G_OBJECT(ds), "scale_factor_changed", G_CALLBACK(ds_scale_factor_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "color_table_changed", G_CALLBACK(ds_color_table_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "color_table_independent_changed", G_CALLBACK(ds_color_table_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "thresholding_changed", G_CALLBACK(ds_thresholding_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "threshold_style_changed", G_CALLBACK(ds_threshold_style_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "thresholds_changed", G_CALLBACK(ds_thresholds_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "conversion_changed", G_CALLBACK(ds_conversion_changed_cb), threshold); g_signal_connect(G_OBJECT(ds), "modality_changed", G_CALLBACK(ds_modality_changed_cb), threshold); if (study != NULL) g_signal_connect(G_OBJECT(study), "view_mode_changed", G_CALLBACK(study_view_mode_changed_cb), threshold); return; } static void threshold_remove_data_set(AmitkThreshold * threshold) { AmitkStudy * study; if (threshold->data_set == NULL) return; study = AMITK_STUDY(amitk_object_get_parent_of_type(AMITK_OBJECT(threshold->data_set), AMITK_OBJECT_TYPE_STUDY)); /* unreferenced pointer */ AMITK_OBJECT(threshold->data_set)->dialog = NULL; g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_scale_factor_changed_cb, threshold); g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_color_table_changed_cb, threshold); g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_thresholding_changed_cb, threshold); g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_threshold_style_changed_cb, threshold); g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_thresholds_changed_cb, threshold); g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_conversion_changed_cb, threshold); g_signal_handlers_disconnect_by_func(G_OBJECT(threshold->data_set), ds_modality_changed_cb, threshold); if (study != NULL) g_signal_handlers_disconnect_by_func(G_OBJECT(study), study_view_mode_changed_cb, threshold); threshold->data_set = amitk_object_unref(threshold->data_set); return; } /* return how many visible reference points we should have */ static gint threshold_visible_refs(AmitkDataSet * data_set) { if (AMITK_DATA_SET_THRESHOLDING(data_set) == AMITK_THRESHOLDING_INTERPOLATE_FRAMES) return 2; else return 1; } /* refresh what's on the histogram */ static void threshold_update_histogram(AmitkThreshold * threshold) { rgb_t fg; GtkStyle * widget_style; GdkPixbuf * pixbuf; if (threshold->minimal) return; /* no histogram in minimal configuration */ /* figure out what colors to use for the distribution image */ widget_style = gtk_widget_get_style(GTK_WIDGET(threshold)); if (widget_style == NULL) { g_warning(_("Threshold has no style?\n")); widget_style = gtk_style_new(); } fg.r = widget_style->fg[GTK_STATE_NORMAL].red >> 8; fg.g = widget_style->fg[GTK_STATE_NORMAL].green >> 8; fg.b = widget_style->fg[GTK_STATE_NORMAL].blue >> 8; pixbuf = image_of_distribution(threshold->data_set, fg, amitk_progress_dialog_update, threshold->progress_dialog); if (pixbuf != NULL) { if (threshold->histogram_image != NULL) gnome_canvas_item_set(threshold->histogram_image, "pixbuf", pixbuf, NULL); else threshold->histogram_image = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(threshold->histogram)), gnome_canvas_pixbuf_get_type(), "pixbuf", pixbuf, "x", 0.0, "y", ((gdouble) THRESHOLD_TRIANGLE_HEIGHT), NULL); g_object_unref(pixbuf); } return; } /* function to update the spin button widgets */ static void threshold_update_spin_buttons(AmitkThreshold * threshold) { guint i_ref; AmitkThresholdEntry i_entry; amide_data_t scale; amide_data_t step; amide_data_t min_val, max_val, min_percent, max_percent; if (threshold->minimal) return; /* no spin buttons in minimal configuration */ g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); scale = (amitk_data_set_get_global_max(threshold->data_set) - amitk_data_set_get_global_min(threshold->data_set)); step = scale / 100.0; if (scale < EPSILON) { scale = EPSILON; step = EPSILON; } for (i_ref=0; i_ref< threshold_visible_refs(threshold->data_set); i_ref++) { switch (AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set)) { case AMITK_THRESHOLD_STYLE_CENTER_WIDTH: max_val = (threshold->threshold_max[i_ref]+threshold->threshold_min[i_ref])/2; /* center */ min_val = (threshold->threshold_max[i_ref]-threshold->threshold_min[i_ref]); /* width */ max_percent = 100*(max_val-amitk_data_set_get_global_min(threshold->data_set))/scale; min_percent = 100*min_val/scale; break; case AMITK_THRESHOLD_STYLE_MIN_MAX: default: max_val = threshold->threshold_max[i_ref]; min_val = threshold->threshold_min[i_ref]; max_percent = 100*(max_val-amitk_data_set_get_global_min(threshold->data_set))/scale; min_percent = 100*(min_val-amitk_data_set_get_global_min(threshold->data_set))/scale; break; } for (i_entry=0; i_entry< AMITK_THRESHOLD_ENTRY_NUM_ENTRIES; i_entry++) g_signal_handlers_block_by_func(G_OBJECT(threshold->spin_button[i_ref][i_entry]), G_CALLBACK(threshold_spin_button_cb), threshold); gtk_spin_button_set_value(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_PERCENT]),max_percent); gtk_spin_button_set_increments(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE]), step, 10.0*step); gtk_spin_button_set_value(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE]),max_val); gtk_spin_button_set_value(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_PERCENT]),min_percent); gtk_spin_button_set_increments(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE]), step, 10.0*step); gtk_spin_button_set_value(GTK_SPIN_BUTTON(threshold->spin_button[i_ref][AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE]), min_val); for (i_entry=0; i_entry< AMITK_THRESHOLD_ENTRY_NUM_ENTRIES; i_entry++) g_signal_handlers_unblock_by_func(G_OBJECT(threshold->spin_button[i_ref][i_entry]), G_CALLBACK(threshold_spin_button_cb), threshold); } return; } static void threshold_update_arrow(AmitkThreshold * threshold, AmitkThresholdArrow arrow) { GnomeCanvasPoints * points; gdouble left, right, point, top, bottom; gboolean up_pointing=FALSE; gboolean down_pointing=FALSE; gchar * fill_color; guint i_ref; amide_data_t initial_diff; amide_data_t global_diff; guint i; amide_data_t center; global_diff = amitk_data_set_get_global_max(threshold->data_set)- amitk_data_set_get_global_min(threshold->data_set); if (global_diff < EPSILON) global_diff = 1.0; /* non sensicle */ for (i_ref=0; i_ref< threshold_visible_refs(threshold->data_set); i_ref++) { points = gnome_canvas_points_new(3); initial_diff = threshold->initial_max[i_ref]- threshold->initial_min[i_ref]; if (initial_diff < EPSILON) initial_diff = EPSILON; switch (arrow) { case AMITK_THRESHOLD_ARROW_FULL_MIN: left = 0; right = THRESHOLD_TRIANGLE_WIDTH; if (EQUAL_ZERO(global_diff)) point = THRESHOLD_TRIANGLE_HEIGHT+THRESHOLD_COLOR_SCALE_HEIGHT; else point = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * (1-(threshold->threshold_min[i_ref]- amitk_data_set_get_global_min(threshold->data_set))/global_diff); top = point; bottom = point+THRESHOLD_TRIANGLE_HEIGHT; if (threshold->threshold_min[i_ref] < amitk_data_set_get_global_min(threshold->data_set)) down_pointing=TRUE; fill_color = "white"; break; case AMITK_THRESHOLD_ARROW_FULL_CENTER: center = (threshold->threshold_max[i_ref]+threshold->threshold_min[i_ref])/2.0; left = 0; right = THRESHOLD_TRIANGLE_WIDTH; if (EQUAL_ZERO(global_diff)) point = THRESHOLD_TRIANGLE_HEIGHT+THRESHOLD_COLOR_SCALE_HEIGHT; else point = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * (1-(center - amitk_data_set_get_global_min(threshold->data_set))/global_diff); top = point-THRESHOLD_TRIANGLE_HEIGHT/1.5; bottom = point+THRESHOLD_TRIANGLE_HEIGHT/1.5; if (center < amitk_data_set_get_global_min(threshold->data_set)) down_pointing=TRUE; else if (center > amitk_data_set_get_global_max(threshold->data_set)) up_pointing = TRUE; fill_color = "gray"; break; case AMITK_THRESHOLD_ARROW_FULL_MAX: left = 0; right = THRESHOLD_TRIANGLE_WIDTH; if (EQUAL_ZERO(global_diff)) point = THRESHOLD_TRIANGLE_HEIGHT+THRESHOLD_COLOR_SCALE_HEIGHT; else point = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * (1-(threshold->threshold_max[i_ref]-amitk_data_set_get_global_min(threshold->data_set))/global_diff); top = point-THRESHOLD_TRIANGLE_HEIGHT; bottom = point; if (threshold->threshold_max[i_ref] > amitk_data_set_get_global_max(threshold->data_set)) up_pointing=TRUE; /* want upward pointing max arrow */ fill_color = "black"; break; case AMITK_THRESHOLD_ARROW_SCALED_MIN: left = THRESHOLD_COLOR_SCALES_WIDTH+2*THRESHOLD_TRIANGLE_WIDTH; right = THRESHOLD_COLOR_SCALES_WIDTH+THRESHOLD_TRIANGLE_WIDTH; if (EQUAL_ZERO(initial_diff)) point = THRESHOLD_TRIANGLE_HEIGHT+THRESHOLD_COLOR_SCALE_HEIGHT; else point = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * (1-(threshold->threshold_min[i_ref]-threshold->initial_min[i_ref])/initial_diff); top = point; bottom = point+THRESHOLD_TRIANGLE_HEIGHT; if (threshold->threshold_min[i_ref] < threshold->initial_min[i_ref]) down_pointing=TRUE; else if (threshold->threshold_min[i_ref] > threshold->initial_max[i_ref]) up_pointing=TRUE; fill_color = "white"; break; case AMITK_THRESHOLD_ARROW_SCALED_CENTER: center = (threshold->threshold_max[i_ref]+threshold->threshold_min[i_ref])/2.0; left = THRESHOLD_COLOR_SCALES_WIDTH+2*THRESHOLD_TRIANGLE_WIDTH; right = THRESHOLD_COLOR_SCALES_WIDTH+THRESHOLD_TRIANGLE_WIDTH; if (EQUAL_ZERO(initial_diff)) point = THRESHOLD_TRIANGLE_HEIGHT+THRESHOLD_COLOR_SCALE_HEIGHT; else point = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * (1-(center-threshold->initial_min[i_ref])/initial_diff); top = point-THRESHOLD_TRIANGLE_HEIGHT/1.5; bottom = point+THRESHOLD_TRIANGLE_HEIGHT/1.5; if (center < threshold->initial_min[i_ref]) down_pointing=TRUE; else if (center > threshold->initial_max[i_ref]) up_pointing=TRUE; fill_color = "gray"; break; case AMITK_THRESHOLD_ARROW_SCALED_MAX: left = THRESHOLD_COLOR_SCALES_WIDTH+2*THRESHOLD_TRIANGLE_WIDTH; right = THRESHOLD_COLOR_SCALES_WIDTH+THRESHOLD_TRIANGLE_WIDTH; if (EQUAL_ZERO(initial_diff)) point = THRESHOLD_TRIANGLE_HEIGHT; else point = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * (1-(threshold->threshold_max[i_ref]-threshold->initial_min[i_ref])/initial_diff); top = point-THRESHOLD_TRIANGLE_HEIGHT; bottom = point; if (threshold->threshold_max[i_ref] > threshold->initial_max[i_ref]) up_pointing=TRUE; else if (threshold->threshold_max[i_ref] < threshold->initial_min[i_ref]) down_pointing=TRUE; fill_color = "black"; break; default: return; } /* end switch (arrow) */ if (up_pointing) { points->coords[0] = left; points->coords[1] = THRESHOLD_TRIANGLE_HEIGHT; points->coords[2] = (left+right)/2.0; points->coords[3] = 0; points->coords[4] = right; points->coords[5] = THRESHOLD_TRIANGLE_HEIGHT; } else if (down_pointing) { points->coords[0] = left; points->coords[1] = THRESHOLD_COLOR_SCALE_HEIGHT + THRESHOLD_TRIANGLE_HEIGHT; points->coords[2] = (left+right)/2.0; points->coords[3] = THRESHOLD_COLOR_SCALE_HEIGHT + 2*THRESHOLD_TRIANGLE_HEIGHT; points->coords[4] = right; points->coords[5] = THRESHOLD_COLOR_SCALE_HEIGHT + THRESHOLD_TRIANGLE_HEIGHT; } else { points->coords[0] = left; points->coords[1] = bottom; points->coords[2] = left; points->coords[3] = top; points->coords[4] = right; points->coords[5] = point; } /* sanity check */ for (i=0; i < 6; i++) if (!finite(points->coords[i])) points->coords[i] = 0.0; /* destroy the center arrow if needed */ if ((AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set) == AMITK_THRESHOLD_STYLE_MIN_MAX) && ((arrow == AMITK_THRESHOLD_ARROW_FULL_CENTER) || (arrow == AMITK_THRESHOLD_ARROW_SCALED_CENTER)) ) { if (threshold->arrow[i_ref][arrow] != NULL) { gtk_object_destroy(GTK_OBJECT(threshold->arrow[i_ref][arrow])); threshold->arrow[i_ref][arrow] = NULL; } } else { /* otherwise, do all the drawing */ if (threshold->arrow[i_ref][arrow] != NULL) gnome_canvas_item_set(threshold->arrow[i_ref][arrow], "points", points, NULL); else { threshold->arrow[i_ref][arrow] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(threshold->color_scales[i_ref])), gnome_canvas_polygon_get_type(), "points", points, "fill_color", fill_color, "outline_color", "black", "width_pixels", 2, NULL); g_object_set_data(G_OBJECT(threshold->arrow[i_ref][arrow]), "type", GINT_TO_POINTER(arrow)); g_object_set_data(G_OBJECT(threshold->arrow[i_ref][arrow]), "which_ref", GINT_TO_POINTER(i_ref)); g_signal_connect(G_OBJECT(threshold->arrow[i_ref][arrow]), "event", G_CALLBACK(threshold_arrow_cb), threshold); } } gnome_canvas_points_unref(points); } return; } /* function called to update the color scales */ static void threshold_update_color_scale(AmitkThreshold * threshold, AmitkThresholdScale scale) { gdouble x,y; guint i_ref; GdkPixbuf * pixbuf; for (i_ref=0; i_ref< threshold_visible_refs(threshold->data_set); i_ref++) { switch (scale) { case AMITK_THRESHOLD_SCALE_FULL: pixbuf = image_from_colortable(AMITK_DATA_SET_COLOR_TABLE(threshold->data_set, AMITK_VIEW_MODE_SINGLE), THRESHOLD_COLOR_SCALE_WIDTH, THRESHOLD_COLOR_SCALE_HEIGHT, threshold->threshold_min[i_ref], threshold->threshold_max[i_ref], amitk_data_set_get_global_min(threshold->data_set), amitk_data_set_get_global_max(threshold->data_set), FALSE); x = THRESHOLD_TRIANGLE_WIDTH; y = THRESHOLD_TRIANGLE_HEIGHT; break; case AMITK_THRESHOLD_SCALE_SCALED: pixbuf = image_from_colortable(AMITK_DATA_SET_COLOR_TABLE(threshold->data_set, AMITK_VIEW_MODE_SINGLE), THRESHOLD_COLOR_SCALE_WIDTH, THRESHOLD_COLOR_SCALE_HEIGHT, threshold->threshold_min[i_ref], threshold->threshold_max[i_ref], threshold->initial_min[i_ref], threshold->initial_max[i_ref], FALSE); x = THRESHOLD_COLOR_SCALE_WIDTH+THRESHOLD_TRIANGLE_WIDTH+THRESHOLD_COLOR_SCALE_SEPARATION; y = THRESHOLD_TRIANGLE_HEIGHT; break; default: pixbuf = NULL; x = y = 0.0; g_return_if_reached(); break; } if (threshold->color_scale_image[i_ref][scale] != NULL) { gnome_canvas_item_set(threshold->color_scale_image[i_ref][scale], "pixbuf", pixbuf, NULL); } else { threshold->color_scale_image[i_ref][scale] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(threshold->color_scales[i_ref])), gnome_canvas_pixbuf_get_type(), "pixbuf", pixbuf, "x", x, "y", y, NULL); } g_object_unref(pixbuf); } return; } static void threshold_update_connector_lines(AmitkThreshold * threshold, AmitkThresholdScale scale) { gdouble temp; GnomeCanvasPoints * line_points; guint i_ref; amide_data_t initial_diff; amide_data_t global_diff; global_diff = amitk_data_set_get_global_max(threshold->data_set)- amitk_data_set_get_global_min(threshold->data_set); if (global_diff < EPSILON) global_diff = 1.0; /* non-sensicle */ for (i_ref=0; i_ref< threshold_visible_refs(threshold->data_set); i_ref++) { initial_diff = threshold->initial_max[i_ref]- threshold->initial_min[i_ref]; if (initial_diff < EPSILON) initial_diff = EPSILON; /* update the line that connect the max arrows of each color scale */ line_points = gnome_canvas_points_new(2); line_points->coords[0] = THRESHOLD_COLOR_SCALE_WIDTH+THRESHOLD_TRIANGLE_WIDTH; temp = (1.0-(threshold->threshold_max[i_ref]- amitk_data_set_get_global_min(threshold->data_set))/global_diff); if (temp < 0.0) temp = 0.0; line_points->coords[1] = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * temp; line_points->coords[2] = THRESHOLD_COLOR_SCALE_WIDTH+ THRESHOLD_TRIANGLE_WIDTH+THRESHOLD_COLOR_SCALE_SEPARATION; temp = (1.0-(threshold->threshold_max[i_ref]-threshold->initial_min[i_ref])/initial_diff); if ((temp < 0.0) || (scale==AMITK_THRESHOLD_SCALE_FULL) || isnan(temp)) temp = 0.0; else if (temp > 1.0) temp = 1.0; line_points->coords[3] = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * temp; if (threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_MAX] != NULL) gnome_canvas_item_set(threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_MAX], "points", line_points, NULL); else threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_MAX] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(threshold->color_scales[i_ref])), gnome_canvas_line_get_type(), "points", line_points, "fill_color", "black", "width_units", 1.0, NULL); gnome_canvas_points_unref(line_points); /* update the line that connect the min arrows of each color scale */ line_points = gnome_canvas_points_new(2); line_points->coords[0] = THRESHOLD_COLOR_SCALE_WIDTH+THRESHOLD_TRIANGLE_WIDTH; temp = (1.0-(threshold->threshold_min[i_ref]- amitk_data_set_get_global_min(threshold->data_set))/global_diff); if (temp > 1.0) temp = 1.0; line_points->coords[1] = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * temp; line_points->coords[2] = THRESHOLD_COLOR_SCALE_WIDTH+ THRESHOLD_TRIANGLE_WIDTH+THRESHOLD_COLOR_SCALE_SEPARATION; temp = (1.0-(threshold->threshold_min[i_ref]-threshold->initial_min[i_ref])/initial_diff); if ((temp > 1.0) || (scale==AMITK_THRESHOLD_SCALE_FULL) || isnan(temp)) temp = 1.0; else if (temp < 0.0) temp = 0.0; line_points->coords[3] = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * temp; if (threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_MIN] != NULL) gnome_canvas_item_set(threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_MIN], "points", line_points, NULL); else threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_MIN] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(threshold->color_scales[i_ref])), gnome_canvas_line_get_type(), "points", line_points, "fill_color", "black", "width_units", 1.0, NULL); gnome_canvas_points_unref(line_points); /* update the line that connects the center arrows of each color scale */ if (AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set) == AMITK_THRESHOLD_STYLE_CENTER_WIDTH) { line_points = gnome_canvas_points_new(2); line_points->coords[0] = THRESHOLD_COLOR_SCALE_WIDTH+THRESHOLD_TRIANGLE_WIDTH; temp = (1.0-((threshold->threshold_max[i_ref]+threshold->threshold_min[i_ref])/2.0- amitk_data_set_get_global_min(threshold->data_set))/global_diff); if (temp > 1.0) temp = 1.0; else if (temp < 0.0) temp = 0.0; line_points->coords[1] = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * temp; line_points->coords[2] = THRESHOLD_COLOR_SCALE_WIDTH+ THRESHOLD_TRIANGLE_WIDTH+THRESHOLD_COLOR_SCALE_SEPARATION; temp = (1.0-((threshold->threshold_max[i_ref]+threshold->threshold_min[i_ref])/2.0- threshold->initial_min[i_ref])/initial_diff); if ((scale == AMITK_THRESHOLD_SCALE_FULL) || isnan(temp)) temp = 0.5; else if (temp > 1.0) temp = 1.0; else if (temp < 0.0) temp = 0.0; line_points->coords[3] = THRESHOLD_TRIANGLE_HEIGHT + THRESHOLD_COLOR_SCALE_HEIGHT * temp; if (threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_CENTER] != NULL) gnome_canvas_item_set(threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_CENTER], "points", line_points, NULL); else threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_CENTER] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(threshold->color_scales[i_ref])), gnome_canvas_line_get_type(), "points", line_points, "fill_color", "black", "width_units", 1.0, NULL); gnome_canvas_points_unref(line_points); } else { /* hide if not CENTER_WIDTH style */ if (threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_CENTER] != NULL) { gtk_object_destroy(GTK_OBJECT(threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_CENTER])); threshold->connector_line[i_ref][AMITK_THRESHOLD_LINE_CENTER] = NULL; } } } return; } /* update all the color scales */ static void threshold_update_color_scales(AmitkThreshold * threshold) { guint i_ref; threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_FULL); for (i_ref=0; i_ref< threshold_visible_refs(threshold->data_set); i_ref++) { threshold->initial_min[i_ref] = threshold->threshold_min[i_ref]; threshold->initial_max[i_ref] = threshold->threshold_max[i_ref]; } threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_SCALED); threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_SCALED); return; } /* update which widgets are shown or hidden */ static void threshold_update_layout(AmitkThreshold * threshold) { guint i_ref; AmitkThresholdEntry i_entry; g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); for (i_ref=0; i_ref<2; i_ref++) { if ((i_ref==1) && (AMITK_DATA_SET_THRESHOLDING(threshold->data_set) != AMITK_THRESHOLDING_INTERPOLATE_FRAMES)) { if (!threshold->minimal) { gtk_widget_hide(threshold->percent_label[i_ref]); gtk_widget_hide(threshold->absolute_label[i_ref]); gtk_widget_hide(threshold->full_label[i_ref]); gtk_widget_hide(threshold->scaled_label[i_ref]); gtk_widget_hide(threshold->color_scales[i_ref]); for (i_entry=0; i_entry< AMITK_THRESHOLD_ENTRY_NUM_ENTRIES; i_entry++) gtk_widget_hide(threshold->spin_button[i_ref][i_entry]); } } else { gtk_widget_show(threshold->color_scales[i_ref]); if (!threshold->minimal) { gtk_widget_show(threshold->percent_label[i_ref]); gtk_widget_show(threshold->absolute_label[i_ref]); gtk_widget_show(threshold->full_label[i_ref]); gtk_widget_show(threshold->scaled_label[i_ref]); for (i_entry=0; i_entry< AMITK_THRESHOLD_ENTRY_NUM_ENTRIES; i_entry++) gtk_widget_show(threshold->spin_button[i_ref][i_entry]); } } if (!threshold->minimal) { if (AMITK_DATA_SET_THRESHOLDING(threshold->data_set) == AMITK_THRESHOLDING_GLOBAL) { gtk_widget_show(threshold->histogram_label); gtk_widget_show(threshold->histogram); } else { gtk_widget_hide(threshold->histogram_label); gtk_widget_hide(threshold->histogram); } if (AMITK_DATA_SET_THRESHOLDING(threshold->data_set) != AMITK_THRESHOLDING_INTERPOLATE_FRAMES) { gtk_widget_hide(threshold->ref_frame_label[i_ref]); gtk_widget_hide(threshold->threshold_ref_frame_menu[i_ref]); } else { gtk_widget_show(threshold->ref_frame_label[i_ref]); gtk_widget_show_all(threshold->threshold_ref_frame_menu[i_ref]); } } } return; } static void threshold_update_style(AmitkThreshold * threshold) { AmitkThresholdStyle i_style; if (threshold->minimal) return; /* no style in minimal configuration */ switch(AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set)) { case AMITK_THRESHOLD_STYLE_CENTER_WIDTH: gtk_label_set_text(GTK_LABEL(threshold->min_max_label[AMITK_LIMIT_MAX]), _("Center")); gtk_label_set_text(GTK_LABEL(threshold->min_max_label[AMITK_LIMIT_MIN]), _("Width")); break; case AMITK_THRESHOLD_STYLE_MIN_MAX: default: gtk_label_set_text(GTK_LABEL(threshold->min_max_label[AMITK_LIMIT_MAX]), _("Max Threshold")); gtk_label_set_text(GTK_LABEL(threshold->min_max_label[AMITK_LIMIT_MIN]), _("Min Threshold")); break; } for (i_style=0; i_stylestyle_button[i_style]), G_CALLBACK(threshold_style_cb), threshold); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(threshold->style_button[AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set)]), TRUE); for (i_style=0; i_stylestyle_button[i_style]), G_CALLBACK(threshold_style_cb), threshold); return; } /* set which toggle button is depressed */ static void threshold_update_type(AmitkThreshold * threshold) { AmitkThresholding i_thresholding; if (threshold->minimal) return; /* no changing of threshold type in minimal setup */ g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); for (i_thresholding=0; i_thresholding < AMITK_THRESHOLDING_NUM; i_thresholding++) g_signal_handlers_block_by_func(G_OBJECT(threshold->type_button[i_thresholding]), G_CALLBACK(thresholding_cb), threshold); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(threshold->type_button[AMITK_DATA_SET_THRESHOLDING(threshold->data_set)]), TRUE); for (i_thresholding=0; i_thresholding < AMITK_THRESHOLDING_NUM; i_thresholding++) g_signal_handlers_unblock_by_func(G_OBJECT(threshold->type_button[i_thresholding]), G_CALLBACK(thresholding_cb), threshold); gtk_widget_set_sensitive(threshold->type_button[AMITK_THRESHOLDING_PER_FRAME], (AMITK_DATA_SET_DYNAMIC(threshold->data_set))); gtk_widget_set_sensitive(threshold->type_button[AMITK_THRESHOLDING_INTERPOLATE_FRAMES], (AMITK_DATA_SET_DYNAMIC(threshold->data_set))); return; } /* set what the "absolute" label says */ static void threshold_update_absolute_label(AmitkThreshold * threshold) { guint i_ref; if (threshold->minimal) return; /* not shown in minimal setup */ g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); for (i_ref=0; i_ref<2; i_ref++) { switch (AMITK_DATA_SET_CONVERSION(threshold->data_set)) { case AMITK_CONVERSION_SUV: case AMITK_CONVERSION_PERCENT_ID_PER_CC: gtk_label_set_text(GTK_LABEL(threshold->absolute_label[i_ref]), amitk_conversion_names[AMITK_DATA_SET_CONVERSION(threshold->data_set)]); break; case AMITK_CONVERSION_STRAIGHT: default: gtk_label_set_text(GTK_LABEL(threshold->absolute_label[i_ref]), _("Absolute")); break; } } return; } /* function to update whether windowing buttons are shown */ static void threshold_update_windowing(AmitkThreshold * threshold) { if (threshold->minimal) return; /* not shown in minimal setup */ g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); if (AMITK_DATA_SET_MODALITY(threshold->data_set) == AMITK_MODALITY_CT) { gtk_widget_show(threshold->window_label); gtk_widget_show(threshold->window_vbox); } else { gtk_widget_hide(threshold->window_label); gtk_widget_hide(threshold->window_vbox); } return; } /* function to update what are in the ref frame menus */ static void threshold_update_ref_frames(AmitkThreshold * threshold) { GtkTreeModel * model; guint i_ref, i_frame; gchar * temp_string; if (threshold->minimal) return; /* not shown in minimal setup */ g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); for (i_ref=0; i_ref<2; i_ref++) { g_signal_handlers_block_by_func(G_OBJECT(threshold->threshold_ref_frame_menu[i_ref]), G_CALLBACK(threshold_ref_frame_cb), threshold); /* remove the old menu */ model = gtk_combo_box_get_model (GTK_COMBO_BOX(threshold->threshold_ref_frame_menu[i_ref])); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make new menu */ for (i_frame=0; i_framedata_set); i_frame++) { temp_string = g_strdup_printf("%d",i_frame); gtk_combo_box_append_text(GTK_COMBO_BOX(threshold->threshold_ref_frame_menu[i_ref]), temp_string); g_free(temp_string); } gtk_combo_box_set_active(GTK_COMBO_BOX(threshold->threshold_ref_frame_menu[i_ref]), AMITK_DATA_SET_THRESHOLD_REF_FRAME(threshold->data_set,i_ref)); g_signal_handlers_unblock_by_func(G_OBJECT(threshold->threshold_ref_frame_menu[i_ref]), G_CALLBACK(threshold_ref_frame_cb), threshold); } return; } static void threshold_update_color_table(AmitkThreshold * threshold, AmitkViewMode view_mode) { g_return_if_fail(AMITK_IS_DATA_SET(threshold->data_set)); g_signal_handlers_block_by_func(G_OBJECT(threshold->color_table_menu[view_mode]), G_CALLBACK(color_table_cb), threshold); gtk_combo_box_set_active(GTK_COMBO_BOX(threshold->color_table_menu[view_mode]), AMITK_DATA_SET_COLOR_TABLE(threshold->data_set, view_mode)); g_signal_handlers_unblock_by_func(G_OBJECT(threshold->color_table_menu[view_mode]), G_CALLBACK(color_table_cb), threshold); if (view_mode == AMITK_VIEW_MODE_SINGLE) { } else { g_signal_handlers_block_by_func(G_OBJECT(threshold->color_table_independent[view_mode]), G_CALLBACK(color_table_independent_cb), threshold); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(threshold->color_table_independent[view_mode]), AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(threshold->data_set, view_mode)); g_signal_handlers_unblock_by_func(G_OBJECT(threshold->color_table_independent[view_mode]), G_CALLBACK(color_table_independent_cb), threshold); gtk_widget_set_sensitive(threshold->color_table_menu[view_mode], AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(threshold->data_set, view_mode)); } return; } static void threshold_update_color_tables(AmitkThreshold * threshold) { AmitkViewMode i_view_mode; for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { if (i_view_mode <= threshold->view_mode) { gtk_widget_show(threshold->color_table_label[i_view_mode]); gtk_widget_show(threshold->color_table_hbox[i_view_mode]); } else { /* never reached for AMITK_VIEW_MODE_SINGLE */ gtk_widget_hide(threshold->color_table_label[i_view_mode]); gtk_widget_hide(threshold->color_table_hbox[i_view_mode]); } threshold_update_color_table(threshold, i_view_mode); } return; } static void ds_scale_factor_changed_cb(AmitkDataSet * ds, AmitkThreshold * threshold) { gint i; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); for (i=0; i<2; i++) { threshold->threshold_max[i] = AMITK_DATA_SET_THRESHOLD_MAX(ds, i); threshold->threshold_min[i] = AMITK_DATA_SET_THRESHOLD_MIN(ds, i); } threshold_update_spin_buttons(threshold); return; } static void ds_color_table_changed_cb(AmitkDataSet * ds, AmitkViewMode view_mode, AmitkThreshold * threshold) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); threshold_update_color_table(threshold, view_mode); threshold_update_color_scales(threshold); return; } static void ds_thresholding_changed_cb(AmitkDataSet * ds, AmitkThreshold * threshold) { AmitkThresholdArrow i_arrow; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); /* need to make sure the second reference items are made before they're shown in update_layout */ threshold_update_color_scales(threshold); for (i_arrow=0;i_arrow< AMITK_THRESHOLD_ARROW_NUM_ARROWS;i_arrow++) threshold_update_arrow(threshold, i_arrow); threshold_update_type(threshold); #if 0 threshold_update_ref_frames(threshold); #endif threshold_update_layout(threshold); return; } static void ds_threshold_style_changed_cb(AmitkDataSet * ds, AmitkThreshold * threshold) { AmitkThresholdScale i_scale; threshold_update_style(threshold); threshold_update_spin_buttons(threshold); for (i_scale=0; i_scale < AMITK_THRESHOLD_SCALE_NUM_SCALES; i_scale++) threshold_update_connector_lines(threshold, i_scale); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_CENTER); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_CENTER); return; } static void ds_thresholds_changed_cb(AmitkDataSet * ds, AmitkThreshold * threshold) { gint i; g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); for (i=0; i<2; i++) { threshold->threshold_max[i] = AMITK_DATA_SET_THRESHOLD_MAX(ds, i); threshold->threshold_min[i] = AMITK_DATA_SET_THRESHOLD_MIN(ds, i); } threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_FULL); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MIN); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_CENTER); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MAX); threshold_update_ref_frames(threshold); threshold_update_spin_buttons(threshold); return; } static void ds_conversion_changed_cb(AmitkDataSet * ds, AmitkThreshold * threshold) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); threshold_update_spin_buttons(threshold); threshold_update_absolute_label(threshold); return; } static void ds_modality_changed_cb(AmitkDataSet * ds, AmitkThreshold * threshold) { g_return_if_fail(AMITK_IS_DATA_SET(ds)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); threshold_update_windowing(threshold); return; } static void study_view_mode_changed_cb(AmitkStudy * study, AmitkThreshold * threshold) { g_return_if_fail(AMITK_IS_STUDY(study)); g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); threshold->view_mode = AMITK_STUDY_VIEW_MODE(study); threshold_update_color_tables(threshold); return; } /* function called when the max or min triangle is moved * mostly taken from Pennington's fine book */ static gint threshold_arrow_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { AmitkThreshold * threshold = data; gdouble item_x, item_y; gdouble delta; amide_data_t temp, center, width, max, min; AmitkThresholdArrow which_threshold_arrow; guint which_ref; which_ref = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_ref")); /* get the location of the event, and convert it to our coordinate system */ item_x = event->button.x; item_y = event->button.y; gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(widget)->parent, &item_x, &item_y); /* figure out which of the arrows triggered the callback */ which_threshold_arrow = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "type")); /* switch on the event which called this */ switch (event->type) { case GDK_BUTTON_PRESS: threshold->initial_y[which_ref] = item_y; threshold->initial_min[which_ref] = threshold->threshold_min[which_ref]; threshold->initial_max[which_ref] = threshold->threshold_max[which_ref]; gnome_canvas_item_grab(GNOME_CANVAS_ITEM(threshold->arrow[which_ref][which_threshold_arrow]), GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, threshold_cursor, event->button.time); break; case GDK_MOTION_NOTIFY: delta = threshold->initial_y[which_ref] - item_y; if (event->motion.state & GDK_BUTTON1_MASK) { delta /= THRESHOLD_COLOR_SCALE_HEIGHT; /* calculate how much the arrow has been moved in terms of data values */ switch(which_threshold_arrow) { case AMITK_THRESHOLD_ARROW_FULL_MAX: case AMITK_THRESHOLD_ARROW_FULL_CENTER: case AMITK_THRESHOLD_ARROW_FULL_MIN: delta *= (amitk_data_set_get_global_max(threshold->data_set) - amitk_data_set_get_global_min(threshold->data_set)); break; case AMITK_THRESHOLD_ARROW_SCALED_MAX: case AMITK_THRESHOLD_ARROW_SCALED_CENTER: case AMITK_THRESHOLD_ARROW_SCALED_MIN: delta *= (threshold->initial_max[which_ref] - threshold->initial_min[which_ref]); break; default: delta=0; /* shouldn't get here */ break; } switch (which_threshold_arrow) { case AMITK_THRESHOLD_ARROW_FULL_MAX: case AMITK_THRESHOLD_ARROW_SCALED_MAX: temp = threshold->initial_max[which_ref] + delta; if (temp < amitk_data_set_get_global_min(threshold->data_set)) temp = amitk_data_set_get_global_min(threshold->data_set); if (AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set) == AMITK_THRESHOLD_STYLE_CENTER_WIDTH) { center = (threshold->initial_max[which_ref]+threshold->initial_min[which_ref])/2.0; if ((temp-EPSILON*fabs(temp)) < center) temp = center+EPSILON*fabs(center); width = 2.0*(temp-center); threshold->threshold_max[which_ref] = center+width/2.0; threshold->threshold_min[which_ref] = center-width/2.0; threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MIN); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MAX); if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_SCALED_MAX) { threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MAX); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MIN); } } else { if ((temp-EPSILON*fabs(temp)) < threshold->threshold_min[which_ref]) temp = threshold->threshold_min[which_ref]+EPSILON*fabs(threshold->threshold_min[which_ref]); threshold->threshold_max[which_ref] = temp; threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MAX); if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_SCALED_MAX) threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MAX); } if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_FULL_MAX) threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_FULL); else { threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_SCALED); threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_SCALED); } break; case AMITK_THRESHOLD_ARROW_FULL_CENTER: case AMITK_THRESHOLD_ARROW_SCALED_CENTER: g_return_val_if_fail(AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set) == AMITK_THRESHOLD_STYLE_CENTER_WIDTH, FALSE); center = (threshold->initial_max[which_ref]+threshold->initial_min[which_ref])/2.0; width = (threshold->initial_max[which_ref]-threshold->initial_min[which_ref]); temp = center+delta; if (temp < amitk_data_set_get_global_min(threshold->data_set)) temp = amitk_data_set_get_global_min(threshold->data_set); if (temp > amitk_data_set_get_global_max(threshold->data_set)) temp = amitk_data_set_get_global_max(threshold->data_set); threshold->threshold_max[which_ref] = temp+width/2.0; threshold->threshold_min[which_ref] = temp-width/2.0; threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MIN); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_CENTER); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MAX); if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_SCALED_CENTER) { threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MIN); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_CENTER); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MAX); } if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_FULL_CENTER) threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_FULL); else { threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_SCALED); threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_SCALED); } break; case AMITK_THRESHOLD_ARROW_FULL_MIN: case AMITK_THRESHOLD_ARROW_SCALED_MIN: temp = threshold->initial_min[which_ref] + delta; if (temp > amitk_data_set_get_global_max(threshold->data_set)) temp = amitk_data_set_get_global_max(threshold->data_set); // if (temp < amitk_data_set_get_global_min(threshold->data_set)) // temp = amitk_data_set_get_global_min(threshold->data_set); if (AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set) == AMITK_THRESHOLD_STYLE_CENTER_WIDTH) { center = (threshold->initial_max[which_ref]+threshold->initial_min[which_ref])/2.0; if ((temp+EPSILON*fabs(temp)) > center) temp = center-EPSILON*fabs(center); width = 2.0*(center-temp); threshold->threshold_max[which_ref] = center+width/2.0; threshold->threshold_min[which_ref] = center-width/2.0; threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MIN); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MAX); if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_SCALED_MIN) { threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MAX); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MIN); } } else { if ((temp+EPSILON*fabs(temp)) > threshold->threshold_max[which_ref]) temp = threshold->threshold_max[which_ref]-EPSILON*fabs(threshold->threshold_max[which_ref]); threshold->threshold_min[which_ref] = temp; threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_FULL_MIN); if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_SCALED_MIN) threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MIN); } if (which_threshold_arrow == AMITK_THRESHOLD_ARROW_FULL_MIN) threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_FULL); else { threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_SCALED); threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_SCALED); } break; default: break; } threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_FULL); threshold_update_spin_buttons(threshold); /* show the current val in the spin button's */ } break; case GDK_BUTTON_RELEASE: if (AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set) == AMITK_THRESHOLD_STYLE_MIN_MAX) { switch (which_threshold_arrow) { case AMITK_THRESHOLD_ARROW_SCALED_MAX: case AMITK_THRESHOLD_ARROW_FULL_MAX: amitk_data_set_set_threshold_max(threshold->data_set, which_ref, threshold->threshold_max[which_ref]); break; case AMITK_THRESHOLD_ARROW_SCALED_MIN: case AMITK_THRESHOLD_ARROW_FULL_MIN: amitk_data_set_set_threshold_min(threshold->data_set, which_ref, threshold->threshold_min[which_ref]); break; default: g_return_val_if_reached(FALSE); break; } } else { /* AMITK_THRESHOLD_STYLE_CENTER_WIDTH */ /* need to do this, as the first set_threshold call will cause threshold->threshold_* to change due to a callback */ max = threshold->threshold_max[which_ref]; min = threshold->threshold_min[which_ref]; amitk_data_set_set_threshold_max(threshold->data_set, which_ref,max); amitk_data_set_set_threshold_min(threshold->data_set, which_ref,min); } gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(widget), event->button.time); /* reset the scaled color scale */ threshold->initial_max[which_ref] = threshold->threshold_max[which_ref]; threshold->initial_min[which_ref] = threshold->threshold_min[which_ref]; threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MAX); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_CENTER); threshold_update_arrow(threshold, AMITK_THRESHOLD_ARROW_SCALED_MIN); threshold_update_color_scale(threshold, AMITK_THRESHOLD_SCALE_SCALED); threshold_update_connector_lines(threshold, AMITK_THRESHOLD_SCALE_SCALED); break; default: break; } return FALSE; } /* function to change the color table */ static void color_table_cb(GtkWidget * widget, gpointer data) { AmitkColorTable i_color_table; AmitkThreshold * threshold = data; AmitkViewMode view_mode; i_color_table = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); view_mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "view_mode")); /* check if we actually changed values */ if (AMITK_DATA_SET_COLOR_TABLE(threshold->data_set, view_mode) != i_color_table) amitk_data_set_set_color_table(AMITK_DATA_SET(threshold->data_set), view_mode, i_color_table); return; } static void color_table_independent_cb(GtkWidget * widget, gpointer data) { AmitkThreshold * threshold = data; AmitkViewMode view_mode; gboolean state; view_mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "view_mode")); /* get the state of the button */ state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if (AMITK_DATA_SET_COLOR_TABLE_INDEPENDENT(threshold->data_set, view_mode) != state) amitk_data_set_set_color_table_independent(AMITK_DATA_SET(threshold->data_set), view_mode, state); return; } /* function to update the reference frames */ static void threshold_ref_frame_cb(GtkWidget * widget, gpointer data) { guint which_ref,frame; AmitkThreshold * threshold = data; /* figure out which menu item called me */ which_ref = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"which_ref")); frame = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); /* check if we actually changed values */ if (frame != AMITK_DATA_SET_THRESHOLD_REF_FRAME(threshold->data_set, which_ref)) { if ((which_ref==0) && (frame > AMITK_DATA_SET_THRESHOLD_REF_FRAME(threshold->data_set,1))) frame =AMITK_DATA_SET_THRESHOLD_REF_FRAME(threshold->data_set,1); else if ((which_ref==1) && (frame < AMITK_DATA_SET_THRESHOLD_REF_FRAME(threshold->data_set,0))) frame = AMITK_DATA_SET_THRESHOLD_REF_FRAME(threshold->data_set,0); /* and inact the changes */ amitk_data_set_set_threshold_ref_frame(threshold->data_set, which_ref, frame); } return; } static void threshold_spin_button_cb(GtkWidget* widget, gpointer data) { AmitkThreshold * threshold = data; amide_data_t global_diff, temp; amide_data_t center, width; amide_data_t min_val=0.0; amide_data_t max_val=0.0; gboolean max_val_changed=FALSE; gboolean min_val_changed=FALSE; AmitkThresholdEntry which_threshold_entry; guint which_ref; /* figure out which of the arrows triggered the callback */ which_threshold_entry = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "type")); which_ref = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_ref")); temp = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); global_diff = amitk_data_set_get_global_max(threshold->data_set)- amitk_data_set_get_global_min(threshold->data_set); if (global_diff < EPSILON) global_diff = EPSILON; /* non sensicle */ switch (AMITK_DATA_SET_THRESHOLD_STYLE(threshold->data_set)) { case AMITK_THRESHOLD_STYLE_CENTER_WIDTH: switch (which_threshold_entry) { /* max are the "center" entries */ case AMITK_THRESHOLD_ENTRY_MAX_PERCENT: temp = (global_diff*temp/100.0)+amitk_data_set_get_global_min(threshold->data_set); case AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE: center = temp; width = threshold->threshold_max[which_ref]-threshold->threshold_min[which_ref]; break; /* min are the "width" entries */ case AMITK_THRESHOLD_ENTRY_MIN_PERCENT: temp = (global_diff*temp/100.0); case AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE: default: center = (threshold->threshold_max[which_ref]+threshold->threshold_min[which_ref])/2.0; width = temp; break; } max_val = center+width/2.0; min_val = center-width/2.0; max_val_changed=TRUE; min_val_changed=TRUE; break; case AMITK_THRESHOLD_STYLE_MIN_MAX: default: switch (which_threshold_entry) { case AMITK_THRESHOLD_ENTRY_MAX_PERCENT: temp = (global_diff*temp/100.0)+amitk_data_set_get_global_min(threshold->data_set); case AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE: max_val = temp; max_val_changed = TRUE; break; case AMITK_THRESHOLD_ENTRY_MIN_PERCENT: temp = (global_diff * temp/100.0)+amitk_data_set_get_global_min(threshold->data_set); case AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE: default: min_val = temp; min_val_changed = TRUE; break; } } if (min_val_changed) { /* make sure it's a valid floating point */ if ((min_val < amitk_data_set_get_global_max(threshold->data_set)) && (min_val < threshold->threshold_max[which_ref])) { } amitk_data_set_set_threshold_min(threshold->data_set, which_ref, min_val); threshold->threshold_min[which_ref] = min_val; } if (max_val_changed) { if ((max_val > threshold->threshold_min[which_ref]) && (max_val > amitk_data_set_get_global_min(threshold->data_set))) { } amitk_data_set_set_threshold_max(threshold->data_set, which_ref, max_val); threshold->threshold_max[which_ref] = max_val; } /* need to manually twiddle the spin button's, rejected values of amitk_data_set_set_threshold_whatever won't elicit a signal */ threshold_update_spin_buttons(threshold); return; } static void thresholding_cb(GtkWidget * widget, gpointer data) { AmitkThreshold * threshold = data; AmitkThresholding thresholding; thresholding = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"thresholding")); /* check if we actually changed values */ if (AMITK_DATA_SET_THRESHOLDING(threshold->data_set) != thresholding) amitk_data_set_set_thresholding(threshold->data_set, thresholding); return; } static void threshold_style_cb(GtkWidget * widget, gpointer data) { AmitkThreshold * threshold = data; amitk_data_set_set_threshold_style(threshold->data_set, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "threshold_style"))); return; } static void windowing_cb(GtkWidget * widget, gpointer data) { AmitkThreshold * threshold = data; AmitkWindow window; gint i; window = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_window")); for (i=0; i<2; i++) { amitk_data_set_set_threshold_min(threshold->data_set, i, AMITK_DATA_SET_THRESHOLD_WINDOW(threshold->data_set, window, AMITK_LIMIT_MIN)); amitk_data_set_set_threshold_max(threshold->data_set, i, AMITK_DATA_SET_THRESHOLD_WINDOW(threshold->data_set, window, AMITK_LIMIT_MAX)); } } /* function to load a new data set into the widget */ void amitk_threshold_new_data_set(AmitkThreshold * threshold, AmitkDataSet * new_data_set) { AmitkThresholdArrow i_arrow; g_return_if_fail(AMITK_IS_THRESHOLD(threshold)); g_return_if_fail(AMITK_IS_DATA_SET(new_data_set)); threshold_remove_data_set(threshold); threshold_add_data_set(threshold, new_data_set); threshold_update_histogram(threshold); threshold_update_layout(threshold); threshold_update_color_tables(threshold); threshold_update_color_scales(threshold); threshold_update_spin_buttons(threshold); threshold_update_type(threshold); threshold_update_style(threshold); threshold_update_absolute_label(threshold); threshold_update_windowing(threshold); threshold_update_ref_frames(threshold); /* FULL Arrows obviously need to get redrawn. SCALED arrows are also redrawn, as they may not have yet been drawn */ for (i_arrow=0;i_arrow< AMITK_THRESHOLD_ARROW_NUM_ARROWS;i_arrow++) threshold_update_arrow(threshold, i_arrow); return; } /* data set can be NULL */ GtkWidget* amitk_threshold_new (AmitkDataSet * ds, AmitkThresholdLayout layout, GtkWindow * parent, gboolean minimal) { AmitkThreshold * threshold; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), NULL); g_return_val_if_fail(parent != NULL, NULL); threshold = g_object_new (amitk_threshold_get_type (), NULL); threshold->minimal = minimal; threshold->progress_dialog = amitk_progress_dialog_new(parent); /* gets killed with parent */ threshold_construct(threshold, layout); if (ds != NULL) amitk_threshold_new_data_set(threshold, ds); return GTK_WIDGET (threshold); } GType amitk_threshold_dialog_get_type (void) { static GType threshold_dialog_type = 0; if (!threshold_dialog_type) { GTypeInfo threshold_dialog_info = { sizeof (AmitkThresholdDialogClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) threshold_dialog_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkThresholdDialog), 0, /* # preallocs */ (GInstanceInitFunc) threshold_dialog_init, NULL /* value table */ }; threshold_dialog_type = g_type_register_static(GTK_TYPE_DIALOG, "AmitkThresholdDialog", &threshold_dialog_info, 0); } return threshold_dialog_type; } static void threshold_dialog_class_init (AmitkThresholdDialogClass *klass) { /* GtkObjectClass *gtkobject_class; */ /* gtkobject_class = (GtkObjectClass*) klass; */ threshold_dialog_parent_class = g_type_class_peek_parent(klass); } static void init_common(GtkWindow * dialog) { GdkPixbuf * pixbuf; g_return_if_fail(GTK_IS_WINDOW(dialog)); pixbuf = gtk_widget_render_icon(GTK_WIDGET(dialog), "amide_icon_thresholding", -1, 0); gtk_window_set_icon(dialog, pixbuf); g_object_unref(pixbuf); return; } static void threshold_dialog_init (AmitkThresholdDialog * dialog) { init_common(GTK_WINDOW(dialog)); gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); dialog->vbox = gtk_vbox_new (FALSE, 10); gtk_container_set_border_width (GTK_CONTAINER (dialog), 10); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), dialog->vbox); gtk_widget_show (dialog->vbox); /* make the data set title thingie */ dialog->data_set_label = gtk_label_new(NULL); gtk_box_pack_start(GTK_BOX(dialog->vbox), dialog->data_set_label, FALSE, FALSE,0); gtk_widget_show(dialog->data_set_label); return; } /* this gets called after we have a data_set */ static void threshold_dialog_construct(AmitkThresholdDialog * dialog, GtkWindow * parent, AmitkDataSet * data_set) { gchar * temp_string; dialog->threshold = amitk_threshold_new(data_set, AMITK_THRESHOLD_LINEAR_LAYOUT, parent, FALSE); gtk_box_pack_end(GTK_BOX(dialog->vbox), dialog->threshold, TRUE, TRUE, 0); gtk_widget_show(dialog->threshold); /* reset the title */ temp_string = g_strdup_printf(_("Data Set: %s\n"),AMITK_OBJECT_NAME(data_set)); gtk_label_set_text (GTK_LABEL(dialog->data_set_label), temp_string); g_free(temp_string); return; } GtkWidget* amitk_threshold_dialog_new (AmitkDataSet * data_set, GtkWindow * parent) { AmitkThresholdDialog *dialog; g_return_val_if_fail(AMITK_IS_DATA_SET(data_set), NULL); if (AMITK_OBJECT(data_set)->dialog != NULL) return NULL; dialog = g_object_new(AMITK_TYPE_THRESHOLD_DIALOG, NULL); threshold_dialog_construct(dialog, parent, data_set); gtk_window_set_title (GTK_WINDOW (dialog), _("Threshold Dialog")); gtk_window_set_transient_for(GTK_WINDOW (dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW (dialog), TRUE); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); /* allows auto shrink */ return GTK_WIDGET (dialog); } /* function to load a new data set into the widget */ void amitk_threshold_dialog_new_data_set(AmitkThresholdDialog * dialog, AmitkDataSet * new_data_set) { gchar * temp_string; g_return_if_fail(AMITK_IS_THRESHOLD_DIALOG(dialog)); g_return_if_fail(AMITK_IS_DATA_SET(new_data_set)); amitk_threshold_new_data_set(AMITK_THRESHOLD(dialog->threshold), new_data_set); /* reset the title */ temp_string = g_strdup_printf(_("Data Set: %s\n"),AMITK_OBJECT_NAME(new_data_set)); gtk_label_set_text (GTK_LABEL(dialog->data_set_label), temp_string); g_free(temp_string); return; } /* function to return a pointer to the data set that this dialog currently referes to */ AmitkDataSet * amitk_threshold_dialog_data_set(AmitkThresholdDialog * dialog) { return AMITK_THRESHOLD(dialog->threshold)->data_set; } /* -------------- thresholds_dialog ---------------- */ GType amitk_thresholds_dialog_get_type (void) { static GType thresholds_dialog_type = 0; if (!thresholds_dialog_type) { GTypeInfo thresholds_dialog_info = { sizeof (AmitkThresholdsDialogClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) thresholds_dialog_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkThresholdsDialog), 0, /* # preallocs */ (GInstanceInitFunc) thresholds_dialog_init, NULL /* value table */ }; thresholds_dialog_type = g_type_register_static(GTK_TYPE_DIALOG, "AmitkThresholdsDialog", &thresholds_dialog_info, 0); } return thresholds_dialog_type; } static void thresholds_dialog_class_init (AmitkThresholdsDialogClass *klass) { /* GtkObjectClass *gtkobject_class; */ /* gtkobject_class = (GtkObjectClass*) klass; */ thresholds_dialog_parent_class = g_type_class_peek_parent(klass); } static void thresholds_dialog_init (AmitkThresholdsDialog * dialog) { GtkWidget * main_vbox; init_common(GTK_WINDOW(dialog)); dialog->thresholds = NULL; gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); main_vbox = gtk_vbox_new (FALSE, 10); gtk_container_set_border_width (GTK_CONTAINER (dialog), 10); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), main_vbox); gtk_widget_show (main_vbox); dialog->notebook = gtk_notebook_new(); gtk_container_add (GTK_CONTAINER (main_vbox), dialog->notebook); gtk_widget_show (dialog->notebook); } /* this gets called after we have a list of data set */ static void thresholds_dialog_construct(AmitkThresholdsDialog * dialog, GtkWindow * parent, GList * data_sets) { GtkWidget * threshold; GtkWidget * label; while (data_sets != NULL) { g_return_if_fail(AMITK_IS_DATA_SET(data_sets->data)); threshold = amitk_threshold_new(data_sets->data, AMITK_THRESHOLD_LINEAR_LAYOUT, parent, FALSE); dialog->thresholds = g_list_append(dialog->thresholds, threshold); label = gtk_label_new(AMITK_OBJECT_NAME(data_sets->data)); gtk_notebook_append_page(GTK_NOTEBOOK(dialog->notebook), threshold, label); gtk_widget_show(threshold); gtk_widget_show(label); data_sets = data_sets->next; } return; } GtkWidget* amitk_thresholds_dialog_new (GList * objects, GtkWindow * parent) { AmitkThresholdsDialog *dialog; GList * data_sets; g_return_val_if_fail(objects != NULL, NULL); /* check that the list contains at leat 1 data set */ data_sets = amitk_objects_get_of_type(objects, AMITK_OBJECT_TYPE_DATA_SET, FALSE); g_return_val_if_fail(data_sets != NULL, NULL); dialog = g_object_new(AMITK_TYPE_THRESHOLDS_DIALOG, NULL); thresholds_dialog_construct(dialog, parent, data_sets); gtk_window_set_title (GTK_WINDOW (dialog), _("Threshold Dialog")); gtk_window_set_transient_for(GTK_WINDOW (dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW (dialog), TRUE); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); /* allows auto shrink */ amitk_objects_unref(data_sets); return GTK_WIDGET (dialog); } amide-1.0.6/amide-current/src/amitk_threshold.h000066400000000000000000000157761423227705100215000ustar00rootroot00000000000000/* amitk_threshold.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapated from gtkcolorsel.h */ #ifndef __AMITK_THRESHOLD_H__ #define __AMITK_THRESHOLD_H__ /* includes we always need with this widget */ #include #include #include "amitk_data_set.h" #include "amitk_study.h" G_BEGIN_DECLS /* ------------- Threshold---------- */ #define AMITK_TYPE_THRESHOLD (amitk_threshold_get_type ()) #define AMITK_THRESHOLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_THRESHOLD, AmitkThreshold)) #define AMITK_THRESHOLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLD, AmitkThresholdClass)) #define AMITK_IS_THRESHOLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_THRESHOLD)) #define AMITK_IS_THRESHOLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_THRESHOLD)) typedef struct _AmitkThreshold AmitkThreshold; typedef struct _AmitkThresholdClass AmitkThresholdClass; typedef enum { AMITK_THRESHOLD_SCALE_FULL, AMITK_THRESHOLD_SCALE_SCALED, AMITK_THRESHOLD_SCALE_NUM_SCALES } AmitkThresholdScale; typedef enum { AMITK_THRESHOLD_ARROW_FULL_MIN, AMITK_THRESHOLD_ARROW_FULL_CENTER, AMITK_THRESHOLD_ARROW_FULL_MAX, AMITK_THRESHOLD_ARROW_SCALED_MIN, AMITK_THRESHOLD_ARROW_SCALED_CENTER, AMITK_THRESHOLD_ARROW_SCALED_MAX, AMITK_THRESHOLD_ARROW_NUM_ARROWS } AmitkThresholdArrow; typedef enum { AMITK_THRESHOLD_ENTRY_MAX_ABSOLUTE, AMITK_THRESHOLD_ENTRY_MAX_PERCENT, AMITK_THRESHOLD_ENTRY_MIN_ABSOLUTE, AMITK_THRESHOLD_ENTRY_MIN_PERCENT, AMITK_THRESHOLD_ENTRY_NUM_ENTRIES } AmitkThresholdEntry; typedef enum { AMITK_THRESHOLD_LINE_MAX, AMITK_THRESHOLD_LINE_CENTER, AMITK_THRESHOLD_LINE_MIN, AMITK_THRESHOLD_LINE_NUM_LINES } AmitkThresholdLine; typedef enum { AMITK_THRESHOLD_BOX_LAYOUT, AMITK_THRESHOLD_LINEAR_LAYOUT } AmitkThresholdLayout; struct _AmitkThreshold { GtkVBox vbox; gboolean minimal; /* true if we just want the color table menu and the color scale */ AmitkViewMode view_mode; GtkWidget * color_scales[2]; GtkWidget * histogram; GtkWidget * histogram_label; GnomeCanvasItem * color_scale_image[2][AMITK_THRESHOLD_SCALE_NUM_SCALES]; GnomeCanvasItem * histogram_image; GnomeCanvasItem * arrow[2][AMITK_THRESHOLD_ARROW_NUM_ARROWS]; GnomeCanvasItem * connector_line[2][AMITK_THRESHOLD_LINE_NUM_LINES]; GtkWidget * spin_button[2][AMITK_THRESHOLD_ENTRY_NUM_ENTRIES]; GtkWidget * color_table_label[AMITK_VIEW_MODE_NUM]; GtkWidget * color_table_hbox[AMITK_VIEW_MODE_NUM]; GtkWidget * color_table_menu[AMITK_VIEW_MODE_NUM]; GtkWidget * color_table_independent[AMITK_VIEW_MODE_NUM]; GtkWidget * threshold_ref_frame_menu[2]; GtkWidget * percent_label[2]; GtkWidget * absolute_label[2]; GtkWidget * ref_frame_label[2]; GtkWidget * full_label[2]; GtkWidget * scaled_label[2]; GtkWidget * type_button[AMITK_THRESHOLDING_NUM]; GtkWidget * window_label; GtkWidget * window_vbox; GtkWidget * style_button[AMITK_THRESHOLD_STYLE_NUM]; GtkWidget * min_max_label[AMITK_LIMIT_NUM]; gdouble initial_y[2]; amide_data_t initial_min[2]; amide_data_t initial_max[2]; amide_data_t threshold_max[2]; amide_data_t threshold_min[2]; GtkWidget * progress_dialog; AmitkDataSet * data_set; /* what data set this threshold corresponds to */ }; struct _AmitkThresholdClass { GtkVBoxClass parent_class; }; GType amitk_threshold_get_type (void); GtkWidget* amitk_threshold_new (AmitkDataSet * data_set, AmitkThresholdLayout layout, GtkWindow * parent, gboolean minimal); void amitk_threshold_new_data_set (AmitkThreshold * threshold, AmitkDataSet * new_data_set); void amitk_threshold_style_widgets (GtkWidget ** radio_buttons, GtkWidget * hbox); /* ---------- ThresholdDialog------------- */ #define AMITK_TYPE_THRESHOLD_DIALOG (amitk_threshold_dialog_get_type ()) #define AMITK_THRESHOLD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_THRESHOLD_DIALOG, AmitkThresholdDialog)) #define AMITK_THRESHOLD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLD_DIALOG, AmitkThresholdDialogClass)) #define AMITK_IS_THRESHOLD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_THRESHOLD_DIALOG)) #define AMITK_IS_THRESHOLD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_THRESHOLD_DIALOG)) typedef struct _AmitkThresholdDialog AmitkThresholdDialog; typedef struct _AmitkThresholdDialogClass AmitkThresholdDialogClass; struct _AmitkThresholdDialog { GtkDialog dialog; GtkWidget *data_set_label; GtkWidget *vbox; GtkWidget *threshold; }; struct _AmitkThresholdDialogClass { GtkDialogClass parent_class; }; GType amitk_threshold_dialog_get_type (void); GtkWidget* amitk_threshold_dialog_new (AmitkDataSet * data_set, GtkWindow * parent); void amitk_threshold_dialog_new_data_set (AmitkThresholdDialog * threshold_dialog, AmitkDataSet * new_data_set); AmitkDataSet * amitk_threshold_dialog_data_set (AmitkThresholdDialog * threshold_dialog); /*---------- ThresholdDialogs--------------- */ #define AMITK_TYPE_THRESHOLDS_DIALOG (amitk_thresholds_dialog_get_type ()) #define AMITK_THRESHOLDS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_THRESHOLDS_DIALOG, AmitkThresholdsDialog)) #define AMITK_THRESHOLDS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLDS_DIALOG, AmitkThresholdsDialogClass)) #define AMITK_IS_THRESHOLDS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_THRESHOLDS_DIALOG)) #define AMITK_IS_THRESHOLDS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_THRESHOLDS_DIALOG)) typedef struct _AmitkThresholdsDialog AmitkThresholdsDialog; typedef struct _AmitkThresholdsDialogClass AmitkThresholdsDialogClass; struct _AmitkThresholdsDialog { GtkDialog dialog; GtkWidget *notebook; GList * thresholds; }; struct _AmitkThresholdsDialogClass { GtkDialogClass parent_class; }; GType amitk_thresholds_dialog_get_type (void); GtkWidget* amitk_thresholds_dialog_new (GList * objects, GtkWindow * parent); G_END_DECLS #endif /* __AMITK_THRESHOLD_H__ */ amide-1.0.6/amide-current/src/amitk_tree_view.c000066400000000000000000001446131423227705100214610ustar00rootroot00000000000000/* amitk_tree_view.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* adapted from gtkcolorsel.c */ #include "amide_config.h" #include "amitk_tree_view.h" #include "amitk_study.h" #include "amitk_marshal.h" #include "amitk_progress_dialog.h" #include "image.h" #include #include #define AMITK_TREE_VIEW_DND_OBJECT_TYPE "pointer/object" #define AMITK_DND_URI_LIST_TYPE "text/uri-list" enum { AMITK_TREE_VIEW_DND_OBJECT, AMITK_DND_URI_LIST, }; #if WORKING_ON_IT static const GtkTargetEntry drag_types[] = { { AMITK_TREE_VIEW_DND_OBJECT_TYPE, 0, AMITK_TREE_VIEW_DND_OBJECT } }; static const GtkTargetEntry drop_types[] = { { AMITK_TREE_VIEW_DND_OBJECT_TYPE, 0, AMITK_TREE_VIEW_DND_OBJECT }, { AMITK_DND_URI_LIST_TYPE, 0, AMITK_DND_URI_LIST } }; #endif enum { HELP_EVENT, ACTIVATE_OBJECT, POPUP_OBJECT, ADD_OBJECT, DELETE_OBJECT, LAST_SIGNAL } amitk_tree_view_signals; /* notes MULTIPLE_SELECTION - is only used in AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION VISIBLE_SINGLE/VISIBLE_LINKED_2WAY/VISIBLE_LINKED_3WAY - are used in AMITK_TREE_VIEW_MODE_MAIN, and directly correlate with the related AmitkObject parameters */ enum { COLUMN_MULTIPLE_SELECTION, COLUMN_VISIBLE_SINGLE, COLUMN_VISIBLE_LINKED_2WAY, COLUMN_VISIBLE_LINKED_3WAY, COLUMN_EXPANDER, COLUMN_ICON, COLUMN_NAME, COLUMN_OBJECT, NUM_COLUMNS }; typedef struct { AmitkObject * object; GtkTreeIter iter; gboolean found; } tree_view_find_t; static void tree_view_class_init (AmitkTreeViewClass *klass); static void tree_view_init (AmitkTreeView *tree_view); static void tree_view_destroy (GtkObject *object); static void tree_view_set_view_mode(AmitkTreeView * tree_view, AmitkViewMode view_mode); static void tree_view_add_roi_cb(GtkWidget * widget, gpointer data); static void tree_view_popup_roi_menu(AmitkTreeView * tree_view, AmitkObject * parent_object, guint button, guint32 activate_time); static gboolean tree_view_button_press_event(GtkWidget *tree_view,GdkEventButton *event); static gboolean tree_view_button_release_event(GtkWidget *tree_view, GdkEventButton *event); static gboolean tree_view_key_press_event(GtkWidget * tree_view, GdkEventKey * event); static void tree_view_emit_help_signal(AmitkTreeView * tree_view); static gboolean tree_view_motion_notify_event(GtkWidget *widget, GdkEventMotion *event); static gboolean tree_view_enter_notify_event(GtkWidget * tree_view, GdkEventCrossing *event); static GdkPixbuf * tree_view_get_object_pixbuf(AmitkTreeView * tree_view, AmitkObject * object); //static void tree_view_drop_cb(GtkWidget * menu, gpointer context); #if WORKING_ON_IT /* source drag-n-drop */ static void tree_view_drag_begin (GtkWidget *widget, GdkDragContext *context); static void tree_view_drag_end (GtkWidget *widget, GdkDragContext *context); static void tree_view_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time); static void tree_view_drag_data_delete (GtkWidget *widget, GdkDragContext *context); /* target drag-n-drop */ static void tree_view_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time); static gboolean tree_view_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time); static gboolean tree_view_drag_drop (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time); static void tree_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time); #endif static void tree_view_object_update_cb(AmitkObject * object, gpointer tree_view); static void tree_view_data_set_color_table_cb(AmitkDataSet * data_set, AmitkViewMode view_mode, gpointer tree_view); static void tree_view_object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer tree_view); static void tree_view_object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer tree_view); static gboolean tree_view_find_recurse(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); static gboolean tree_view_find_object(AmitkTreeView * tree_view, AmitkObject * object, GtkTreeIter * iter); static void tree_view_add_object(AmitkTreeView * tree_view, AmitkObject * object); static void tree_view_remove_object(AmitkTreeView * tree_view, AmitkObject * object); static GtkTreeViewClass *parent_class; static guint tree_view_signals[LAST_SIGNAL]; GType amitk_tree_view_get_type (void) { static GType tree_view_type = 0; if (!tree_view_type) { static const GTypeInfo tree_view_info = { sizeof (AmitkTreeViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) tree_view_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkTreeView), 0, /* # preallocs */ (GInstanceInitFunc) tree_view_init, NULL /* value table */ }; tree_view_type = g_type_register_static(GTK_TYPE_TREE_VIEW, "AmitkTreeView", &tree_view_info, 0); } return tree_view_type; } static void tree_view_class_init (AmitkTreeViewClass *klass) { GtkObjectClass *gtkobject_class; /* GtkTreeViewClass *tree_view_class; */ GtkWidgetClass *widget_class; gtkobject_class = (GtkObjectClass*) klass; widget_class = (GtkWidgetClass*) klass; /* tree_view_class = (GtkTreeViewClass*) klass; */ parent_class = g_type_class_peek_parent(klass); gtkobject_class->destroy = tree_view_destroy; widget_class->button_press_event = tree_view_button_press_event; widget_class->button_release_event = tree_view_button_release_event; widget_class->key_press_event = tree_view_key_press_event; widget_class->motion_notify_event = tree_view_motion_notify_event; widget_class->enter_notify_event = tree_view_enter_notify_event; #if WORKING_ON_IT widget_class->drag_begin = tree_view_drag_begin; widget_class->drag_end = tree_view_drag_end; widget_class->drag_data_get = tree_view_drag_data_get; widget_class->drag_data_delete = tree_view_drag_data_delete; widget_class->drag_leave = tree_view_drag_leave; widget_class->drag_motion = tree_view_drag_motion; widget_class->drag_drop = tree_view_drag_drop; widget_class->drag_data_received = tree_view_drag_data_received; #endif tree_view_signals[HELP_EVENT] = g_signal_new ("help_event", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkTreeViewClass, help_event), NULL, NULL, amitk_marshal_VOID__ENUM, G_TYPE_NONE, 1, AMITK_TYPE_HELP_INFO); tree_view_signals[ACTIVATE_OBJECT] = g_signal_new ("activate_object", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkTreeViewClass, activate_object), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, AMITK_TYPE_OBJECT); tree_view_signals[POPUP_OBJECT] = g_signal_new ("popup_object", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkTreeViewClass, popup_object), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, AMITK_TYPE_OBJECT); tree_view_signals[ADD_OBJECT] = g_signal_new ("add_object", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkTreeViewClass, add_object), NULL, NULL, amitk_marshal_VOID__OBJECT_ENUM_ENUM, G_TYPE_NONE,3, AMITK_TYPE_OBJECT, AMITK_TYPE_OBJECT_TYPE, AMITK_TYPE_ROI_TYPE); tree_view_signals[DELETE_OBJECT] = g_signal_new ("delete_object", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AmitkTreeViewClass, delete_object), NULL, NULL, amitk_marshal_VOID__OBJECT, G_TYPE_NONE,1, AMITK_TYPE_OBJECT); } static void tree_view_init (AmitkTreeView * tree_view) { tree_view->study = NULL; tree_view->active_object = NULL; tree_view->mouse_x = -1; tree_view->mouse_y = -1; tree_view->current_path = NULL; tree_view->prev_view_mode = AMITK_VIEW_MODE_SINGLE; tree_view->press_x = -1; tree_view->press_y = -1; tree_view->drag_begin_possible = FALSE; tree_view->src_object = NULL; tree_view->dest_object = NULL; // tree_view->drag_list = gtk_target_list_new(drag_types, G_N_ELEMENTS(drag_types)); /* setup ability to do drag-n-drop */ // gtk_drag_dest_set (GTK_WIDGET (tree_view), // GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT, // drag_types, G_N_ELEMENTS(drag_types), // GDK_ACTION_ASK); #if WORKING_ON_IT gtk_drag_source_set (GTK_WIDGET(tree_view), GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, drag_types, G_N_ELEMENTS (drag_types), GDK_ACTION_COPY); gtk_drag_dest_set (GTK_WIDGET(tree_view), GTK_DEST_DEFAULT_ALL, drop_types, G_N_ELEMENTS (drop_types), GDK_ACTION_COPY); #endif } static void tree_view_destroy (GtkObject * object) { AmitkTreeView * tree_view; g_return_if_fail (object != NULL); g_return_if_fail (AMITK_IS_TREE_VIEW (object)); tree_view = AMITK_TREE_VIEW (object); if (tree_view->current_path != NULL) { gtk_tree_path_free(tree_view->current_path); tree_view->current_path = NULL; } if (tree_view->active_object != NULL) { tree_view->active_object = amitk_object_unref(tree_view->active_object); } if (tree_view->study != NULL) { tree_view_remove_object(tree_view, AMITK_OBJECT(tree_view->study)); tree_view->study = NULL; } if (tree_view->preferences != NULL) { g_object_unref(tree_view->preferences); tree_view->preferences = NULL; } if (tree_view->progress_dialog != NULL) { g_object_unref(tree_view->progress_dialog); tree_view->progress_dialog = NULL; } if (tree_view->drag_list != NULL) { gtk_target_list_unref (tree_view->drag_list); tree_view->drag_list = NULL; } if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } /* function only for AMITK_TREE_VIEW_MODE_MAIN */ static void tree_view_set_view_mode(AmitkTreeView * tree_view, AmitkViewMode view_mode) { AmitkViewMode i_view_mode; if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; /* remove all linked columns, we'll add them back below if needed */ for (i_view_mode = 0; i_view_mode <= tree_view->prev_view_mode; i_view_mode++) { g_object_ref(tree_view->select_column[i_view_mode]); /* view_remove_column removes a reference */ gtk_tree_view_remove_column (GTK_TREE_VIEW (tree_view), tree_view->select_column[i_view_mode]); } tree_view->prev_view_mode = view_mode; /* insert_column doesn't add a reference */ for (i_view_mode = 0; i_view_mode <= view_mode; i_view_mode++) gtk_tree_view_insert_column (GTK_TREE_VIEW (tree_view), tree_view->select_column[i_view_mode], COLUMN_VISIBLE_SINGLE+i_view_mode); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), view_mode != AMITK_VIEW_MODE_SINGLE); return; } /* callback function for adding an roi */ static void tree_view_add_roi_cb(GtkWidget * widget, gpointer data) { AmitkTreeView * tree_view = data; AmitkRoiType roi_type; AmitkObject * parent_object; /* figure out which menu item called me */ roi_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"roi_type")); parent_object = g_object_get_data(G_OBJECT(widget), "parent"); g_signal_emit(G_OBJECT(tree_view), tree_view_signals[ADD_OBJECT], 0, parent_object, AMITK_OBJECT_TYPE_ROI, roi_type); return; } static void tree_view_popup_roi_menu(AmitkTreeView * tree_view, AmitkObject * parent_object, guint button, guint32 activate_time) { GtkWidget * menu; GtkWidget * menuitem; AmitkRoiType i_roi_type; menu = gtk_menu_new(); for (i_roi_type=0; i_roi_typex, event->y, &(tree_view->current_path), &column, &cell_x, &cell_y); switch(AMITK_TREE_VIEW(tree_view)->mode) { case AMITK_TREE_VIEW_MODE_MAIN: if (event->button == 1) { tree_view->drag_begin_possible = TRUE; tree_view->press_x = event->x; tree_view->press_y = event->y; } /* making the selection mode none reduces some of the flickering caused by us manually trying to force which row is selected */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); break; default: break; } /* run the tree widget's button press event first */ return_value = GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event); switch(AMITK_TREE_VIEW(tree_view)->mode) { case AMITK_TREE_VIEW_MODE_MAIN: /* reset what's the active mark */ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); amitk_tree_view_set_active_object(tree_view, tree_view->active_object); if ((event->button == 3) && !valid_row) tree_view_popup_roi_menu(tree_view, NULL, event->button, event->time); break; default: break; } return return_value; } static gint path_compare(GtkTreePath * path1, GtkTreePath * path2) { if ((path1 == NULL) && (path2 == NULL)) return 0; else if ((path1 == NULL) || (path2 == NULL)) return 1; else return gtk_tree_path_compare(path1, path2); } static gboolean tree_view_button_release_event (GtkWidget *widget, GdkEventButton *event) { GtkTreePath * path=NULL; gint cell_x, cell_y; GtkTreeViewColumn * column; AmitkTreeView * tree_view; g_return_val_if_fail (AMITK_IS_TREE_VIEW (widget), FALSE); tree_view = AMITK_TREE_VIEW(widget); g_return_val_if_fail (event != NULL, FALSE); // g_print("release button\n"); tree_view->drag_begin_possible = FALSE; // gtk_drag_finish (tree_view->drag_context, // gboolean success, // gboolean del, // guint32 time) // gtk_grab_remove (widget); /* figure out if this click was on an item in the tree */ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree_view), event->x, event->y, &path, &column, &cell_x, &cell_y)) { /* make sure this isn't the expand button, and we're trying to expand, also check that we're doing a button release on the object we started the button press with */ if (column != gtk_tree_view_get_expander_column(GTK_TREE_VIEW(tree_view)) && path_compare(path, tree_view->current_path)==0) { GtkTreeModel * model; GtkTreeIter iter; gboolean select = FALSE; gboolean unselect = FALSE; gboolean make_active = FALSE; gboolean popup = FALSE; gboolean add_object = FALSE; gboolean multiple_selection; gboolean visible[AMITK_VIEW_MODE_NUM]; gboolean visible_at_all; AmitkObjectType add_type = -1; AmitkObject * object=NULL; AmitkViewMode view_mode; AmitkViewMode i_view_mode; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_model_get(model, &iter, COLUMN_OBJECT, &object, COLUMN_MULTIPLE_SELECTION, &multiple_selection, COLUMN_VISIBLE_SINGLE, &(visible[AMITK_VIEW_MODE_SINGLE]), COLUMN_VISIBLE_LINKED_2WAY, &(visible[AMITK_VIEW_MODE_LINKED_2WAY]), COLUMN_VISIBLE_LINKED_3WAY, &(visible[AMITK_VIEW_MODE_LINKED_3WAY]), -1); view_mode = AMITK_VIEW_MODE_SINGLE;/* default */ visible_at_all = visible[AMITK_VIEW_MODE_SINGLE]; for (i_view_mode = AMITK_VIEW_MODE_NUM-1; i_view_mode > 0; i_view_mode--) { visible_at_all = visible_at_all || visible[i_view_mode]; if (column == tree_view->select_column[i_view_mode]) { view_mode = i_view_mode; } } switch(tree_view->mode) { case AMITK_TREE_VIEW_MODE_MAIN: switch (event->button) { case 1: /* left button */ if (!AMITK_IS_STUDY(object)) { if (visible[view_mode]) unselect = TRUE; else select = TRUE; } break; case 2: /* middle button */ make_active = TRUE; if ((!visible_at_all) && (!AMITK_IS_STUDY(object))) select = TRUE; break; case 3: /* right button */ if (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { if (object != NULL) { if (AMITK_IS_DATA_SET(object)) { add_object=TRUE; if (event->state & GDK_SHIFT_MASK) add_type=AMITK_OBJECT_TYPE_ROI; else add_type=AMITK_OBJECT_TYPE_FIDUCIAL_MARK; } else if (AMITK_IS_STUDY(object)) { add_object=TRUE; add_type=AMITK_OBJECT_TYPE_ROI; } } } else { popup = TRUE; } break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } if (select) amitk_object_select(object, view_mode); else if (unselect) amitk_object_unselect(object, view_mode); if (make_active) g_signal_emit(G_OBJECT(tree_view), tree_view_signals[ACTIVATE_OBJECT], 0,object); if (popup) g_signal_emit(G_OBJECT(tree_view), tree_view_signals[POPUP_OBJECT], 0, object); if ((add_object) && (add_type==AMITK_OBJECT_TYPE_FIDUCIAL_MARK)) g_signal_emit(G_OBJECT(tree_view), tree_view_signals[ADD_OBJECT], 0, object, add_type, 0); if ((add_object) && (add_type==AMITK_OBJECT_TYPE_ROI)) tree_view_popup_roi_menu(tree_view, object, event->button, event->time); break; case AMITK_TREE_VIEW_MODE_SINGLE_SELECTION: switch (event->button) { case 1: /* left button */ g_signal_emit(G_OBJECT(tree_view), tree_view_signals[ACTIVATE_OBJECT],0,object); break; } break; case AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION: switch (event->button) { case 1: /* left button */ if (multiple_selection) gtk_tree_store_set(GTK_TREE_STORE(model), &iter, COLUMN_MULTIPLE_SELECTION, FALSE, -1); else if (!AMITK_IS_STUDY(object)) gtk_tree_store_set(GTK_TREE_STORE(model), &iter, COLUMN_MULTIPLE_SELECTION, TRUE, -1); break; default: break; } break; default: break; } } gtk_tree_path_free(path); } if (tree_view->current_path != NULL) { gtk_tree_path_free(tree_view->current_path); tree_view->current_path = NULL; } return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event); } static gboolean tree_view_key_press_event(GtkWidget * widget, GdkEventKey * event) { GtkTreePath * path; gint cell_x, cell_y; GtkTreeModel * model; GtkTreeIter iter; AmitkObject * object; AmitkTreeView * tree_view; g_return_val_if_fail(AMITK_IS_TREE_VIEW(widget), FALSE); tree_view = AMITK_TREE_VIEW(widget); switch (tree_view->mode) { case AMITK_TREE_VIEW_MODE_MAIN: if (event->state & GDK_CONTROL_MASK) if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree_view), tree_view->mouse_x, tree_view->mouse_y, &path, NULL, &cell_x, &cell_y)) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(model, &iter, COLUMN_OBJECT, &object, -1); if ((event->keyval == GDK_x) || (event->keyval == GDK_X)) if (!AMITK_IS_STUDY(object)) g_signal_emit(G_OBJECT(tree_view), tree_view_signals[DELETE_OBJECT], 0, object); } break; default: break; } return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event); } static void tree_view_emit_help_signal(AmitkTreeView * tree_view) { GtkTreePath * path=NULL; gint cell_x, cell_y; AmitkHelpInfo help_type; GtkTreeModel * model; GtkTreeIter iter; AmitkObject * object; if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree_view), tree_view->mouse_x, tree_view->mouse_y, &path, NULL, &cell_x, &cell_y)) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(model, &iter, COLUMN_OBJECT, &object, -1); if (AMITK_IS_STUDY(object)) help_type = AMITK_HELP_INFO_TREE_VIEW_STUDY; else if (AMITK_IS_DATA_SET(object)) help_type = AMITK_HELP_INFO_TREE_VIEW_DATA_SET; else if (AMITK_IS_ROI(object)) help_type = AMITK_HELP_INFO_TREE_VIEW_ROI; else if (AMITK_IS_FIDUCIAL_MARK(object)) help_type = AMITK_HELP_INFO_TREE_VIEW_FIDUCIAL_MARK; else { g_error("unknown object type in %s at %d\n", __FILE__, __LINE__); help_type = AMITK_HELP_INFO_TREE_VIEW_NONE; } } else { help_type = AMITK_HELP_INFO_TREE_VIEW_NONE; } g_signal_emit(G_OBJECT(tree_view), tree_view_signals[HELP_EVENT], 0,help_type); return; } /* we have to track motion notify for several reasons: 1. know which entry we're on for button_press events 2. context sensitive help 3. are we initiating a drag? */ static gboolean tree_view_motion_notify_event(GtkWidget *widget, GdkEventMotion *event) { AmitkTreeView * tree_view; g_return_val_if_fail(AMITK_IS_TREE_VIEW(widget), FALSE); tree_view = AMITK_TREE_VIEW(widget); tree_view->mouse_x = event->x; tree_view->mouse_y = event->y; switch(tree_view->mode) { case AMITK_TREE_VIEW_MODE_MAIN: tree_view_emit_help_signal(tree_view); break; default: break; } /* pass the signal on */ return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event); } static gboolean tree_view_enter_notify_event(GtkWidget * widget, GdkEventCrossing *event) { GtkTreeSelection *selection; GtkTreeIter iter; AmitkTreeView * tree_view; g_return_val_if_fail(AMITK_IS_TREE_VIEW(widget), FALSE); tree_view = AMITK_TREE_VIEW(widget); switch(tree_view->mode) { case AMITK_TREE_VIEW_MODE_MAIN: tree_view_emit_help_signal(tree_view); gtk_widget_grab_focus(widget); /* move the keyboard entry focus into the tree */ /* double check that the right row is selected - gtk sometimes moves the selection to the 1st row */ if (tree_view->active_object != NULL) { if (tree_view_find_object(tree_view, tree_view->active_object, &iter)) { selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); if (!gtk_tree_selection_iter_is_selected(selection, &iter)) gtk_tree_selection_select_iter(selection, &iter); } } break; default: break; } /* pass the signal on */ return (* GTK_WIDGET_CLASS (parent_class)->enter_notify_event) (widget, event); } /* note, the contents of GdkPixbuf are shared, and should not be modified */ static GdkPixbuf * tree_view_get_object_pixbuf(AmitkTreeView * tree_view, AmitkObject * object) { GdkPixbuf * pixbuf=NULL; if (AMITK_IS_ROI(object)) { switch (AMITK_ROI_TYPE(object)) { case AMITK_ROI_TYPE_ELLIPSOID: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_ellipsoid", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; case AMITK_ROI_TYPE_CYLINDER: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_cylinder", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; case AMITK_ROI_TYPE_BOX: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_box", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; case AMITK_ROI_TYPE_ISOCONTOUR_2D: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_isocontour_2d", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; case AMITK_ROI_TYPE_ISOCONTOUR_3D: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_isocontour_3d", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; case AMITK_ROI_TYPE_FREEHAND_2D: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_freehand_2d", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; case AMITK_ROI_TYPE_FREEHAND_3D: pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_roi_freehand_3d", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); break; default: g_error("Unknown case in %s at %d\n", __FILE__, __LINE__); break; } } else if (AMITK_IS_DATA_SET(object)) { pixbuf = image_get_data_set_pixbuf(AMITK_DATA_SET(object)); } else if (AMITK_IS_STUDY(object)) { pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_study", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); } else if (AMITK_IS_FIDUCIAL_MARK(object)) { pixbuf = gtk_widget_render_icon(GTK_WIDGET(tree_view), "amide_icon_align_pt", GTK_ICON_SIZE_LARGE_TOOLBAR, 0); } else { g_error("Unknown case in %s at %d\n", __FILE__, __LINE__); } return pixbuf; } //static void tree_view_drop_cb(GtkWidget * menu, gpointer data) { // GdkDragContext * context =data; // AmitkTreeView * tree_view; // gboolean move; // move = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu), "move")); // tree_view = g_object_get_data(G_OBJECT(menu), "tree_view"); // return; //} #if WORKING_ON_IT static void tree_view_drag_begin (GtkWidget *widget, GdkDragContext *context) { GtkTreePath * path=NULL; GtkTreeIter iter; // GdkPixbuf * pixbuf; AmitkObject * object; gint cell_x, cell_y; GtkTreeModel * model; AmitkTreeView * tree_view; g_return_if_fail(AMITK_IS_TREE_VIEW(widget)); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("drag begin from %s\n", AMITK_OBJECT_NAME(tree_view->study)); /* figure out what we're suppose to be dragging */ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree_view), tree_view->mouse_x, tree_view->mouse_y, &path, NULL, &cell_x, &cell_y)) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(model, &iter, COLUMN_OBJECT, &object, -1); g_return_if_fail(AMITK_IS_OBJECT(object)); /* if object is appropriate, start dragging */ if (!AMITK_IS_STUDY(object)) { tree_view->src_object = object; g_print("drag begin - figured out source\n"); // context = gtk_drag_begin(widget, tree_view->drag_list, // GDK_ACTION_ASK, 1, (GdkEvent*)event); // pixbuf = tree_view_get_object_pixbuf(tree_view, object); // gtk_drag_set_icon_pixbuf(context, pixbuf, -10,-10); // g_object_unref(pixbuf); } } } static void tree_view_drag_end (GtkWidget *widget, GdkDragContext *context) { AmitkTreeView * tree_view; g_return_if_fail(AMITK_IS_TREE_VIEW(widget)); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("drag end %s\n", AMITK_OBJECT_NAME(tree_view->study)); tree_view->src_object = NULL; } static void tree_view_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time) { // char *entry_text; AmitkTreeView * tree_view; g_return_if_fail(AMITK_IS_TREE_VIEW(widget)); g_return_if_fail(selection_data != NULL); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("drag data get %s info %d\n", AMITK_OBJECT_NAME(tree_view->study), info); switch (info) { case AMITK_TREE_VIEW_DND_OBJECT: // gtk_selection_data_set_text(selection_data, AMITK_OBJECT_NAME(tree_view->src_object), -1); gtk_selection_data_set (selection_data, selection_data->target, 8, (guchar *) AMITK_OBJECT_NAME(tree_view->src_object), strlen (AMITK_OBJECT_NAME(tree_view->src_object))+1); break; case AMITK_DND_URI_LIST: default: g_assert_not_reached (); } } static void tree_view_drag_data_delete (GtkWidget *widget, GdkDragContext *context) { AmitkTreeView * tree_view; g_return_if_fail(AMITK_IS_TREE_VIEW(widget)); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("drag data delete on %s\n", AMITK_OBJECT_NAME(tree_view->study)); } static void tree_view_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time) { AmitkTreeView * tree_view; g_return_if_fail(AMITK_IS_TREE_VIEW(widget)); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("target leave on %s\n", AMITK_OBJECT_NAME(tree_view->study)); } static gboolean tree_view_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time) { AmitkTreeView * tree_view; g_return_val_if_fail(AMITK_IS_TREE_VIEW(widget), FALSE); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; // g_print("target motion %d %d on %s\n", x, y, AMITK_OBJECT_NAME(tree_view->study)); // gdk_drag_status (context, 0, time); // gtk_drag_finish (context, FALSE, FALSE, time); // valid_row = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree_view), event->x, event->y, // &(AMITK_TREE_VIEW(tree_view)->current_path), // &column, &cell_x, &cell_y); return TRUE; } static gboolean tree_view_drag_drop (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time) { // GtkWidget * menu; // GtkWidget * menuitem; // GdkAtom target = GDK_NONE; AmitkTreeView * tree_view; g_return_val_if_fail(AMITK_IS_TREE_VIEW(widget), FALSE); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("drop on %d %d %s\n", x, y, AMITK_OBJECT_NAME(tree_view->study)); /* check if drop is valid */ /* record which object we're moving/copying, and to where */ /* see if we want to copy or move */ // menu = gtk_menu_new(); // menuitem = gtk_menu_item_new_with_label("Move"); // gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); // g_object_set_data(G_OBJECT(menuitem), "move", GINT_TO_POINTER(TRUE)); // g_object_set(data(G_OBJECT(menuitem), "tree_view", tree_view); // g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(tree_view_drop_cb), context); // gtk_widget_show(menuitem); // menuitem = gtk_menu_item_new_with_label("Copy"); // gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); // g_object_set_data(G_OBJECT(menuitem), "move", GINT_TO_POINTER(FALSE)); // g_object_set(data(G_OBJECT(menuitem), "tree_view", tree_view); // g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(tree_view_drop_cb), context); // gtk_widget_show(menuitem); // gtk_widget_show(menu); // gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, time); // target = gtk_drag_dest_find_target (widget, context, NULL); // if (target != GDK_NONE) { // g_print("target\n"); // gtk_drag_get_data (widget, context, target, time); // } else { // gtk_drag_finish (context, FALSE, FALSE, time); // } /* Drag and drop didn't happen! */ // gtk_drag_finish (context, FALSE, FALSE, time); return TRUE; } static void tree_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time) { gchar *str; gchar **uris; gint uris_index; AmitkTreeView * tree_view; AmitkDataSet * dropped_ds; gchar * import_filename; g_return_if_fail(AMITK_IS_TREE_VIEW(widget)); tree_view = AMITK_TREE_VIEW(widget); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; g_print("target receive %s\n", AMITK_OBJECT_NAME(tree_view->study)); if (selection_data->length >= 0) g_print("selection data format %d\n", selection_data->format); g_print("context->action %d\n", context->action); switch (info) { case AMITK_TREE_VIEW_DND_OBJECT: str = selection_data->data; // str = gtk_selection_data_get_text (selection_data); g_print("target receive x %d y %d info %d suggested action %d\n", x,y,info, context->suggested_action); g_print("target receive x %d y %d info %d suggested action %d selection %s\n", x,y,info, context->suggested_action,str); g_free(str); break; case AMITK_DND_URI_LIST: uris = g_strsplit (selection_data->data, "\r\n", 0); for (uris_index=0; (uris[uris_index] != NULL && uris[uris_index][0] != '\0'); uris_index++) { if ((import_filename = g_filename_from_uri(uris[uris_index], NULL, NULL)) == NULL) g_warning("Could not generate filename for URI: %s", uris[uris_index]); else { dropped_ds = amitk_data_set_import_file(AMITK_IMPORT_METHOD_GUESS, 0, import_filename, NULL, tree_view->preferences, amitk_progress_dialog_update, tree_view->progress_dialog); g_free(import_filename); if (dropped_ds != NULL) { amitk_object_add_child(AMITK_OBJECT(tree_view->study), AMITK_OBJECT(dropped_ds)); /* this adds a reference to the data set*/ amitk_object_unref(dropped_ds); /* so remove a reference */ } } } g_strfreev (uris); break; default: g_assert_not_reached (); } gtk_drag_finish (context, FALSE, FALSE, time); } /* if ((data->length >= 0) && (data->format == 8)) */ /* { */ /* if (context->action == GDK_ACTION_ASK) */ /* { */ /* GtkWidget *dialog; */ /* gint response; */ /* dialog = gtk_message_dialog_new (NULL, */ /* GTK_DIALOG_MODAL | */ /* GTK_DIALOG_DESTROY_WITH_PARENT, */ /* GTK_MESSAGE_INFO, */ /* GTK_BUTTONS_YES_NO, */ /* "Move the data ?\n"); */ /* response = gtk_dialog_run (GTK_DIALOG (dialog)); */ /* gtk_widget_destroy (dialog); */ /* if (response == GTK_RESPONSE_YES) */ /* context->action = GDK_ACTION_MOVE; */ /* else */ /* context->action = GDK_ACTION_COPY; */ /* } */ /* gtk_drag_finish (context, TRUE, FALSE, time); */ /* return; */ /* } */ /* } */ #endif static void tree_view_study_view_mode_cb(AmitkStudy * study, gpointer data) { AmitkTreeView * tree_view = data; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(AMITK_IS_STUDY(study)); if (tree_view->mode != AMITK_TREE_VIEW_MODE_MAIN) return; tree_view_set_view_mode(tree_view, AMITK_STUDY_VIEW_MODE(study)); return; } static void tree_view_object_update_cb(AmitkObject * object, gpointer data) { AmitkTreeView * tree_view = data; GtkTreeIter iter; GtkTreeModel * model; GdkPixbuf * pixbuf; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(AMITK_IS_OBJECT(object)); if (tree_view_find_object(tree_view, object, &iter)) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); pixbuf = tree_view_get_object_pixbuf(tree_view, object); gtk_tree_store_set(GTK_TREE_STORE(model), &iter, COLUMN_ICON, pixbuf, COLUMN_NAME, AMITK_OBJECT_NAME(object), COLUMN_VISIBLE_SINGLE, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_0), COLUMN_VISIBLE_LINKED_2WAY, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_1), COLUMN_VISIBLE_LINKED_3WAY, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_2), -1); g_object_unref(pixbuf); } if (tree_view->mode == AMITK_TREE_VIEW_MODE_MAIN) { if (tree_view->active_object == object) { if (!amitk_object_get_selected(object, AMITK_SELECTION_ANY)) /* we're unselecting the active object */ g_signal_emit(G_OBJECT(tree_view), tree_view_signals[ACTIVATE_OBJECT], 0,NULL); } else if (tree_view->active_object == NULL) { /* currently no active object */ if (amitk_object_get_selected(object, AMITK_SELECTION_ANY)) /* we've selected something */ g_signal_emit(G_OBJECT(tree_view), tree_view_signals[ACTIVATE_OBJECT], 0,object); } } return; } static void tree_view_data_set_color_table_cb(AmitkDataSet * data_set, AmitkViewMode view_mode, gpointer data) { g_return_if_fail(AMITK_IS_DATA_SET(data_set)); if (view_mode == AMITK_VIEW_MODE_SINGLE) tree_view_object_update_cb(AMITK_OBJECT(data_set), data); } static void tree_view_object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { AmitkTreeView * tree_view = data; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(AMITK_IS_OBJECT(child)); tree_view_add_object(AMITK_TREE_VIEW(tree_view), child); return; } static void tree_view_object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { AmitkTreeView * tree_view = data; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(AMITK_IS_OBJECT(child)); tree_view_remove_object(AMITK_TREE_VIEW(tree_view), child); return; } static gboolean tree_view_find_recurse(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { tree_view_find_t * tree_view_find=data; AmitkObject * object; gtk_tree_model_get(model, iter, COLUMN_OBJECT, &object, -1); g_return_val_if_fail(object != NULL, FALSE); if (object == tree_view_find->object) { tree_view_find->iter = *iter; tree_view_find->found = TRUE; return TRUE; } else { return FALSE; } } static gboolean tree_view_find_object(AmitkTreeView * tree_view, AmitkObject * object, GtkTreeIter * iter) { GtkTreeModel * model; tree_view_find_t tree_view_find; g_return_val_if_fail(AMITK_IS_TREE_VIEW(tree_view),FALSE); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); tree_view_find.object = object; tree_view_find.found = FALSE; gtk_tree_model_foreach(model, tree_view_find_recurse, &tree_view_find); if (tree_view_find.found) { *iter = tree_view_find.iter; return TRUE; } else return FALSE; } static void tree_view_add_object(AmitkTreeView * tree_view, AmitkObject * object) { GList * children; GtkTreeIter parent_iter; GtkTreeIter iter; GtkTreeModel * model; GdkPixbuf * pixbuf; amitk_object_ref(object); /* add a reference */ if (AMITK_IS_STUDY(object)) { /* save a pointer to thestudy object */ if (tree_view->study != NULL) { tree_view_remove_object(tree_view, AMITK_OBJECT(tree_view->study)); } tree_view->study = AMITK_STUDY(object); tree_view_set_view_mode(tree_view, AMITK_STUDY_VIEW_MODE(object)); } model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); if (AMITK_OBJECT_PARENT(object) == NULL) gtk_tree_store_append (GTK_TREE_STORE(model), &iter, NULL); /* Acquire a top-level iterator */ else { if (tree_view_find_object(tree_view, AMITK_OBJECT_PARENT(object), &parent_iter)) gtk_tree_store_append (GTK_TREE_STORE(model), &iter, &parent_iter); else g_return_if_reached(); } pixbuf = tree_view_get_object_pixbuf(tree_view, object); gtk_tree_store_set(GTK_TREE_STORE(model), &iter, COLUMN_MULTIPLE_SELECTION, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_0), /* default */ COLUMN_VISIBLE_SINGLE, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_0), COLUMN_VISIBLE_LINKED_2WAY, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_1), COLUMN_VISIBLE_LINKED_3WAY, amitk_object_get_selected(object, AMITK_SELECTION_SELECTED_2), COLUMN_EXPANDER, "*", COLUMN_ICON, pixbuf, COLUMN_NAME, AMITK_OBJECT_NAME(object), COLUMN_OBJECT, object, -1); g_object_unref(pixbuf); g_signal_connect(G_OBJECT(object), "object_name_changed", G_CALLBACK(tree_view_object_update_cb), tree_view); g_signal_connect(G_OBJECT(object), "object_selection_changed", G_CALLBACK(tree_view_object_update_cb), tree_view); if (AMITK_IS_DATA_SET(object)) { g_signal_connect(G_OBJECT(object), "modality_changed", G_CALLBACK(tree_view_object_update_cb), tree_view); g_signal_connect(G_OBJECT(object), "color_table_changed", G_CALLBACK(tree_view_data_set_color_table_cb), tree_view); } else if (AMITK_IS_ROI(object)) { g_signal_connect(G_OBJECT(object), "roi_type_changed", G_CALLBACK(tree_view_object_update_cb), tree_view); } else if (AMITK_IS_STUDY(object)) { g_signal_connect(G_OBJECT(object), "view_mode_changed", G_CALLBACK(tree_view_study_view_mode_cb), tree_view); } g_signal_connect(G_OBJECT(object), "object_add_child", G_CALLBACK(tree_view_object_add_child_cb), tree_view); g_signal_connect(G_OBJECT(object), "object_remove_child", G_CALLBACK(tree_view_object_remove_child_cb), tree_view); /* add children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { tree_view_add_object(tree_view, children->data); children = children->next; } } static void tree_view_remove_object(AmitkTreeView * tree_view, AmitkObject * object) { GList * children; GtkTreeIter iter; GtkTreeModel * model; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(tree_view_find_object(tree_view, object, &iter)); /* shouldn't fail */ /* unselect the object */ if (tree_view->mode == AMITK_TREE_VIEW_MODE_MAIN) amitk_object_unselect(object, AMITK_SELECTION_ALL); /* recursive remove children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { tree_view_remove_object(tree_view, children->data); children = children->next; } /* disconnect the object's signals */ g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(tree_view_object_update_cb), tree_view); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(tree_view_object_add_child_cb), tree_view); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(tree_view_object_remove_child_cb), tree_view); if (AMITK_IS_STUDY(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(tree_view_study_view_mode_cb), tree_view); } if (AMITK_IS_DATA_SET(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(tree_view_data_set_color_table_cb), tree_view); } /* remove the object */ model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); /* and unref */ amitk_object_unref(object); return; } /* preferences and progress_dialog can be NULL, nicer if they're not */ GtkWidget* amitk_tree_view_new (AmitkTreeViewMode tree_mode, AmitkPreferences * preferences, GtkWidget * progress_dialog) { AmitkTreeView * tree_view; AmitkViewMode i_view_mode; gchar * temp_string; GtkTreeStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; tree_view = g_object_new(amitk_tree_view_get_type(), NULL); tree_view->mode = tree_mode; /* if given preferences, save them */ if (preferences != NULL) tree_view->preferences = g_object_ref(preferences); else tree_view->preferences = NULL; /* if given a progress dialog, save it */ if (progress_dialog != NULL) tree_view->progress_dialog = g_object_ref(progress_dialog); else tree_view->progress_dialog = NULL; gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE); store = gtk_tree_store_new(NUM_COLUMNS, G_TYPE_BOOLEAN, /* COLUMN_MULTIPLE_SELECTION */ G_TYPE_BOOLEAN, /* COLUMN_VISIBLE_SINGLE */ G_TYPE_BOOLEAN,/* COLUMN_VISIBLE_LINKED_2WAY */ G_TYPE_BOOLEAN, /* COLUMN_VISIBLE_LINKED_3WAY */ G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model (GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL (store)); g_object_unref(store); renderer = gtk_cell_renderer_toggle_new (); column = gtk_tree_view_column_new_with_attributes("", renderer, /* "visible" */ "active", COLUMN_MULTIPLE_SELECTION, NULL); for (i_view_mode = 0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { renderer = gtk_cell_renderer_toggle_new (); temp_string = g_strdup_printf("%d", i_view_mode+1); tree_view->select_column[i_view_mode] = gtk_tree_view_column_new_with_attributes(temp_string, renderer, /* "visible" */ "active", COLUMN_VISIBLE_SINGLE+i_view_mode, NULL); g_free(temp_string); } switch(tree_view->mode) { case AMITK_TREE_VIEW_MODE_MAIN: /* by default, only first select column is shown */ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), tree_view->select_column[AMITK_VIEW_MODE_SINGLE]); break; case AMITK_TREE_VIEW_MODE_SINGLE_SELECTION: break; case AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION: gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); break; default: g_error("unexpected case in %s at %d\n", __FILE__, __LINE__); break; } renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes("", renderer, /* "expand "*/ "text", COLUMN_EXPANDER, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); gtk_tree_view_set_expander_column(GTK_TREE_VIEW(tree_view), column); renderer = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new_with_attributes("", renderer, /* "icon" */ "pixbuf", COLUMN_ICON, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes("name", renderer, "text", COLUMN_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); switch (tree_view->mode) { case AMITK_TREE_VIEW_MODE_MAIN: case AMITK_TREE_VIEW_MODE_SINGLE_SELECTION: gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); break; case AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION: default: gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); break; } return GTK_WIDGET (tree_view); } void amitk_tree_view_set_study(AmitkTreeView * tree_view, AmitkStudy * study) { g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(AMITK_IS_STUDY(study)); tree_view_add_object(tree_view, AMITK_OBJECT(study)); return; } void amitk_tree_view_expand_object(AmitkTreeView * tree_view, AmitkObject * object) { GtkTreeIter iter; GtkTreeModel * model; GtkTreePath * path; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail(AMITK_IS_OBJECT(object)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); if (tree_view_find_object(tree_view, object, &iter)) { path = gtk_tree_model_get_path(model, &iter); gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, FALSE); gtk_tree_path_free(path); } return; } /* this function can return NULL */ AmitkObject * amitk_tree_view_get_active_object(AmitkTreeView * tree_view) { g_return_val_if_fail(AMITK_IS_TREE_VIEW(tree_view), NULL); return tree_view->active_object; } void amitk_tree_view_set_active_object(AmitkTreeView * tree_view, AmitkObject * object) { GtkTreeSelection *selection; GtkTreeIter iter; g_return_if_fail(AMITK_IS_TREE_VIEW(tree_view)); g_return_if_fail((tree_view->mode == AMITK_TREE_VIEW_MODE_MAIN) || (tree_view->mode == AMITK_TREE_VIEW_MODE_SINGLE_SELECTION)); if (tree_view->active_object != NULL) { amitk_object_unref(tree_view->active_object); tree_view->active_object = NULL; } selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); if (object == NULL) { /* if any item is marked as active, unselect it */ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) gtk_tree_selection_unselect_iter(selection, &iter); } else { g_return_if_fail(AMITK_IS_OBJECT(object)); if (tree_view_find_object(tree_view, object, &iter)) { tree_view->active_object = amitk_object_ref(object); if (!gtk_tree_selection_iter_is_selected(selection, &iter)) gtk_tree_selection_select_iter(selection, &iter); } } return; } gboolean multiple_selection_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList ** pobjects = data; gboolean multiple_selection; AmitkObject * object; gtk_tree_model_get(model, iter, COLUMN_OBJECT, &object, COLUMN_MULTIPLE_SELECTION, &multiple_selection, -1); if (multiple_selection) *pobjects = g_list_append(*pobjects, amitk_object_ref(object)); return FALSE; } GList * amitk_tree_view_get_multiple_selection_objects(AmitkTreeView * tree_view) { GList * objects=NULL; GtkTreeModel *tree_model; g_return_val_if_fail(AMITK_IS_TREE_VIEW(tree_view), NULL); g_return_val_if_fail(tree_view->mode == AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION, NULL); tree_model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); gtk_tree_model_foreach(tree_model, multiple_selection_foreach, &objects); return objects; } amide-1.0.6/amide-current/src/amitk_tree_view.h000066400000000000000000000074631423227705100214670ustar00rootroot00000000000000/* amitk_tree_view.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_TREE_VIEW_H__ #define __AMITK_TREE_VIEW_H__ /* includes we always need with this widget */ #include #include "amitk_type_builtins.h" #include "amitk_study.h" G_BEGIN_DECLS #define AMITK_TYPE_TREE_VIEW (amitk_tree_view_get_type ()) #define AMITK_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_TREE_VIEW, AmitkTreeView)) #define AMITK_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_THESHOLD, AmitkTreeViewClass)) #define AMITK_IS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_TREE_VIEW)) #define AMITK_IS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_TREE_VIEW)) typedef enum { AMITK_TREE_VIEW_MODE_MAIN, AMITK_TREE_VIEW_MODE_SINGLE_SELECTION, AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION, AMITK_TREE_VIEW_MODE_NUM } AmitkTreeViewMode; typedef struct _AmitkTreeView AmitkTreeView; typedef struct _AmitkTreeViewClass AmitkTreeViewClass; struct _AmitkTreeView { GtkTreeView tree_view; AmitkTreeViewMode mode; AmitkStudy * study; AmitkObject * active_object; AmitkPreferences * preferences; GtkWidget * progress_dialog; GtkTreeViewColumn * select_column[AMITK_VIEW_MODE_NUM]; AmitkViewMode prev_view_mode; gint mouse_x; /* the current mouse position */ gint mouse_y; GtkTreePath * current_path; /* drag-n-drop info */ gboolean drag_begin_possible; gint press_x; gint press_y; AmitkObject * src_object; /* not referenced */ AmitkObject * dest_object; /* not referenced */ GtkTargetList * drag_list; }; struct _AmitkTreeViewClass { GtkTreeViewClass parent_class; void (* help_event) (AmitkTreeView * tree_view, AmitkHelpInfo help_type); void (* activate_object) (AmitkTreeView * tree, AmitkObject * object); void (* popup_object) (AmitkTreeView * tree_view, AmitkObject * object); void (* add_object) (AmitkTreeView * tree_view, AmitkObject * parent, AmitkObjectType type, AmitkRoiType roi_type); void (* delete_object) (AmitkTreeView * tree_view, AmitkObject * object); }; GType amitk_tree_view_get_type (void); GtkWidget* amitk_tree_view_new (AmitkTreeViewMode tree_mode, AmitkPreferences * preferences, GtkWidget * progress_dialog); void amitk_tree_view_set_study (AmitkTreeView * tree_view, AmitkStudy * study); void amitk_tree_view_expand_object (AmitkTreeView * tree_view, AmitkObject * object); AmitkObject * amitk_tree_view_get_active_object (AmitkTreeView * tree_view); void amitk_tree_view_set_active_object (AmitkTreeView * tree_view, AmitkObject * object); GList * amitk_tree_view_get_multiple_selection_objects(AmitkTreeView * tree_view); G_END_DECLS #endif /* __AMITK_TREE_VIEW_H__ */ amide-1.0.6/amide-current/src/amitk_type.h000066400000000000000000000033531423227705100204510ustar00rootroot00000000000000/* amitk_type.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_TYPE_H__ #define __AMITK_TYPE_H__ #include G_BEGIN_DECLS /* setup the types for various internal data formats */ /* note, don't change these unless you want to go digging through the code for locations where the signal marshallers expect the type to be DOUBLE. Would also need to update the REAL_EQUAL type functions in amitk_point.h */ typedef gdouble amide_data_t; #define SIZE_OF_AMIDE_DATA_T 8 #define AMITK_TYPE_DATA G_TYPE_DOUBLE typedef gdouble amide_time_t; #define SIZE_OF_AMIDE_TIME_T 8 #define AMITK_TYPE_TIME G_TYPE_DOUBLE typedef gdouble amide_real_t; #define SIZE_OF_AMIDE_REAL_T 8 #define AMITK_TYPE_REAL G_TYPE_DOUBLE /* size of a point in integer space */ typedef gint16 amide_intpoint_t; #define SIZE_OF_AMIDE_INTPOINT_T 2; typedef gboolean (*AmitkUpdateFunc) (gpointer, char *, gdouble); G_END_DECLS #endif /* __AMITK_TYPE_H__ */ amide-1.0.6/amide-current/src/amitk_volume.c000066400000000000000000000440361423227705100207750ustar00rootroot00000000000000/* amitk_volume.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amitk_volume.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" enum { VOLUME_CORNER_CHANGED, VOLUME_GET_CENTER, VOLUME_CHANGED, LAST_SIGNAL }; static void volume_class_init (AmitkVolumeClass *klass); static void volume_init (AmitkVolume *volume); static void volume_corner_changed (AmitkVolume *volume, AmitkPoint *new_corner); static void volume_get_center (const AmitkVolume *volume, AmitkPoint *center); static void volume_scale (AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling); static AmitkObject * volume_copy (const AmitkObject * object); static void volume_copy_in_place (AmitkObject * dest_object, const AmitkObject * src_object); static void volume_write_xml (const AmitkObject *object, xmlNodePtr nodes, FILE *study_file); static gchar * volume_read_xml (AmitkObject *object, xmlNodePtr nodes, FILE *study_file, gchar *error_buf); static AmitkObjectClass* parent_class; static guint volume_signals[LAST_SIGNAL]; GType amitk_volume_get_type(void) { static GType volume_type = 0; if (!volume_type) { static const GTypeInfo volume_info = { sizeof (AmitkVolumeClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) volume_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (AmitkVolume), 0, /* n_preallocs */ (GInstanceInitFunc) volume_init, NULL /* value table */ }; volume_type = g_type_register_static (AMITK_TYPE_OBJECT, "AmitkVolume", &volume_info, 0); } return volume_type; } static void volume_class_init (AmitkVolumeClass * class) { // GObjectClass *gobject_class = G_OBJECT_CLASS (class); AmitkObjectClass * object_class = AMITK_OBJECT_CLASS(class); AmitkSpaceClass * space_class = AMITK_SPACE_CLASS(class); parent_class = g_type_class_peek_parent(class); space_class->space_scale = volume_scale; object_class->object_copy = volume_copy; object_class->object_copy_in_place = volume_copy_in_place; object_class->object_write_xml = volume_write_xml; object_class->object_read_xml = volume_read_xml; class->volume_corner_changed = volume_corner_changed; class->volume_get_center = volume_get_center; volume_signals[VOLUME_CORNER_CHANGED] = g_signal_new ("volume_corner_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkVolumeClass, volume_corner_changed), NULL, NULL, amitk_marshal_VOID__BOXED, G_TYPE_NONE,1, AMITK_TYPE_POINT); volume_signals[VOLUME_GET_CENTER] = g_signal_new ("volume_get_center", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkVolumeClass, volume_get_center), NULL, NULL, amitk_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); volume_signals[VOLUME_CHANGED] = g_signal_new ("volume_changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(AmitkVolumeClass, volume_changed), NULL, NULL, amitk_marshal_VOID__VOID, G_TYPE_NONE,0); } static void volume_init (AmitkVolume * volume) { volume->corner = zero_point; volume->valid = FALSE; return; } static void volume_corner_changed(AmitkVolume *volume, AmitkPoint * new_corner) { volume->corner = *new_corner; volume->valid = TRUE; return; } static void volume_get_center(const AmitkVolume *volume, AmitkPoint * pcenter) { AmitkCorners corners; /* get the far corner, corner[0] is currently always zero */ corners[0] = amitk_space_b2s(AMITK_SPACE(volume), AMITK_SPACE_OFFSET(volume)); corners[1] = volume->corner; /* the center in roi coords is then just half the far corner */ (*pcenter) = point_add(point_cmult(0.5,corners[1]), point_cmult(0.5,corners[0])); /* now, translate that into the base coord frame */ (*pcenter) = amitk_space_s2b(AMITK_SPACE(volume), (*pcenter)); return; } static void volume_scale(AmitkSpace * space, AmitkPoint * ref_point, AmitkPoint * scaling) { AmitkVolume * volume; AmitkPoint new_corner; AmitkPoint shift; g_return_if_fail(AMITK_IS_VOLUME(space)); volume = AMITK_VOLUME(space); /* readjust the far corner */ /* note that this is an approximate scaling. Since we preserve angles, we can't correctly scale ROI's if the ROI is not orthogonal to the space that's initially being scaled. */ new_corner = AMITK_VOLUME_CORNER(volume); new_corner = amitk_space_s2b(AMITK_SPACE(volume), new_corner); shift = point_sub(new_corner, *ref_point); shift = point_mult(*scaling, shift); new_corner = point_add(*ref_point, shift); /* update the space */ AMITK_SPACE_CLASS(parent_class)->space_scale (space, ref_point, scaling); /* calculate the new corner */ if (AMITK_VOLUME_VALID(volume)) { new_corner = amitk_space_b2s(AMITK_SPACE(volume), new_corner); g_return_if_fail(new_corner.x >= 0); g_return_if_fail(new_corner.y >= 0); g_return_if_fail(new_corner.z >= 0); amitk_volume_set_corner(volume, new_corner); } } static AmitkObject * volume_copy(const AmitkObject * object) { AmitkVolume * copy; g_return_val_if_fail(AMITK_IS_VOLUME(object), NULL); copy = amitk_volume_new(); amitk_object_copy_in_place(AMITK_OBJECT(copy), AMITK_OBJECT(object)); return AMITK_OBJECT(copy); } static void volume_copy_in_place(AmitkObject * dest_object, const AmitkObject * src_object) { g_return_if_fail(AMITK_IS_VOLUME(src_object)); g_return_if_fail(AMITK_IS_VOLUME(dest_object)); if (AMITK_VOLUME_VALID(src_object)) amitk_volume_set_corner(AMITK_VOLUME(dest_object), AMITK_VOLUME_CORNER(src_object)); else AMITK_VOLUME(dest_object)->valid = FALSE; AMITK_OBJECT_CLASS (parent_class)->object_copy_in_place (dest_object, src_object); } static void volume_write_xml(const AmitkObject * object, xmlNodePtr nodes, FILE * study_file) { AMITK_OBJECT_CLASS(parent_class)->object_write_xml(object, nodes, study_file); amitk_point_write_xml(nodes, "corner", AMITK_VOLUME_CORNER(object)); xml_save_boolean(nodes, "valid", AMITK_VOLUME_VALID(object)); return; } static gchar * volume_read_xml(AmitkObject * object, xmlNodePtr nodes, FILE * study_file, gchar * error_buf) { AmitkVolume * volume; error_buf = AMITK_OBJECT_CLASS(parent_class)->object_read_xml(object, nodes, study_file, error_buf); volume = AMITK_VOLUME(object); volume->corner = amitk_point_read_xml(nodes, "corner", &error_buf); volume->valid = xml_get_boolean(nodes, "valid", &error_buf); /* legacy, "valid" is a new parameter */ if (!volume->valid) if (!POINT_EQUAL(volume->corner, zero_point)) volume->valid = TRUE; return error_buf; } AmitkVolume * amitk_volume_new (void) { AmitkVolume * volume; volume = g_object_new(amitk_volume_get_type(), NULL); return volume; } /* point should be in the base coordinate frame */ gboolean amitk_volume_point_in_bounds(const AmitkVolume * volume, const AmitkPoint base_point) { AmitkPoint point; g_return_val_if_fail(AMITK_IS_VOLUME(volume), FALSE); g_return_val_if_fail(AMITK_VOLUME_VALID(volume), FALSE); point = amitk_space_b2s(AMITK_SPACE(volume), base_point); if ((point.x < 0.0) || (point.y < 0.0) || (point.z < 0.0) || (point.x > AMITK_VOLUME_X_CORNER(volume)) || (point.y > AMITK_VOLUME_Y_CORNER(volume)) || (point.z > AMITK_VOLUME_Z_CORNER(volume))) return FALSE; else return TRUE; } AmitkPoint amitk_volume_place_in_bounds(const AmitkVolume * volume, const AmitkPoint base_point) { AmitkPoint point; g_return_val_if_fail(AMITK_IS_VOLUME(volume), zero_point); g_return_val_if_fail(AMITK_VOLUME_VALID(volume), zero_point); point = amitk_space_b2s(AMITK_SPACE(volume), base_point); if (point.x < 0.0) point.x = 0.0; else if (point.x > AMITK_VOLUME_X_CORNER(volume)) point.x = AMITK_VOLUME_X_CORNER(volume); if (point.y < 0.0) point.y = 0.0; else if (point.y > AMITK_VOLUME_Y_CORNER(volume)) point.y = AMITK_VOLUME_Y_CORNER(volume); if (point.z < 0.0) point.z = 0.0; else if (point.z > AMITK_VOLUME_Z_CORNER(volume)) point.z = AMITK_VOLUME_Z_CORNER(volume); point = amitk_space_s2b(AMITK_SPACE(volume), point); return point; } AmitkPoint amitk_volume_get_center(const AmitkVolume * volume) { AmitkPoint center; g_return_val_if_fail(AMITK_IS_VOLUME(volume), zero_point); g_return_val_if_fail(AMITK_VOLUME_VALID(volume), zero_point); g_signal_emit(G_OBJECT(volume), volume_signals[VOLUME_GET_CENTER], 0, ¢er); return center; } void amitk_volume_set_corner(AmitkVolume * volume, AmitkPoint corner) { g_return_if_fail(AMITK_IS_VOLUME(volume)); if (!POINT_EQUAL(AMITK_VOLUME_CORNER(volume), corner) || (!AMITK_VOLUME_VALID(volume))) { g_signal_emit(G_OBJECT(volume), volume_signals[VOLUME_CORNER_CHANGED], 0, &corner); g_signal_emit(G_OBJECT(volume), volume_signals[VOLUME_CHANGED], 0); } } void amitk_volume_set_z_corner(AmitkVolume * volume, amide_real_t z) { AmitkPoint corner; g_return_if_fail(AMITK_IS_VOLUME(volume)); g_return_if_fail(AMITK_VOLUME_VALID(volume)); if (!REAL_EQUAL(AMITK_VOLUME_Z_CORNER(volume), z)) { corner = AMITK_VOLUME_CORNER(volume); corner.z = z; g_signal_emit(G_OBJECT(volume), volume_signals[VOLUME_CORNER_CHANGED], 0, &corner); g_signal_emit(G_OBJECT(volume), volume_signals[VOLUME_CHANGED], 0); } } /* center should be in the base coordinate frame */ void amitk_volume_set_center(AmitkVolume * volume, const AmitkPoint new_center) { AmitkPoint shift; AmitkPoint new_offset; g_return_if_fail(AMITK_IS_VOLUME(volume)); g_return_if_fail(AMITK_VOLUME_VALID(volume)); shift = point_sub(new_center, amitk_volume_get_center(volume)); if (!POINT_EQUAL(shift, zero_point)) { new_offset = point_add(AMITK_SPACE_OFFSET(volume), shift); amitk_space_set_offset(AMITK_SPACE(volume), new_offset); } return; } /* takes a volume and a coordinate space, and give the corners of a box with sides orthogonal to the given space that totally encompasses the volume. The returned corners are in the coordinate space of the "space" variable */ void amitk_volume_get_enclosing_corners(const AmitkVolume * volume, const AmitkSpace * space, AmitkCorners return_corners) { AmitkCorners corners; g_return_if_fail(AMITK_IS_VOLUME(volume)); g_return_if_fail(AMITK_IS_SPACE(space)); g_return_if_fail(AMITK_VOLUME_VALID(volume)); corners[0] = amitk_space_b2s(AMITK_SPACE(volume), AMITK_SPACE_OFFSET(volume)); corners[1] = volume->corner; /* look at all eight corners of our cube, figure out the min and max coords */ amitk_space_get_enclosing_corners(AMITK_SPACE(volume), corners, space, return_corners); return; } /* takes a list of objects and a view coordinate space, give the corners necessary to totally encompass the volumes in the given space */ gboolean amitk_volumes_get_enclosing_corners(const GList * objects, const AmitkSpace * space, AmitkCorners return_corners) { AmitkCorners temp_corners; gboolean valid=FALSE; while (objects != NULL) { if (AMITK_IS_VOLUME(objects->data)) { if (AMITK_VOLUME_VALID(objects->data)) { amitk_volume_get_enclosing_corners(AMITK_VOLUME(objects->data),space,temp_corners); if (!valid) { valid = TRUE; return_corners[0] = temp_corners[0]; return_corners[1] = temp_corners[1]; } else { return_corners[0].x = (return_corners[0].x < temp_corners[0].x) ? return_corners[0].x : temp_corners[0].x; return_corners[0].y = (return_corners[0].y < temp_corners[0].y) ? return_corners[0].y : temp_corners[0].y; return_corners[0].z = (return_corners[0].z < temp_corners[0].z) ? return_corners[0].z : temp_corners[0].z; return_corners[1].x = (return_corners[1].x > temp_corners[1].x) ? return_corners[1].x : temp_corners[1].x; return_corners[1].y = (return_corners[1].y > temp_corners[1].y) ? return_corners[1].y : temp_corners[1].y; return_corners[1].z = (return_corners[1].z > temp_corners[1].z) ? return_corners[1].z : temp_corners[1].z; } } } objects = objects->next; } if (!valid) return_corners[0] = return_corners[1] = zero_point; return valid; } /* returns the corners of a box (orthogonal to volume1's coordinate space) that completely encloses the intersection of the two volumes. Corner points are in the space of volume 1. Returns FALSE if no intersection. */ gboolean amitk_volume_volume_intersection_corners(const AmitkVolume * volume1, const AmitkVolume * volume2, AmitkCorners return_corners) { gint i; g_return_val_if_fail(AMITK_IS_VOLUME(volume1), FALSE); g_return_val_if_fail(AMITK_IS_VOLUME(volume2), FALSE); g_return_val_if_fail(AMITK_VOLUME_VALID(volume1), FALSE); g_return_val_if_fail(AMITK_VOLUME_VALID(volume2), FALSE); /* get the corners in the volume's space that orthogonally encloses the roi */ amitk_volume_get_enclosing_corners(volume2, AMITK_SPACE(volume1), return_corners); /* and reduce the size of the intersection box */ for (i=0; i<2; i++) { if (return_corners[i].x < 0.0) return_corners[i].x = 0; if (return_corners[i].y < 0.0) return_corners[i].y = 0; if (return_corners[i].z < 0.0) return_corners[i].z = 0; if (return_corners[i].x > volume1->corner.x) return_corners[i].x = volume1->corner.x; if (return_corners[i].y > volume1->corner.y) return_corners[i].y = volume1->corner.y; if (return_corners[i].z > volume1->corner.z) return_corners[i].z = volume1->corner.z; } if (REAL_EQUAL(return_corners[0].x, return_corners[1].x) || REAL_EQUAL(return_corners[0].y, return_corners[1].y) || REAL_EQUAL(return_corners[0].z, return_corners[1].z)) return FALSE; else return TRUE; } /* returns the maximal dimensional size of a list of volumes */ amide_real_t amitk_volumes_get_max_size(GList * objects) { amide_real_t temp, max_size; if (objects == NULL) return -1.0; /* invalid */ /* first process the rest of the list */ max_size = amitk_volumes_get_max_size(objects->next); /* now process and compare to the children */ temp = amitk_volumes_get_max_size(AMITK_OBJECT_CHILDREN(objects->data)); if (temp > max_size) max_size = temp; /* and process this guy */ if (AMITK_IS_VOLUME(objects->data)) if (AMITK_VOLUME_VALID(objects->data)) { temp = point_max_dim(AMITK_VOLUME_CORNER(objects->data)); if (temp > max_size) max_size = temp; } return max_size; } /* given a list of volumes, a view space, a view point, and a thickness, calculates an appropriate slab volume in which the specified volumes will be containted. Returns true if the given volume structure is changed. view_center should be in the base reference frame. */ /* field of view is in percent */ gboolean amitk_volumes_calc_display_volume(const GList * volumes, const AmitkSpace * space, const AmitkPoint view_center, const amide_real_t thickness, const amide_real_t fov, AmitkVolume * volume) { AmitkCorners temp_corner; AmitkPoint temp_point; gboolean changed = FALSE; gboolean valid; AmitkPoint width; amide_real_t max_width; if (volumes == NULL) return FALSE; /* set the space of our view volume if needed */ if (!amitk_space_equal(space, AMITK_SPACE(volume))) { amitk_space_copy_in_place(AMITK_SPACE(volume), space); changed = TRUE; } /* figure out the corners */ valid = amitk_volumes_get_enclosing_corners(volumes,space, temp_corner); /* update the corners appropriately */ if (valid) { temp_point = amitk_space_b2s(space, view_center); /* compensate for field of view */ width = point_sub(temp_corner[1], temp_corner[0]); max_width = (fov/100.0)*POINT_MAX(width); if (width.x > max_width) { /* bigger than FOV */ if ((temp_point.x-max_width/2.0) < temp_corner[0].x) temp_corner[1].x = temp_corner[0].x+max_width; else if ((temp_point.x+max_width/2.0) > temp_corner[1].x) temp_corner[0].x = temp_corner[1].x-max_width; else { temp_corner[0].x = temp_point.x - max_width/2.0; temp_corner[1].x = temp_point.x + max_width/2.0; } } if (width.y > max_width) { if ((temp_point.y-max_width/2.0) < temp_corner[0].y) temp_corner[1].y = temp_corner[0].y+max_width; else if ((temp_point.y+max_width/2.0) > temp_corner[1].y) temp_corner[0].y = temp_corner[1].y-max_width; else { temp_corner[0].y = temp_point.y - max_width/2.0; temp_corner[1].y = temp_point.y + max_width/2.0; } } temp_corner[0].z = temp_point.z - thickness/2.0; temp_corner[1].z = temp_point.z + thickness/2.0; temp_corner[0] = amitk_space_s2b(space, temp_corner[0]); temp_corner[1] = amitk_space_s2b(space, temp_corner[1]); if (!POINT_EQUAL(AMITK_SPACE_OFFSET(volume), temp_corner[0])) { amitk_space_set_offset(AMITK_SPACE(volume), temp_corner[0]); changed = TRUE; } temp_corner[1] = amitk_space_b2s(AMITK_SPACE(volume), temp_corner[1]); if (!POINT_EQUAL(AMITK_VOLUME_CORNER(volume), temp_corner[1])) { amitk_volume_set_corner(volume, temp_corner[1]); changed = TRUE; } } return changed; } amide-1.0.6/amide-current/src/amitk_volume.h000066400000000000000000000101411423227705100207700ustar00rootroot00000000000000/* amitk_volume.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_VOLUME_H__ #define __AMITK_VOLUME_H__ #include "amitk_object.h" G_BEGIN_DECLS #define AMITK_TYPE_VOLUME (amitk_volume_get_type ()) #define AMITK_VOLUME(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), AMITK_TYPE_VOLUME, AmitkVolume)) #define AMITK_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_VOLUME, AmitkVolumeClass)) #define AMITK_IS_VOLUME(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), AMITK_TYPE_VOLUME)) #define AMITK_IS_VOLUME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_VOLUME)) #define AMITK_VOLUME_GET_CLASS(object) (G_TYPE_CHECK_GET_CLASS ((object), AMITK_TYPE_VOLUME, AmitkVolumeClass)) #define AMITK_VOLUME_CORNER(vol) (AMITK_VOLUME(vol)->corner) #define AMITK_VOLUME_X_CORNER(vol) (AMITK_VOLUME(vol)->corner.x) #define AMITK_VOLUME_Y_CORNER(vol) (AMITK_VOLUME(vol)->corner.y) #define AMITK_VOLUME_Z_CORNER(vol) (AMITK_VOLUME(vol)->corner.z) #define AMITK_VOLUME_VALID(vol) (AMITK_VOLUME(vol)->valid) typedef struct AmitkVolumeClass AmitkVolumeClass; typedef struct AmitkVolume AmitkVolume; struct AmitkVolume { AmitkObject parent; AmitkPoint corner; /* far corner, in volume's coord space. near corner always 0,0,0 in volume's coord space */ gboolean valid; /* if the corner is currently valid */ }; struct AmitkVolumeClass { AmitkObjectClass parent_class; void (*volume_corner_changed) (AmitkVolume * volume, AmitkPoint * new_corner); void (* volume_get_center) (const AmitkVolume * volume, AmitkPoint * center); void (* volume_changed) (AmitkVolume * volume); }; /* Application-level methods */ GType amitk_volume_get_type (void); AmitkVolume * amitk_volume_new (void); gboolean amitk_volume_point_in_bounds (const AmitkVolume * volume, const AmitkPoint point); AmitkPoint amitk_volume_place_in_bounds (const AmitkVolume * volume, const AmitkPoint point); AmitkPoint amitk_volume_get_center (const AmitkVolume * volume); void amitk_volume_set_corner (AmitkVolume * volume, AmitkPoint corner); void amitk_volume_set_z_corner (AmitkVolume * volume, amide_real_t z); void amitk_volume_set_center (AmitkVolume * volume, const AmitkPoint center); void amitk_volume_get_enclosing_corners (const AmitkVolume * volume, const AmitkSpace * space, AmitkCorners return_corners); gboolean amitk_volumes_get_enclosing_corners (const GList * volumes, const AmitkSpace * space, AmitkCorners return_corners); gboolean amitk_volume_volume_intersection_corners(const AmitkVolume * volume1, const AmitkVolume * volume2, AmitkCorners return_corners); amide_real_t amitk_volumes_get_max_size (GList * objects); gboolean amitk_volumes_calc_display_volume (const GList * volumes, const AmitkSpace * space, const AmitkPoint view_center, const amide_real_t thickness, const amide_real_t fov, AmitkVolume * volume); G_END_DECLS #endif /* __AMITK_VOLUME_H__ */ amide-1.0.6/amide-current/src/amitk_window_edit.c000066400000000000000000000275451423227705100220100ustar00rootroot00000000000000/* amitk_window_edit.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2005-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_marshal.h" #include "amitk_type_builtins.h" #include "amitk_window_edit.h" #include "amitk_common.h" static void window_edit_class_init (AmitkWindowEditClass *class); static void window_edit_init (AmitkWindowEdit *window_edit); static void window_edit_destroy(GtkObject * object); static void window_spin_cb(GtkWidget * widget, gpointer window_edit); static void insert_window_level_cb (GtkWidget * widget, gpointer window_edit); static void window_edit_update_entries(AmitkWindowEdit * window_edit); static GtkVBoxClass *parent_class; GType amitk_window_edit_get_type (void) { static GType window_edit_type = 0; if (!window_edit_type) { static const GTypeInfo window_edit_info = { sizeof (AmitkWindowEditClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) window_edit_class_init, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof (AmitkWindowEdit), 0, /* # preallocs */ (GInstanceInitFunc) window_edit_init, NULL /* value table */ }; window_edit_type = g_type_register_static(GTK_TYPE_VBOX, "AmitkWindowEdit", &window_edit_info, 0); } return window_edit_type; } static void window_edit_class_init (AmitkWindowEditClass *class) { GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS(class); parent_class = g_type_class_peek_parent(class); gtkobject_class->destroy = window_edit_destroy; } static void window_edit_init (AmitkWindowEdit *window_edit) { GtkWidget * table; GtkWidget * label; AmitkWindow i_window; AmitkLimit i_limit; guint table_row=0; /* initialize some critical stuff */ window_edit->data_set = NULL; window_edit->preferences = NULL; table = gtk_table_new(11,4, FALSE); gtk_container_add(GTK_CONTAINER(window_edit), table); for (i_limit = 0; i_limit < AMITK_LIMIT_NUM; i_limit++) { window_edit->limit_label[i_limit] = gtk_label_new(NULL); gtk_table_attach(GTK_TABLE(table), window_edit->limit_label[i_limit], 1+i_limit,2+i_limit, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(window_edit->limit_label[i_limit]); } table_row++; for (i_window = 0; i_window < AMITK_WINDOW_NUM; i_window++) { label = gtk_label_new(_(amitk_window_names[i_window])); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); for (i_limit = 0; i_limit < AMITK_LIMIT_NUM; i_limit++) { window_edit->window_spin[i_window][i_limit] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(window_edit->window_spin[i_window][i_limit]), FALSE); g_object_set_data(G_OBJECT(window_edit->window_spin[i_window][i_limit]), "which_window", GINT_TO_POINTER(i_window)); g_object_set_data(G_OBJECT(window_edit->window_spin[i_window][i_limit]), "which_limit", GINT_TO_POINTER(i_limit)); g_signal_connect(G_OBJECT(window_edit->window_spin[i_window][i_limit]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(window_edit->window_spin[i_window][i_limit]), "value_changed", G_CALLBACK(window_spin_cb), window_edit); gtk_table_attach(GTK_TABLE(table), window_edit->window_spin[i_window][i_limit], 1+i_limit,2+i_limit, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(window_edit->window_spin[i_window][i_limit]); } window_edit->insert_button[i_window] = gtk_button_new_with_label("Insert Current Thresholds"); gtk_table_attach(GTK_TABLE(table), window_edit->insert_button[i_window], 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(window_edit->insert_button[i_window]), "which_window", GINT_TO_POINTER(i_window)); g_signal_connect(G_OBJECT(window_edit->insert_button[i_window]), "clicked", G_CALLBACK(insert_window_level_cb), window_edit); table_row++; } gtk_widget_show(table); } static void window_edit_destroy (GtkObject * gtkobject) { AmitkWindowEdit * window_edit; g_return_if_fail (gtkobject != NULL); g_return_if_fail (AMITK_IS_WINDOW_EDIT (gtkobject)); window_edit = AMITK_WINDOW_EDIT(gtkobject); if (window_edit->data_set != NULL) { g_signal_handlers_disconnect_by_func(G_OBJECT(window_edit->data_set), window_edit_update_entries, window_edit); amitk_object_unref(AMITK_OBJECT(window_edit->data_set)); window_edit->data_set = NULL; } if (window_edit->preferences != NULL) { g_signal_handlers_disconnect_by_func(G_OBJECT(window_edit->preferences), window_edit_update_entries, window_edit); g_object_unref(G_OBJECT(window_edit->preferences)); window_edit->preferences = NULL; } if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (gtkobject); } static void window_spin_cb(GtkWidget * widget, gpointer data) { AmitkWindowEdit * window_edit = data; AmitkWindow which_window; AmitkLimit which_limit; amide_data_t value, min, max, center, window; AmitkThresholdStyle threshold_style; g_return_if_fail(AMITK_IS_WINDOW_EDIT(window_edit)); which_window = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_window")); which_limit = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_limit")); value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (window_edit->data_set != NULL) { threshold_style = AMITK_DATA_SET_THRESHOLD_STYLE(window_edit->data_set); min = AMITK_DATA_SET_THRESHOLD_WINDOW(window_edit->data_set, which_window, AMITK_LIMIT_MIN); max = AMITK_DATA_SET_THRESHOLD_WINDOW(window_edit->data_set, which_window, AMITK_LIMIT_MAX); } else {/* window_edit->preferences != NULL */ threshold_style = AMITK_PREFERENCES_THRESHOLD_STYLE(window_edit->preferences); min = AMITK_PREFERENCES_WINDOW(window_edit->preferences, which_window, AMITK_LIMIT_MIN); max = AMITK_PREFERENCES_WINDOW(window_edit->preferences, which_window, AMITK_LIMIT_MAX); } /* if needed, translate center/window to min/max */ if (threshold_style == AMITK_THRESHOLD_STYLE_CENTER_WIDTH) { if (which_limit == AMITK_LIMIT_MIN) { center = value; window = max-min; } else { /* which_limit == AMITK_LIMIT_MAX */ center = (max+min)/2.0; window = value; } min = center-window/2.0; max = center+window/2.0; } if (window_edit->data_set != NULL) { amitk_data_set_set_threshold_window(window_edit->data_set, which_window, AMITK_LIMIT_MIN,min); amitk_data_set_set_threshold_window(window_edit->data_set, which_window, AMITK_LIMIT_MAX,max); } else {/* window_edit->preferences != NULL */ amitk_preferences_set_default_window(window_edit->preferences, which_window, AMITK_LIMIT_MIN, min); amitk_preferences_set_default_window(window_edit->preferences, which_window, AMITK_LIMIT_MAX, max); } return; } static void insert_window_level_cb (GtkWidget * widget, gpointer data) { AmitkWindowEdit * window_edit = data; AmitkWindow window; g_return_if_fail(AMITK_IS_WINDOW_EDIT(window_edit)); g_return_if_fail(AMITK_IS_DATA_SET(window_edit->data_set)); window = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_window")); amitk_data_set_set_threshold_window(window_edit->data_set, window, AMITK_LIMIT_MIN, AMITK_DATA_SET_THRESHOLD_MIN(window_edit->data_set, 0)); amitk_data_set_set_threshold_window(window_edit->data_set, window, AMITK_LIMIT_MAX, AMITK_DATA_SET_THRESHOLD_MAX(window_edit->data_set, 0)); return; } /* function to update the entry widgets */ static void window_edit_update_entries(AmitkWindowEdit * window_edit) { AmitkLimit i_limit; AmitkWindow i_window; AmitkThresholdStyle threshold_style; amide_data_t center; amide_data_t window; amide_data_t value[AMITK_LIMIT_NUM]; g_return_if_fail(AMITK_IS_WINDOW_EDIT(window_edit)); if (window_edit->data_set != NULL) threshold_style = AMITK_DATA_SET_THRESHOLD_STYLE(window_edit->data_set); else /* window_edit->preferences != NULL */ threshold_style = AMITK_PREFERENCES_THRESHOLD_STYLE(window_edit->preferences); for (i_limit = 0; i_limit < AMITK_LIMIT_NUM; i_limit++) { gtk_label_set_text(GTK_LABEL(window_edit->limit_label[i_limit]), amitk_limit_names[threshold_style][i_limit]); } for (i_window = 0; i_window < AMITK_WINDOW_NUM; i_window++) { for (i_limit = 0; i_limit < AMITK_LIMIT_NUM; i_limit++) if (window_edit->data_set != NULL) value[i_limit] = AMITK_DATA_SET_THRESHOLD_WINDOW(window_edit->data_set, i_window, i_limit); else /* window_edit->preferences != NULL */ value[i_limit] = AMITK_PREFERENCES_WINDOW(window_edit->preferences, i_window, i_limit); /* if needed, switch the values to center/window style */ if (threshold_style == AMITK_THRESHOLD_STYLE_CENTER_WIDTH) { center = (value[AMITK_LIMIT_MAX]+value[AMITK_LIMIT_MIN])/2.0; window = (value[AMITK_LIMIT_MAX]-value[AMITK_LIMIT_MIN]); value[AMITK_LIMIT_MIN] = center; value[AMITK_LIMIT_MAX] = window; } for (i_limit = 0; i_limit < AMITK_LIMIT_NUM; i_limit++) { g_signal_handlers_block_by_func(G_OBJECT(window_edit->window_spin[i_window][i_limit]), G_CALLBACK(window_spin_cb), window_edit); gtk_spin_button_set_value(GTK_SPIN_BUTTON(window_edit->window_spin[i_window][i_limit]), value[i_limit]); g_signal_handlers_unblock_by_func(G_OBJECT(window_edit->window_spin[i_window][i_limit]), G_CALLBACK(window_spin_cb), window_edit); } } return; } /* if data_set is specified, this widget causes and reacts to changes in the corresponding data set. Otherwise, the preferences object will be changed/reacted to. */ GtkWidget * amitk_window_edit_new(AmitkDataSet * data_set, AmitkPreferences * preferences) { AmitkWindowEdit * window_edit; AmitkWindow i_window; g_return_val_if_fail(AMITK_IS_DATA_SET(data_set) || AMITK_IS_PREFERENCES(preferences), NULL); window_edit = g_object_new(amitk_window_edit_get_type (), NULL); if (data_set != NULL) { window_edit->data_set = AMITK_DATA_SET(amitk_object_ref(AMITK_OBJECT(data_set))); g_signal_connect_swapped(G_OBJECT(window_edit->data_set), "threshold_style_changed", G_CALLBACK(window_edit_update_entries), window_edit); g_signal_connect_swapped(G_OBJECT(window_edit->data_set), "windows_changed", G_CALLBACK(window_edit_update_entries), window_edit); for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) gtk_widget_show(window_edit->insert_button[i_window]); } else { /* preferences != NULL */ window_edit->preferences = AMITK_PREFERENCES(g_object_ref(G_OBJECT(preferences))); g_signal_connect_swapped(G_OBJECT(window_edit->preferences), "data_set_preferences_changed", G_CALLBACK(window_edit_update_entries), window_edit); for (i_window=0; i_window < AMITK_WINDOW_NUM; i_window++) gtk_widget_hide(window_edit->insert_button[i_window]); } window_edit_update_entries(window_edit); return GTK_WIDGET (window_edit); } amide-1.0.6/amide-current/src/amitk_window_edit.h000066400000000000000000000044701423227705100220050ustar00rootroot00000000000000/* amitk_window_edit.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2005-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __AMITK_WINDOW_EDIT_H__ #define __AMITK_WINDOW_EDIT_H__ /* includes we always need with this widget */ #include #include G_BEGIN_DECLS #define AMITK_TYPE_WINDOW_EDIT (amitk_window_edit_get_type ()) #define AMITK_WINDOW_EDIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AMITK_TYPE_WINDOW_EDIT, AmitkWindowEdit)) #define AMITK_WINDOW_EDIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AMITK_TYPE_WINDOW_EDIT, AmitkWindowEditClass)) #define AMITK_IS_WINDOW_EDIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AMITK_TYPE_WINDOW_EDIT)) #define AMITK_IS_WINDOW_EDIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AMITK_TYPE_WINDOW_EDIT)) typedef struct _AmitkWindowEdit AmitkWindowEdit; typedef struct _AmitkWindowEditClass AmitkWindowEditClass; struct _AmitkWindowEdit { GtkTable table; GtkWidget * limit_label[AMITK_LIMIT_NUM]; GtkWidget * window_spin[AMITK_WINDOW_NUM][AMITK_LIMIT_NUM]; /* used if a data_set is specified */ AmitkDataSet * data_set; GtkWidget * insert_button[AMITK_WINDOW_NUM]; /* only used if no data_set specified */ AmitkPreferences * preferences; }; struct _AmitkWindowEditClass { GtkVBoxClass parent_class; }; GType amitk_window_edit_get_type (void); GtkWidget* amitk_window_edit_new (AmitkDataSet * data_set, AmitkPreferences * preferences); G_END_DECLS #endif /* __AMITK_WINDOW_EDIT_H__ */ amide-1.0.6/amide-current/src/analysis.c000066400000000000000000000446401423227705100201250ustar00rootroot00000000000000/* analysis.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "analysis.h" #include #include #include #include #ifdef AMIDE_DEBUG #include #endif /* make sure we have NAN defined to at least something */ //0.8.12 - hopefully all systems have bits/nan.h //remove in a couple versions //#ifndef NAN //#define NAN 0.0 //#endif #define EMPTY 0.0 static analysis_gate_t * analysis_gate_unref(analysis_gate_t *gate_analysis); static analysis_gate_t * analysis_gate_init(AmitkRoi * roi, AmitkDataSet *ds,guint frame, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value); static analysis_frame_t * analysis_frame_unref(analysis_frame_t * frame_analysis); static analysis_frame_t * analysis_frame_init(AmitkRoi * roi, AmitkDataSet *ds, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value); static analysis_volume_t * analysis_volume_unref(analysis_volume_t *volume_analysis); static analysis_volume_t * analysis_volume_init(AmitkRoi * roi, GList * volumes, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value); void free_array_element(gpointer data, gpointer user_data) { analysis_element_t * element = data; g_free(element); } static analysis_gate_t * analysis_gate_unref(analysis_gate_t * gate_analysis) { analysis_gate_t * return_list; if (gate_analysis == NULL) return gate_analysis; /* sanity checks */ g_return_val_if_fail(gate_analysis->ref_count > 0, NULL); /* remove a reference count */ gate_analysis->ref_count--; /* if we've removed all reference's, free the roi */ if (gate_analysis->ref_count == 0) { g_ptr_array_foreach(gate_analysis->data_array, free_array_element, NULL); /* free the elements */ g_ptr_array_free(gate_analysis->data_array, TRUE); /* TRUE frees the array of pointers to elements as well */ /* recursively delete rest of list */ return_list = analysis_gate_unref(gate_analysis->next_gate_analysis); gate_analysis->next_gate_analysis = NULL; g_free(gate_analysis); gate_analysis = NULL; } else return_list = gate_analysis; return return_list; } static void record_stats(AmitkVoxel ds_voxel, amide_data_t value, amide_real_t voxel_fraction, gpointer data) { GPtrArray * array = data; analysis_element_t * element; /* crashes if alloc fails, but I don't want to do error checking in the inner loop... let's not run out of memory */ if (voxel_fraction > 0.0) { element = g_malloc(sizeof(analysis_element_t)); element->value = value; element->weight = voxel_fraction; element->ds_voxel = ds_voxel; g_ptr_array_add(array, element); } return; } static gint array_comparison(gconstpointer a, gconstpointer b) { const analysis_element_t * ea = *((analysis_element_t **) a); const analysis_element_t * eb = *((analysis_element_t **) b); if (ea->value > eb->value) return -1; else if (ea->value < eb->value) return 1; else return 0; } /* note, the following function for weight variance calculation is derived from statistics/wvariance_source.c from gsl version 1.3. copyright Jim Davies, Brian Gough, released under GPL. */ /* The variance is divided by N-1, since the mean in a sense is being "estimated" from the data set.... If anyone else with more statistical experience disagrees, please speak up */ static gdouble wvariance (GPtrArray * array, guint num_elements, gdouble wmean) { analysis_element_t * element; gdouble wsumofsquares = 0 ; gdouble Wa = 0; gdouble Wb = 0; gdouble wi; gdouble delta; gdouble factor; guint i; if (num_elements < 2) return NAN; /* find the weight sum of the squares */ /* computes sum(wi*(valuei-mean))/sum(wi) */ /* and computes the weighted version of N/(N-1) */ for (i = 0; i < num_elements; i++) { element = g_ptr_array_index(array, i); wi = element->weight; if (wi > 0) { delta = element->value-wmean; Wa += wi ; Wb += wi*wi; wsumofsquares += (delta * delta - wsumofsquares) * (wi / Wa); } } factor = (Wa*Wa)/((Wa*Wa)-Wb); return factor*wsumofsquares; } /* calculate an analysis of several statistical values for an roi on a given data set frame/gate. */ static analysis_gate_t * analysis_gate_init_recurse(AmitkRoi * roi, AmitkDataSet * ds, guint frame, guint gate, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value) { GPtrArray * data_array; analysis_gate_t * analysis; guint subfraction_voxels; guint i; analysis_element_t * element; gdouble max; gboolean done; #ifdef AMIDE_DEBUG struct timeval tv1; struct timeval tv2; gdouble time1; gdouble time2; /* let's do some timing */ gettimeofday(&tv1, NULL); #endif if (gate == AMITK_DATA_SET_NUM_GATES(ds)) return NULL; /* check if we're done */ /* and now calculate this gate's data */ if ((data_array = g_ptr_array_new()) == NULL) { g_warning(_("couldn't allocate memory space for data array for frame %d/gate %d"), frame, gate); return NULL; } /* fill the array with the appropriate info from the data set */ /* note, I really only need a partial sort to get the median value, but glib doesn't have one (only has a full qsort), so I'll just do that. Partial sort would be order(N), qsort is order(NlogN), so it's not that much worse. If I used a partial sort, I'd have to iterate over the subfraction to find the max and min, and I'd have to do another partial sort to find the median */ amitk_roi_calculate_on_data_set(roi, ds, frame, gate,FALSE, accurate, record_stats, data_array); g_ptr_array_sort(data_array, array_comparison); switch(calculation_type) { case ALL_VOXELS: subfraction_voxels = data_array->len; break; case HIGHEST_FRACTION_VOXELS: subfraction_voxels = ceil(subfraction*data_array->len); if ((subfraction_voxels == 0) && (data_array->len > 0)) subfraction_voxels = 1; /* have at least one voxel if the roi is in the data set*/ break; case VOXELS_NEAR_MAX: subfraction_voxels = 0; if (data_array->len > 0) { element = g_ptr_array_index(data_array, 0); max = element->value; done = FALSE; for (i=0; ilen && !done; i++) { element = g_ptr_array_index(data_array, i); if (element->value >= max*threshold_percentage/100.0) subfraction_voxels++; else done = TRUE; } } if ((subfraction_voxels == 0) && (data_array->len > 0)) subfraction_voxels = 1; /* have at least one voxel if the roi is in the data set*/ break; case VOXELS_GREATER_THAN_VALUE: subfraction_voxels = 0; if (data_array->len > 0) { element = g_ptr_array_index(data_array, 0); max = element->value; done = FALSE; for (i=0; ilen && !done; i++) { element = g_ptr_array_index(data_array, i); if (element->value >= threshold_value) subfraction_voxels++; else done = TRUE; } } break; default: subfraction_voxels=0; g_error("unexpected case in %s at line %d",__FILE__, __LINE__); } /* fill in our gate_analysis structure */ if ((analysis = g_try_new(analysis_gate_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for roi analysis of frame %d/gate %d"), frame, gate); return analysis; } analysis->ref_count = 1; /* set values */ analysis->data_array = data_array; analysis->duration = amitk_data_set_get_frame_duration(ds, frame); analysis->time_midpoint = amitk_data_set_get_midpt_time(ds, frame); analysis->gate_time = amitk_data_set_get_gate_time(ds, gate); analysis->total = 0.0; analysis->median = 0.0; analysis->total = 0.0; analysis->voxels = subfraction_voxels; analysis->fractional_voxels = 0.0; analysis->correction = 0.0; analysis->var = 0.0; if (subfraction_voxels == 0) { /* roi not in data set */ analysis->max = 0.0; analysis->min = 0.0; analysis->median = 0.0; analysis->mean = 0.0; } else { /* max */ element = g_ptr_array_index(data_array, 0); analysis->max = element->value; /* min */ element = g_ptr_array_index(data_array, subfraction_voxels-1); analysis->min = element->value; /* median */ if (subfraction_voxels & 0x1) { /* odd */ element = g_ptr_array_index(data_array, (subfraction_voxels-1)/2); analysis->median = element->value; } else { /* even */ element = g_ptr_array_index(data_array, subfraction_voxels/2-1); analysis->median = 0.5*element->value; element = g_ptr_array_index(data_array, subfraction_voxels/2); analysis->median += 0.5*element->value; } /* total and #fractional_voxels */ for (i=0; itotal += element->weight*element->value; analysis->fractional_voxels += element->weight; } /* calculate the mean */ analysis->mean = analysis->total/analysis->fractional_voxels; /* calculate variance */ analysis->var = wvariance(data_array, subfraction_voxels, analysis->mean); } #ifdef AMIDE_DEBUG /* and wrapup our timing */ gettimeofday(&tv2, NULL); time1 = ((double) tv1.tv_sec) + ((double) tv1.tv_usec)/1000000.0; time2 = ((double) tv2.tv_sec) + ((double) tv2.tv_usec)/1000000.0; g_print("Calculated ROI: %s on Data Set: %s Frame %d Gate %d. Took %5.3f (s) \n", AMITK_OBJECT_NAME(roi), AMITK_OBJECT_NAME(ds), frame, gate, time2-time1); #endif /* now let's recurse */ analysis->next_gate_analysis = analysis_gate_init_recurse(roi, ds, frame, gate+1, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); return analysis; } static analysis_gate_t * analysis_gate_init(AmitkRoi * roi, AmitkDataSet * ds, guint frame, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value) { return analysis_gate_init_recurse(roi, ds, frame, 0, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); } static analysis_frame_t * analysis_frame_unref(analysis_frame_t * frame_analysis) { analysis_frame_t * return_list; if (frame_analysis == NULL) return frame_analysis; /* sanity checks */ g_return_val_if_fail(frame_analysis->ref_count > 0, NULL); /* remove a reference count */ frame_analysis->ref_count--; /* if we've removed all reference's, free the roi */ if (frame_analysis->ref_count == 0) { /* recursively delete rest of list */ return_list = analysis_frame_unref(frame_analysis->next_frame_analysis); frame_analysis->next_frame_analysis = NULL; frame_analysis->gate_analyses = analysis_gate_unref(frame_analysis->gate_analyses); g_free(frame_analysis); frame_analysis = NULL; } else return_list = frame_analysis; return return_list; } /* returns a calculated analysis structure of an roi on a frame of a data set */ static analysis_frame_t * analysis_frame_init_recurse(AmitkRoi * roi, AmitkDataSet *ds, guint frame, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value) { analysis_frame_t * temp_frame_analysis; if (frame == AMITK_DATA_SET_NUM_FRAMES(ds)) return NULL; /* check if we're done */ if ((temp_frame_analysis = g_try_new(analysis_frame_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for roi analysis of frames")); return NULL; } temp_frame_analysis->ref_count = 1; /* calculate this one */ temp_frame_analysis->gate_analyses = analysis_gate_init(roi, ds, frame, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); /* recurse */ temp_frame_analysis->next_frame_analysis = analysis_frame_init_recurse(roi, ds, frame+1, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); return temp_frame_analysis; } static analysis_frame_t * analysis_frame_init(AmitkRoi * roi, AmitkDataSet *ds, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value) { /* sanity checks */ g_return_val_if_fail(AMITK_IS_DATA_SET(ds), NULL); if (AMITK_ROI_UNDRAWN(roi)) { g_warning(_("ROI: %s appears not to have been drawn"), AMITK_OBJECT_NAME(roi)); return NULL; } return analysis_frame_init_recurse(roi, ds, 0, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); } /* free up an roi analysis over a data set */ static analysis_volume_t * analysis_volume_unref(analysis_volume_t * volume_analysis) { analysis_volume_t * return_list; if (volume_analysis == NULL) return volume_analysis; /* sanity check */ g_return_val_if_fail(volume_analysis->ref_count > 0, NULL); /* remove a reference count */ volume_analysis->ref_count--; /* stuff to do if reference count is zero */ if (volume_analysis->ref_count == 0) { /* recursively delete rest of list */ return_list = analysis_volume_unref(volume_analysis->next_volume_analysis); volume_analysis->next_volume_analysis = NULL; volume_analysis->frame_analyses = analysis_frame_unref(volume_analysis->frame_analyses); if (volume_analysis->data_set != NULL) volume_analysis->data_set=amitk_object_unref(volume_analysis->data_set); g_free(volume_analysis); volume_analysis = NULL; } else return_list = volume_analysis; return return_list; } /* returns an initialized roi analysis of a list of volumes */ static analysis_volume_t * analysis_volume_init(AmitkRoi * roi, GList * data_sets, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value) { analysis_volume_t * temp_volume_analysis; if (data_sets == NULL) return NULL; g_return_val_if_fail(AMITK_IS_DATA_SET(data_sets->data), NULL); if ((temp_volume_analysis = g_try_new(analysis_volume_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for roi analysis of volumes")); return NULL; } temp_volume_analysis->ref_count = 1; temp_volume_analysis->data_set = amitk_object_ref(data_sets->data); /* calculate this one */ temp_volume_analysis->frame_analyses = analysis_frame_init(roi, temp_volume_analysis->data_set, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); /* recurse */ temp_volume_analysis->next_volume_analysis = analysis_volume_init(roi, data_sets->next, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); return temp_volume_analysis; } /* free up a list of roi analyses */ analysis_roi_t * analysis_roi_unref(analysis_roi_t * roi_analysis) { analysis_roi_t * return_list; if (roi_analysis == NULL) return roi_analysis; /* sanity check */ g_return_val_if_fail(roi_analysis->ref_count > 0, NULL); /* remove a reference count */ roi_analysis->ref_count--; /* stuff to do if reference count is zero */ if (roi_analysis->ref_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing roi_analysis\n"); #endif /* recursively free/dereference rest of list */ return_list = analysis_roi_unref(roi_analysis->next_roi_analysis); roi_analysis->next_roi_analysis = NULL; roi_analysis->volume_analyses = analysis_volume_unref(roi_analysis->volume_analyses); if (roi_analysis->roi != NULL) roi_analysis->roi = amitk_object_unref(roi_analysis->roi); if (roi_analysis->study != NULL) roi_analysis->study = amitk_object_unref(roi_analysis->study); g_free(roi_analysis); roi_analysis = NULL; } else return_list = roi_analysis; return return_list; } /* returns an initialized list of roi analyses */ analysis_roi_t * analysis_roi_init(AmitkStudy * study, GList * rois, GList * data_sets, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value) { analysis_roi_t * temp_roi_analysis; if (rois == NULL) return NULL; if ((temp_roi_analysis = g_try_new(analysis_roi_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for roi analyses")); return NULL; } temp_roi_analysis->ref_count = 1; temp_roi_analysis->roi = amitk_object_ref(rois->data); temp_roi_analysis->study = amitk_object_ref(study); temp_roi_analysis->calculation_type = calculation_type; temp_roi_analysis->accurate = accurate; temp_roi_analysis->subfraction = subfraction; temp_roi_analysis->threshold_percentage = threshold_percentage; temp_roi_analysis->threshold_value = threshold_value; /* calculate this one */ temp_roi_analysis->volume_analyses = analysis_volume_init(temp_roi_analysis->roi, data_sets, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); /* recurse */ temp_roi_analysis->next_roi_analysis = analysis_roi_init(study, rois->next, data_sets, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); return temp_roi_analysis; } amide-1.0.6/amide-current/src/analysis.h000066400000000000000000000063651423227705100201340ustar00rootroot00000000000000/* analysis.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __ANALYSIS_H__ #define __ANALYSIS_H__ /* header files that are always needed with this file */ #include "amitk_study.h" /* defines */ /* typedefs, etc. */ typedef enum { ALL_VOXELS, HIGHEST_FRACTION_VOXELS, VOXELS_NEAR_MAX, VOXELS_GREATER_THAN_VALUE, NUM_CALCULATION_TYPES } analysis_calculation_t; typedef struct _analysis_gate_t analysis_gate_t; typedef struct _analysis_frame_t analysis_frame_t; typedef struct _analysis_volume_t analysis_volume_t; typedef struct _analysis_roi_t analysis_roi_t; typedef struct _analysis_study_t analysis_study_t; typedef struct analysis_element_t { amide_data_t value; amide_real_t weight; AmitkVoxel ds_voxel; } analysis_element_t; struct _analysis_gate_t { /* roi data - array of analysis_element's */ GPtrArray * data_array; /* stats */ amide_data_t mean; amide_data_t median; guint voxels; amide_real_t fractional_voxels; amide_data_t var; amide_data_t min; amide_data_t max; amide_data_t total; /* info */ amide_time_t duration; amide_time_t time_midpoint; amide_time_t gate_time; /* internal */ amide_data_t correction; analysis_gate_t * next_gate_analysis; guint ref_count; }; struct _analysis_frame_t { analysis_gate_t * gate_analyses; guint ref_count; analysis_frame_t * next_frame_analysis; }; struct _analysis_volume_t { AmitkDataSet * data_set; analysis_frame_t * frame_analyses; guint ref_count; analysis_volume_t * next_volume_analysis; }; struct _analysis_roi_t { AmitkRoi * roi; AmitkStudy * study; analysis_calculation_t calculation_type; gboolean accurate; gdouble subfraction; gdouble threshold_percentage; gdouble threshold_value; analysis_volume_t * volume_analyses; guint ref_count; analysis_roi_t * next_roi_analysis; }; /* external functions */ analysis_roi_t * analysis_roi_unref(analysis_roi_t *roi_analysis); /* note, subfraction is only used for calculation_type == HIGHEST_FRACTION_VOXELS, threshold_percentage is only used for calculation_type == VOXELS_NEAR_MAX threshold_value is only used for calculation_type == HIGHER_THAN_VALUE */ analysis_roi_t * analysis_roi_init(AmitkStudy * study, GList * rois, GList * volumes, analysis_calculation_t calculation_type, gboolean accurate, gdouble subfraction, gdouble threshold_percentage, gdouble threshold_value); #endif /* __ANALYSIS_H__ */ amide-1.0.6/amide-current/src/dcmtk_interface.cc000066400000000000000000003361561423227705100215750ustar00rootroot00000000000000/* dcmtk_interface.cc * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2005-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBDCMDATA_SUPPORT #ifdef HAVE_STRPTIME #define __USE_XOPEN_EXTENDED #endif #ifdef OLD_WIN32_HACKS #include #endif #include "dcmtk_interface.h" #include #include #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include /* make sure we get g_mkdir on mingw32 */ /* dcmtk redefines a lot of things that they shouldn't... */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION //#define HAVE_CONFIG_H /* the autoconf compiled version of DCMTK has a config header file */ #include /* for class DicomDirInterface */ #include #include /* for RLE decoders */ #include "dcmtk/dcmjpeg/djdecode.h" /* for dcmjpeg decoders */ #ifdef AMIDE_LIBOPENJP2_SUPPORT #include /* JPG2000 make sure OS specific configuration is included first */ #include #include #include static void * j2k_to_raw(DcmDataset *pdata, AmitkDataSet const *pds); #endif const gchar * dcmtk_version = OFFIS_DCMTK_VERSION; /* based on dcmftest.cc - part of dcmtk */ gboolean dcmtk_test_dicom(const gchar * filename) { FILE * file; gchar signature[4]; gboolean is_dicom; g_return_val_if_fail(filename != NULL, FALSE); if ((file = fopen(filename, "rb")) == NULL) return FALSE; if ((fseek(file, DCM_PreambleLen, SEEK_SET) < 0) || (fread(signature, 1, DCM_MagicLen, file) != DCM_MagicLen)) { is_dicom = FALSE; } else if (strncmp(signature, DCM_Magic, DCM_MagicLen) != 0) { is_dicom = FALSE; } else { is_dicom = TRUE; } fclose(file); return is_dicom; } static AmitkDataSet * read_dicom_file(const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, gint *pnum_frames, gint *pnum_gates, gint *pnum_slices, AmitkUpdateFunc update_func, gpointer update_data, gchar **perror_buf) { DcmFileFormat dcm_format; DcmMetaInfo * dcm_metainfo; DcmXfer *dcm_syntax=NULL; DcmDataset * dcm_dataset; OFCondition result; Uint16 return_uint16=0; Sint32 return_sint32=0; Sint16 return_sint16=0; Float64 return_float64=0.0; Float64 rescale_slope=1.0; Uint16 bits_allocated; Uint16 pixel_representation; const char * return_str=NULL; const char * scan_date=NULL; const char * scan_time=NULL; gchar * temp_str; gboolean valid; gboolean valid_J2K=FALSE; AmitkPoint voxel_size = one_point; AmitkDataSet * ds=NULL; AmitkModality modality; AmitkVoxel dim; AmitkVoxel i; AmitkFormat format; gboolean continue_work=TRUE; gboolean found_value; const void * buffer=NULL; void * ds_pointer; /* long unsigned num_bytes; */ gint format_size; AmitkPoint new_offset; AmitkAxes new_axes; AmitkPoint direction; amide_time_t acquisition_start_time=-1.0; amide_time_t dose_time=-1.0; amide_time_t decay_time=-1.0; gdouble decay_value; gdouble half_life=-1.0; gint hours, minutes, seconds; struct tm time_structure; /* note - dcmtk always uses POSIX locale - look to setlocale stuff in libmdc_interface.c if this ever comes up*/ result = dcm_format.loadFile(filename); if (result.bad()) { g_warning(_("could not read DICOM file %s, dcmtk returned %s"),filename, result.text()); goto error; } dcm_metainfo = dcm_format.getMetaInfo(); if (dcm_metainfo == NULL) { g_warning(_("could not find metainfo in DICOM file %s\n"), filename); } dcm_dataset = dcm_format.getDataset(); if (dcm_dataset == NULL) { g_warning(_("could not find dataset in DICOM file %s\n"), filename); goto error; } if (dcm_metainfo == NULL) { dcm_syntax = new DcmXfer(dcm_dataset->getOriginalXfer()); } else { /* What TransSyntax is used to encode the image */ if (dcm_metainfo->findAndGetString(DCM_TransferSyntaxUID, return_str).good()) { if (return_str != NULL) { // g_debug("TransferSyntaxUID %s", return_str); dcm_syntax = new DcmXfer(return_str); } } } if (dcm_syntax == NULL) { g_warning(_("could not determine TransferSyntax %s\n"), filename); goto error; } // g_debug("TransferSyntax is %s (%d)", dcm_syntax->getXferName(), dcm_syntax->getXfer()); modality = AMITK_MODALITY_OTHER; if (dcm_dataset->findAndGetString(DCM_Modality, return_str).good()) { if (return_str != NULL) { /* first, process modalities we know we don't read */ if ((g_ascii_strcasecmp(return_str, "PR") == 0)) { amitk_append_str_with_newline(perror_buf, _("Modality %s is not understood. Ignoring File %s"), return_str, filename); goto error; } /* now to modalities we think we understand */ if ((g_ascii_strcasecmp(return_str, "CR") == 0) || (g_ascii_strcasecmp(return_str, "CT") == 0) || (g_ascii_strcasecmp(return_str, "DF") == 0) || (g_ascii_strcasecmp(return_str, "DS") == 0) || (g_ascii_strcasecmp(return_str, "DX") == 0) || (g_ascii_strcasecmp(return_str, "MG") == 0) || (g_ascii_strcasecmp(return_str, "PX") == 0) || (g_ascii_strcasecmp(return_str, "RF") == 0) || (g_ascii_strcasecmp(return_str, "RG") == 0) || (g_ascii_strcasecmp(return_str, "XA") == 0) || (g_ascii_strcasecmp(return_str, "XA") == 0)) modality = AMITK_MODALITY_CT; else if ((g_ascii_strcasecmp(return_str, "MA") == 0) || (g_ascii_strcasecmp(return_str, "MR") == 0) || (g_ascii_strcasecmp(return_str, "MS") == 0)) modality = AMITK_MODALITY_MRI; else if ((g_ascii_strcasecmp(return_str, "ST") == 0) || (g_ascii_strcasecmp(return_str, "NM") == 0)) modality = AMITK_MODALITY_SPECT; else if ((g_ascii_strcasecmp(return_str, "PT") == 0)) modality = AMITK_MODALITY_PET; } } /* register global decompression codecs */ DJDecoderRegistration::registerCodecs(EDC_photometricInterpretation, EUC_default, EPC_default, OFFalse); DcmRLEDecoderRegistration::registerCodecs(); /* uncompress the raw data in case this is a JPEG encoded file */ result = dcm_dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL); if (result.bad()) { /* check if this is JPEG2000, which is not currently freely supported by dcmtk */ return_str = dcm_syntax->getXferID(); if (return_str != NULL) if ((strcmp(return_str, UID_JPEG2000LosslessOnlyTransferSyntax) == 0) || (strcmp(return_str, UID_JPEG2000TransferSyntax) == 0) || (strcmp(return_str, UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax) == 0) || (strcmp(return_str, UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax) == 0)) valid_J2K = TRUE; if (!valid_J2K) { g_warning(_("could not decompress data in DICOM file %s, dcmtk returned %s"), filename, result.text()); goto error; } } /* get basic data */ if (dcm_dataset->findAndGetUint16(DCM_Columns, return_uint16).bad()) { g_warning(_("could not find # of columns - Failed to load file %s\n"), filename); goto error; } dim.x = return_uint16; if (dcm_dataset->findAndGetUint16(DCM_Rows, return_uint16).bad()) { g_warning(_("could not find # of rows - Failed to load file %s\n"), filename); goto error; } dim.y = return_uint16; /* number of slices */ /* note, number of "Frames" is the number of frames of data within the single DICOM file that do not have repeated header information, it does not refer necessarily to the number of time frames as is the convention for nuclear medicine. The DICOM tag NumberOfSlices is the number of slices in the study, not the number in the particular DICOM file, so it's not what we want to be using. */ if (dcm_dataset->findAndGetString(DCM_NumberOfFrames, return_str, OFTrue).bad()) { /* note, I've never actually seen a DICOM file that uses the DCM_Planes tag, it's now retired */ if (dcm_dataset->findAndGetUint16(DCM_RETIRED_Planes, return_uint16).bad()) dim.z = 1; else dim.z = return_uint16; } else { if (return_str != NULL) { if (sscanf(return_str, "%d", &(return_sint32)) != 1) g_warning("could not process NumberOfFrames - Failed to load file %s\n", filename); dim.z = return_sint32; if (dim.z < 1) g_warning("in correct NumberOf Frames (%d) - Failed to load file %s\n", dim.z, filename); } } // g_debug("Number of frames: %d (%d x %d px.)", dim.z, dim.x, dim.y); dim.t = 1; /* no support for multiple time frame of data in a single file */ dim.g = 1; /* no support for multiple gates in a single file */ /* TimeSlices can also indicate # of bed positions, so only use for number of frames if this is explicitly a DYNAMIC data set */ if (dcm_dataset->findAndGetString(DCM_SeriesType, return_str, OFTrue).good()) if (return_str != NULL) if (strstr(return_str, "DYNAMIC") != NULL) if (dcm_dataset->findAndGetUint16(DCM_NumberOfTimeSlices, return_uint16).good()) *pnum_frames = return_uint16; if (dcm_dataset->findAndGetString(DCM_SeriesType, return_str, OFTrue).good()) if (return_str != NULL) if (strstr(return_str, "GATED\\IMAGE") != NULL) if (dcm_dataset->findAndGetUint16(DCM_NumberOfTimeSlots, return_uint16).good()) *pnum_gates = return_uint16; /* some files use NumberOfTemporalPositions */ if (*pnum_gates == 1) if (dcm_dataset->findAndGetSint32(DCM_NumberOfTemporalPositions, return_sint32).good()) if (return_sint32 > 0) *pnum_gates = return_sint32; /* record how many slices in each volume. Used if there is an inconsistent between the number of gates and total number of images */ /* 0x0021,0x104f corresponds to LocationsInAcquisition */ if (dcm_dataset->findAndGetSint16(DcmTagKey(0x0021, 0x104f), return_sint16).good()) if (return_sint16 > 0) *pnum_slices = return_sint16; if (dcm_dataset->findAndGetUint16(DCM_BitsAllocated, return_uint16).bad()) { g_warning(_("could not find # of bits allocated - Failed to load file %s\n"), filename); goto error; } bits_allocated = return_uint16; if (dcm_dataset->findAndGetUint16(DCM_PixelRepresentation, return_uint16).bad()) { g_warning(_("could not find pixel representation - Failed to load file %s\n"), filename); goto error; } pixel_representation = return_uint16; switch(bits_allocated) { case 8: if (pixel_representation) format = AMITK_FORMAT_SBYTE; else format = AMITK_FORMAT_UBYTE; break; case 16: if (pixel_representation) format = AMITK_FORMAT_SSHORT; else format = AMITK_FORMAT_USHORT; break; case 32: /* DICOM doesn't actually support anything but 8 and 16bit */ if (pixel_representation) format = AMITK_FORMAT_SINT; else format = AMITK_FORMAT_UINT; break; default: g_warning(_("unsupported # of bits allocated (%d) - Failed to load file %s\n"), bits_allocated, filename); goto error; } /* malloc data set, including raw_data->data=g_try_malloc(amitk_raw_data_num_voxels(rd) * amitk_format_sizes[(rd)->format]) amitk_raw_data_num_voxels(rd) = ((rd)->dim.x * (rd)->dim.y * (rd)->dim.z * (rd)->dim.g * (rd)->dim.t) */ ds = amitk_data_set_new_with_data(preferences, modality, format, dim, AMITK_SCALING_TYPE_0D_WITH_INTERCEPT); if (ds == NULL) { g_warning(_("Couldn't allocate space for the data set structure to hold DCMTK data - Failed to load file %s"), filename); goto error; } /* get the series number */ if (dcm_dataset->findAndGetSint32(DCM_SeriesNumber, return_sint32).good()) amitk_data_set_set_series_number(ds, return_sint32); /* get the dicom image type, we don't do anything with this, but we store it in case we're going to export this data set as DICOM data */ if (dcm_dataset->findAndGetString(DCM_ImageType, return_str).good()) amitk_data_set_set_dicom_image_type(ds, return_str); /* function can handle NULL strings */ /* get the voxel size */ if (dcm_dataset->findAndGetFloat64(DCM_PixelSpacing, return_float64, 0, OFTrue).good()) { voxel_size.y = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_PixelSpacing, return_float64,1, OFTrue).good()) voxel_size.x = return_float64; else { voxel_size.x = voxel_size.y; } } else { amitk_append_str_with_newline(perror_buf, _("Could not find the pixel size, setting to 1 mm for File %s"), filename); } /* try to figure out the correct z thickness */ voxel_size.z = -1; if (dcm_dataset->findAndGetFloat64(DCM_SpacingBetweenSlices, return_float64, 0, OFTrue).good()) voxel_size.z = return_float64; if (voxel_size.z <= 0.0) { if (dcm_dataset->findAndGetFloat64(DCM_SliceThickness, return_float64, 0, OFTrue).good()) { voxel_size.z = return_float64; } else { amitk_append_str_with_newline(perror_buf, _("Could not find the slice thickness, setting to 1 mm for File %s"), filename); voxel_size.z = 1; } } // g_debug("Voxel size (mm): %f x %f x %f", voxel_size.x, voxel_size.y, voxel_size.z); /* store this number, occasionally used in sorting */ if (dcm_dataset->findAndGetSint32(DCM_InstanceNumber, return_sint32).good()) ds->instance_number = return_sint32; /* DICOM coordinates are LPH+, meaning that x increases toward patient left, y increases towards patient posterior, and z increases toward patient head. AMIDE is LAF+ */ /* ImageOrientationPatient contains a vector along the row direction, as well as the column direction, note though that the column direction in DICOM is in the wrong direction - it's from top to bottom, the z axis is off as well */ new_axes[AMITK_AXIS_X] = base_axes[AMITK_AXIS_X]; new_axes[AMITK_AXIS_Y] = base_axes[AMITK_AXIS_Y]; new_axes[AMITK_AXIS_Z] = base_axes[AMITK_AXIS_Z]; if (dcm_dataset->findAndGetFloat64(DCM_ImageOrientationPatient, return_float64, 0, OFTrue).good()) { new_axes[AMITK_AXIS_X].x = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImageOrientationPatient, return_float64, 1, OFTrue).good()) { new_axes[AMITK_AXIS_X].y = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImageOrientationPatient, return_float64, 2, OFTrue).good()) { new_axes[AMITK_AXIS_X].z = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImageOrientationPatient, return_float64, 3, OFTrue).good()) { new_axes[AMITK_AXIS_Y].x = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImageOrientationPatient, return_float64, 4, OFTrue).good()) { new_axes[AMITK_AXIS_Y].y = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImageOrientationPatient, return_float64, 5, OFTrue).good()) { new_axes[AMITK_AXIS_Y].z = return_float64; } } } } } } else { g_warning(_("Couldn't find ImageOrientationPatient in file %s"), filename); } new_axes[AMITK_AXIS_X].y *= -1.0; new_axes[AMITK_AXIS_X].z *= -1.0; new_axes[AMITK_AXIS_Y].y *= -1.0; new_axes[AMITK_AXIS_Y].z *= -1.0; POINT_CROSS_PRODUCT(new_axes[AMITK_AXIS_X], new_axes[AMITK_AXIS_Y], new_axes[AMITK_AXIS_Z]); amitk_space_set_axes(AMITK_SPACE(ds), new_axes, zero_point); /* note, ImagePositionPatient is suppose to be defined as the center of the upper left hand voxel in Patient space, not necessarily with respect to the Gantry. At least for GE scanners, the offset is on corner of this voxel */ found_value=FALSE; if (dcm_dataset->findAndGetFloat64(DCM_ImagePositionPatient, return_float64, 0, OFTrue).good()) { new_offset.x = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImagePositionPatient, return_float64, 1, OFTrue).good()) { new_offset.y = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_ImagePositionPatient, return_float64, 2, OFTrue).good()) { new_offset.z = return_float64; /* not doing the half voxel correction... values seem more correct without, at least for GE. If this was not the case, the code would be: new_offset.x -= 0.5*voxel_size.x; new_offset.y -= 0.5*voxel_size.y; new_offset.z -= 0.5*voxel_size.z; */ /* Offset seems to be in base coordinate space, otherwise the code would be amitk_space_set_offset(AMITK_SPACE(ds), amitk_space_s2b(AMITK_SPACE(ds), new_offset)); */ new_offset.y = -1.0*new_offset.y; /* DICOM specifies y axis in wrong direction */ new_offset.z = -1.0*new_offset.z; /* DICOM specifies z axis in wrong direction */ amitk_space_set_offset(AMITK_SPACE(ds), new_offset); found_value=TRUE; } } } if (!found_value) { /* see if we can get it otherwise */ if (dcm_dataset->findAndGetFloat64(DCM_SliceLocation, return_float64, 0, OFTrue).good()) { /* if no ImagePositionPatient, try using SliceLocation */ new_offset.x = new_offset.y = 0.0; //this looks wrong 2007.11.21 - doing what's done in the DCM_ImagePositionPatient case // new_offset.z = -1.0*(return_float64+voxel_size.z*dim.z); /* DICOM specifies z axis in wrong direction */ new_offset.z = -1.0*return_float64; /* DICOM specifies z axis in wrong direction */ amitk_space_set_offset(AMITK_SPACE(ds), new_offset); found_value=TRUE; } } if (!found_value) { g_warning(_("Couldn't find ImagePositionPatient nor SliceLocation in file %s"), filename); } amitk_data_set_set_voxel_size(ds, voxel_size); amitk_data_set_calc_far_corner(ds); if (dcm_dataset->findAndGetString(DCM_PatientID, return_str, OFTrue).good()) amitk_data_set_set_subject_id(ds, return_str); if (dcm_dataset->findAndGetFloat64(DCM_PatientWeight, return_float64).good()) { amitk_data_set_set_subject_weight(ds, return_float64); amitk_data_set_set_displayed_weight_unit(ds, AMITK_WEIGHT_UNIT_KILOGRAM); } /* any MRI parameters we may need */ if (dcm_dataset->findAndGetFloat64(DCM_InversionTime, return_float64).good()) amitk_data_set_set_inversion_time(ds, return_float64); if (dcm_dataset->findAndGetFloat64(DCM_EchoTime, return_float64).good()) amitk_data_set_set_echo_time(ds, return_float64); if (dcm_dataset->findAndGetFloat64(DCM_DiffusionBValue, return_float64, 0, OFTrue).good()) { amitk_data_set_set_diffusion_b_value(ds, return_float64); } else if (dcm_dataset->findAndGetSint32(DcmTagKey(0x0043, 0x1039), return_sint32, 0, OFTrue).good()) { /* GE */ amitk_data_set_set_diffusion_b_value(ds, return_sint32); } /* diffusion directions */ direction = zero_point; if (dcm_dataset->findAndGetFloat64(DCM_DiffusionGradientOrientation, return_float64, 0, OFTrue).good()) direction.x = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_DiffusionGradientOrientation, return_float64, 1, OFTrue).good()) direction.y = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_DiffusionGradientOrientation, return_float64, 2, OFTrue).good()) direction.z = return_float64; /* following works for GE.... */ if (POINT_EQUAL(direction, zero_point)) { if (dcm_dataset->findAndGetFloat64(DcmTagKey(0x0019, 0x10bb), return_float64, 0, OFTrue).good()) direction.x = return_float64; if (dcm_dataset->findAndGetFloat64(DcmTagKey(0x0019, 0x10bc), return_float64, 0, OFTrue).good()) direction.y = return_float64; if (dcm_dataset->findAndGetFloat64(DcmTagKey(0x0019, 0x10bd), return_float64, 0, OFTrue).good()) direction.z = return_float64; } amitk_data_set_set_diffusion_direction(ds, direction); /* store the gate time if possible, DICOM stores this as milliseconds */ if (dcm_dataset->findAndGetFloat64(DCM_TriggerTime, return_float64).good()) amitk_data_set_set_gate_time(ds, 0, return_float64/1000.0); else amitk_data_set_set_gate_time(ds, 0, 0.0); /* and get the Temporal position, DICOM uses this with gated MR images */ if (dcm_dataset->findAndGetSint32(DCM_TemporalPositionIdentifier, return_sint32).good()) ds->gate_num=return_sint32; else ds->gate_num=-1; /* find the most relevant start time */ return_str = NULL; if (!dcm_dataset->findAndGetString(DCM_SeriesTime, return_str, OFTrue).good()) if (!dcm_dataset->findAndGetString(DCM_AcquisitionTime, return_str, OFTrue).good()) dcm_dataset->findAndGetString(DCM_StudyTime, return_str, OFTrue); if (return_str != NULL) { if (sscanf(return_str, "%2d%2d%2d\n", &hours, &minutes, &seconds)==3) { acquisition_start_time = ((hours*60)+minutes)*60+seconds; } } if (dcm_dataset->findAndGetString(DCM_RadiopharmaceuticalStartTime, return_str, OFTrue).good()) if (return_str != NULL) if (sscanf(return_str, "%2d%2d%2d\n", &hours, &minutes, &seconds)==3) dose_time = ((hours*60)+minutes)*60+seconds; if ((dose_time >= 0.0) && (acquisition_start_time >= 0.0)) { /* correct for if the dose was measured the previous day... note, DICOM can't seem to handle dose measured more than 24hours in the past */ if (acquisition_start_time > dose_time) decay_time = acquisition_start_time-dose_time; else decay_time = acquisition_start_time+24*60*60-dose_time; } if (dcm_dataset->findAndGetFloat64(DCM_RadionuclideHalfLife, return_float64, 0, OFTrue).good()) half_life = return_float64; if (dcm_dataset->findAndGetFloat64(DCM_RadionuclideTotalDose, return_float64, 0, OFTrue).good()) { /* note, for NM data sets, total dose is in MBq. For PET data sets total dose is suppose to be in Bq. However, it seems that the value is sometimes in the wrong units, at least for GE data. */ decay_value = return_float64; if (decay_value > 10000.0) decay_value /= 1E6; /* if more than 10000, assume its in Bq, and convert */ if ((decay_time > 0.0) && (half_life > 0.0)) decay_value *= pow(0.5, decay_time/half_life); amitk_data_set_set_injected_dose(ds, decay_value); amitk_data_set_set_displayed_dose_unit(ds, AMITK_DOSE_UNIT_MEGABECQUEREL); } if (dcm_dataset->findAndGetString(DCM_Units, return_str, OFTrue).good()) { if (return_str != NULL) { /* BQML - voxel values are in Bq per ml */ if (strcmp(return_str, "BQML")==0) { amitk_data_set_set_cylinder_factor(ds,1.0/1.0E6); amitk_data_set_set_displayed_cylinder_unit(ds, AMITK_CYLINDER_UNIT_MEGABECQUEREL_PER_CC_IMAGE_UNIT); } } } if (dcm_dataset->findAndGetString(DCM_StudyDescription, return_str, OFTrue).good()) { amitk_object_set_name(AMITK_OBJECT(ds), return_str); if (pstudyname != NULL) *pstudyname = g_strdup(return_str); } if (dcm_dataset->findAndGetString(DCM_SeriesDescription, return_str, OFTrue).good()) { /* note, this overwrites the name set immediately above based on StudyDescription */ if (return_str != NULL) amitk_object_set_name(AMITK_OBJECT(ds), return_str); } if (dcm_dataset->findAndGetString(DCM_PatientName, return_str, OFTrue).good()) { if (AMITK_OBJECT_NAME(ds) == NULL) amitk_object_set_name(AMITK_OBJECT(ds), return_str); amitk_data_set_set_subject_name(ds, return_str); } if (dcm_dataset->findAndGetString(DCM_SeriesDate, return_str, OFTrue).good()) scan_date = return_str; else if (dcm_dataset->findAndGetString(DCM_AcquisitionDate, return_str, OFTrue).good()) scan_date = return_str; else if (dcm_dataset->findAndGetString(DCM_StudyDate, return_str, OFTrue).good()) scan_date = return_str; if (dcm_dataset->findAndGetString(DCM_SeriesTime, return_str, OFTrue).good()) scan_time = return_str; else if (dcm_dataset->findAndGetString(DCM_AcquisitionTime, return_str, OFTrue).good()) scan_time = return_str; else if (dcm_dataset->findAndGetString(DCM_StudyTime, return_str, OFTrue).good()) scan_time = return_str; valid=FALSE; if (scan_date != NULL) { if (3 == sscanf(scan_date, "%4d%2d%2d", &(time_structure.tm_year), &(time_structure.tm_mon), &(time_structure.tm_mday))) { time_structure.tm_year -= 1900; /* years start from 1900 */ if (time_structure.tm_mon > 0) time_structure.tm_mon -= 1; /* now from 0-11 */ if (scan_time != NULL) if (3 == sscanf(scan_time, "%2d%2d%2d", &(time_structure.tm_hour), &(time_structure.tm_min), &(time_structure.tm_sec))) valid = TRUE; if (!valid) { time_structure.tm_hour = 0; time_structure.tm_min = 0; time_structure.tm_sec = 0; } } time_structure.tm_isdst = -1; /* "-1" is suppose to let the system figure it out */ if (mktime(&time_structure) != -1) { amitk_data_set_set_scan_date(ds, asctime(&time_structure)); valid = TRUE; } else { valid = FALSE; } } if (!valid) { if ((scan_date != NULL) && (scan_time != NULL)) { temp_str = g_strdup_printf("%s %s\n",scan_date,scan_time); amitk_data_set_set_scan_date(ds,temp_str); g_free(temp_str); } else if (scan_date != NULL) { amitk_data_set_set_scan_date(ds,scan_date); } else if (scan_time != NULL) { amitk_data_set_set_scan_date(ds,scan_time); } } if (dcm_dataset->findAndGetString(DCM_PatientBirthDate, return_str, OFTrue).good()) amitk_data_set_set_subject_dob(ds, return_str); if (dcm_dataset->findAndGetString(DCM_PatientSex, return_str, OFTrue).good()) if (return_str != NULL) { if (return_str[0] == 'M') amitk_data_set_set_subject_sex(ds, AMITK_SUBJECT_SEX_MALE); else if (return_str[0] == 'F') amitk_data_set_set_subject_sex(ds, AMITK_SUBJECT_SEX_FEMALE); /* default is unknown */ } /* because of how the dicom coordinates are setup, after reading in the patient slices, they should all be oriented as SUPINE_HEADFIRST in AMIDE */ /* 20071121 - renabled following code, not sure if above statement is true */ // amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST); if (dcm_dataset->findAndGetString(DCM_PatientPosition, return_str, OFTrue).good()) { if (return_str != NULL) { if (g_ascii_strcasecmp(return_str, "HFS")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST); else if (g_ascii_strcasecmp(return_str, "FFS")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST); else if (g_ascii_strcasecmp(return_str, "HFP")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST); else if (g_ascii_strcasecmp(return_str, "FFP")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST); else if (g_ascii_strcasecmp(return_str, "HFDR")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST); else if (g_ascii_strcasecmp(return_str, "FFDR")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST); else if (g_ascii_strcasecmp(return_str, "HFDL")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST); else if (g_ascii_strcasecmp(return_str, "FFDL")==0) amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST); // g_debug("Patient position is %s", return_str); } } format_size = amitk_format_sizes[format]; /* num_bytes = amitk_raw_format_calc_num_bytes(dim, amitk_format_to_raw_format(format)); */ /* a "GetSint16Array" function is also provided, but for some reason I get an error when using it. I'll just use GetUint16Array even for signed stuff */ if (!valid_J2K) { switch (format) { case AMITK_FORMAT_SBYTE: case AMITK_FORMAT_UBYTE: { const Uint8 * temp_buffer; result = dcm_dataset->findAndGetUint8Array(DCM_PixelData, temp_buffer); buffer = (void *) temp_buffer; break; } case AMITK_FORMAT_SSHORT: case AMITK_FORMAT_USHORT: { const Uint16 * temp_buffer; result = dcm_dataset->findAndGetUint16Array(DCM_PixelData, temp_buffer); buffer = (void *) temp_buffer; break; } case AMITK_FORMAT_SINT: case AMITK_FORMAT_UINT: { const Uint32 * temp_buffer; result = dcm_dataset->findAndGetUint32Array(DCM_PixelData, temp_buffer); // result = dcm_dataset->findAndGetUint16Array(DCM_PixelData, temp_buffer); buffer = (void *) temp_buffer; break; } default: g_warning(_("unsupported data format in %s at %d\n"), __FILE__, __LINE__); goto error; break; } assert(buffer); if (result.bad()) { g_warning(_("error reading in pixel data - DCMTK error: %s - Failed to read file %s"), result.text(), filename); goto error; } } else { #ifdef AMIDE_LIBOPENJP2_SUPPORT buffer = j2k_to_raw(dcm_dataset, ds); if (!buffer) { g_warning(_("error while decompressing JPEG 2000 from DCMTK file %s"), filename); goto error; } #else g_warning(_("file %s is JPEG 2000 encoded and supporting libraries have not been compiled in."), filename); goto error; #endif } i = zero_voxel; /* store the scaling factor... if there is one */ if (dcm_dataset->findAndGetFloat64(DCM_RescaleSlope, rescale_slope, 0, OFTrue).good()) { *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, i) = rescale_slope; // g_debug("RescaleSlope: %f", return_float64); } /* same for the offset */ /* note, dicom is y = RescaleSlope * x + RescaleIntercept. amide is y = scaling_factor * (x + scaling_intercept), hence the division by rescale_slope */ if (dcm_dataset->findAndGetFloat64(DCM_RescaleIntercept, return_float64, 0, OFTrue).good()) { *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept, i) = return_float64/rescale_slope; // g_debug("RescaleIntercept: %f", return_float64); } // MR: alternative FrameReferenceDateTime if (dcm_dataset->findAndGetFloat64(DCM_FrameReferenceTime, return_float64).good()) amitk_data_set_set_scan_start(ds,return_float64/1000.0); /* and load in the data - plane by plane */ for (i.t = 0; (i.t < dim.t) && (continue_work); i.t++) { /* note ... doesn't seem to be a way to encode different frame durations within one dicom file */ if (dcm_dataset->findAndGetSint32(DCM_ActualFrameDuration, return_sint32).good()) { amitk_data_set_set_frame_duration(ds,i.t, ((gdouble) return_sint32)/1000.0); /* make sure it's not zero */ if (amitk_data_set_get_frame_duration(ds,i.t) < EPSILON) amitk_data_set_set_frame_duration(ds,i.t, EPSILON); } for (i.g = 0; (i.g < ds->raw_data->dim.g) && (continue_work); i.g++) { /* note, we've already flipped the coordinate axis, so reading in the data straight is correct */ ds_pointer = amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), i); memcpy(ds_pointer, (guchar *) buffer, format_size*ds->raw_data->dim.x*ds->raw_data->dim.y*ds->raw_data->dim.z); if (valid_J2K) { /* Free allocated buffer */ g_free((gpointer)buffer); buffer=NULL; } } } amitk_data_set_set_scale_factor(ds, 1.0); /* set the external scaling factor */ amitk_data_set_calc_far_corner(ds); /* set the far corner of the volume */ amitk_data_set_calc_min_max(ds, update_func, update_data); goto function_end; error: if (ds != NULL) { ds = AMITK_DATA_SET(amitk_object_unref(ds)); ds = NULL; } function_end: /* deregister global decompression codecs */ DJDecoderRegistration::cleanup(); if (valid_J2K && buffer) { /* Free allocated buffer */ //g_free((gpointer)buffer); //buffer=NULL; } return ds; } void transfer_slice(AmitkDataSet * ds, AmitkDataSet * slice_ds, AmitkVoxel i) { size_t num_bytes_to_transfer; void * ds_pointer; void * slice_pointer; num_bytes_to_transfer = amitk_raw_format_calc_num_bytes(AMITK_DATA_SET_DIM(slice_ds), AMITK_DATA_SET_FORMAT(slice_ds)); ds_pointer = amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), i); g_return_if_fail(ds_pointer != NULL); slice_pointer = amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(slice_ds), zero_voxel); g_return_if_fail(slice_pointer != NULL); memcpy(ds_pointer, slice_pointer, num_bytes_to_transfer); /* copy the scaling factors */ *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, i) = amitk_data_set_get_internal_scaling_factor(slice_ds, zero_voxel); *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept, i) = amitk_data_set_get_scaling_intercept(slice_ds, zero_voxel); return; } /* sort by location */ static gint sort_slices_func(gconstpointer a, gconstpointer b) { AmitkDataSet * slice_a = (AmitkDataSet *) a; AmitkDataSet * slice_b = (AmitkDataSet *) b; AmitkPoint offset_b; g_return_val_if_fail(AMITK_IS_DATA_SET(slice_a), -1); g_return_val_if_fail(AMITK_IS_DATA_SET(slice_b), 1); offset_b = amitk_space_b2s(AMITK_SPACE(slice_a), AMITK_SPACE_OFFSET(slice_b)); if (offset_b.z > 0.0) return -1; else if (offset_b.z < 0.0) return 1; else return 0; } /* sort by time, then by location */ static gint sort_slices_func_with_time(gconstpointer a, gconstpointer b) { AmitkDataSet * slice_a = (AmitkDataSet *) a; AmitkDataSet * slice_b = (AmitkDataSet *) b; amide_time_t scan_start_a, scan_start_b; g_return_val_if_fail(AMITK_IS_DATA_SET(slice_a), -1); g_return_val_if_fail(AMITK_IS_DATA_SET(slice_b), 1); /* first sort by time */ scan_start_a = AMITK_DATA_SET_SCAN_START(slice_a); scan_start_b = AMITK_DATA_SET_SCAN_START(slice_b); if (!REAL_EQUAL(scan_start_a, scan_start_b)) { if (scan_start_a < scan_start_b) return -1; else return 1; } /* then sort by location */ return sort_slices_func(a,b); } /* sort by gate, then by location */ static gint sort_slices_func_with_gate(gconstpointer a, gconstpointer b) { AmitkDataSet * slice_a = (AmitkDataSet *) a; AmitkDataSet * slice_b = (AmitkDataSet *) b; amide_time_t gate_time_a, gate_time_b; g_return_val_if_fail(AMITK_IS_DATA_SET(slice_a), -1); g_return_val_if_fail(AMITK_IS_DATA_SET(slice_b), 1); /* first sort by gate if we can. Note, we set gate_num to -1 if there's no entry for it in the DICOM file */ if ((slice_a->gate_num >= 0) && (slice_b->gate_num >=0)) { if (slice_a->gate_num < slice_b->gate_num) return -1; else if (slice_a->gate_num > slice_b->gate_num) return 1; } /* if we don't have gate_num entries, sort by gate time */ gate_time_a = amitk_data_set_get_gate_time(slice_a, 0); gate_time_b = amitk_data_set_get_gate_time(slice_b, 0); if (!REAL_EQUAL(gate_time_a, gate_time_b)) { if (gate_time_a < gate_time_b) return -1; else return 1; } /* then sort by location */ return sort_slices_func(a,b); } static GList * find_slices_that_match(GList ** pslices) { AmitkDataSet * initial_ds; AmitkDataSet * comparison_ds; GList * matching_slices=NULL; gboolean match; GList * current_slices; g_return_val_if_fail(*pslices != NULL, NULL); /* put the first slice into the matching set */ initial_ds = AMITK_DATA_SET(g_list_nth_data(*pslices, 0)); *pslices = g_list_remove(*pslices, initial_ds); matching_slices = g_list_append(matching_slices, initial_ds); current_slices = *pslices; /* go through the rest of the slices and find what matches */ while (current_slices != NULL) { comparison_ds = AMITK_DATA_SET(current_slices->data); /* check dimensions are equal */ match = (VOXEL_EQUAL(AMITK_DATA_SET_DIM(initial_ds), AMITK_DATA_SET_DIM(comparison_ds))); /* check voxel sizes are equal */ if (match) match = (POINT_EQUAL(AMITK_DATA_SET_VOXEL_SIZE(initial_ds), AMITK_DATA_SET_VOXEL_SIZE(comparison_ds))); /* check that the orientation of the slices are equal. Note, we use _close instead of _equal (CLOSE vs EPSILON) because there values are coming from character strings in the DICOM header, and may be a little imprecise. */ if (match) match = amitk_space_axes_close(AMITK_SPACE(initial_ds), AMITK_SPACE(comparison_ds)); /* check that the image type tags are the same. g_strcmp0 handles NULL pointers */ if (match) match = (g_strcmp0(AMITK_DATA_SET_DICOM_IMAGE_TYPE(initial_ds), AMITK_DATA_SET_DICOM_IMAGE_TYPE(comparison_ds)) == 0); /* if MRI, check inversion, echo times, and b-value are equal */ if (AMITK_DATA_SET_MODALITY(initial_ds) == AMITK_MODALITY_MRI) { if (match) if (!isnan (AMITK_DATA_SET_INVERSION_TIME(initial_ds)) && !isnan(AMITK_DATA_SET_INVERSION_TIME(comparison_ds))) match = REAL_EQUAL(AMITK_DATA_SET_INVERSION_TIME(initial_ds), AMITK_DATA_SET_INVERSION_TIME(comparison_ds)); if (match) if (!isnan (AMITK_DATA_SET_ECHO_TIME(initial_ds)) && !isnan(AMITK_DATA_SET_ECHO_TIME(comparison_ds))) match = REAL_EQUAL(AMITK_DATA_SET_ECHO_TIME(initial_ds), AMITK_DATA_SET_ECHO_TIME(comparison_ds)); if (match) if (!isnan (AMITK_DATA_SET_DIFFUSION_B_VALUE(initial_ds)) && !isnan(AMITK_DATA_SET_DIFFUSION_B_VALUE(comparison_ds))) { match = REAL_EQUAL(AMITK_DATA_SET_DIFFUSION_B_VALUE(initial_ds), AMITK_DATA_SET_DIFFUSION_B_VALUE(comparison_ds)); if (match) match = POINT_EQUAL(AMITK_DATA_SET_DIFFUSION_DIRECTION(initial_ds), AMITK_DATA_SET_DIFFUSION_DIRECTION(comparison_ds)); } } if (match) matching_slices = g_list_append(matching_slices, comparison_ds); current_slices = current_slices->next; } current_slices = matching_slices; while (current_slices != NULL) { *pslices = g_list_remove(*pslices, current_slices->data); current_slices = current_slices->next; } return matching_slices; } static GList * separate_duplicate_slices(GList * slices_to_combine, GList ** premaining_slices) { GList * current_slices; AmitkDataSet * previous_ds; AmitkDataSet * current_ds; AmitkDataSet * discard_ds; g_return_val_if_fail(slices_to_combine != NULL, NULL); g_return_val_if_fail(premaining_slices != NULL, NULL); current_slices = g_list_first(slices_to_combine); previous_ds = AMITK_DATA_SET(current_slices->data); /* get a list of the duplicates */ current_slices = current_slices->next; while (current_slices != NULL) { current_ds = AMITK_DATA_SET(current_slices->data); current_slices = current_slices->next; if (POINT_EQUAL(AMITK_SPACE_OFFSET(previous_ds), AMITK_SPACE_OFFSET(current_ds))) { if (current_ds->instance_number < previous_ds->instance_number) { discard_ds = previous_ds; previous_ds = current_ds; /* for next iteration */ } else { discard_ds = current_ds; /* previous_ds stays the same */ } *premaining_slices = g_list_append(*premaining_slices, discard_ds); slices_to_combine = g_list_remove(slices_to_combine, discard_ds); } else { previous_ds = current_ds; } } return slices_to_combine; } static AmitkDataSet * import_slices_as_dataset(GList * slices, gint num_frames, gint num_gates, gint num_slices, AmitkUpdateFunc update_func, gpointer update_data, gchar **perror_buf) { AmitkDataSet * ds=NULL; gint num_files; gint i_file; AmitkDataSet * slice_ds=NULL; AmitkVoxel dim, scaling_dim; div_t x; AmitkVoxel i; AmitkPoint offset, initial_offset, diff; gboolean screwed_up_timing; gboolean screwed_up_thickness; amide_real_t true_thickness=0.0; amide_real_t old_thickness=0.0; AmitkPoint voxel_size; gboolean figured_out_dimz=FALSE; g_return_val_if_fail(slices != NULL, NULL); screwed_up_timing=FALSE; screwed_up_thickness=FALSE; num_files = g_list_length(slices); /* special stuff for 1st slice */ slice_ds = (AmitkDataSet *) g_list_nth_data(slices,0); dim = AMITK_DATA_SET_DIM(slice_ds); if ((dim.z != 1) && (num_files != 1)) { g_warning("Don't know how to deal with multiple files containing multiple slices"); goto error; } if (dim.z == 1) dim.z = num_files; /* dealing with dynamic or gated data */ if ((num_frames > 1) || (num_gates > 1)) { if (num_frames > 1) x = div(dim.z, num_frames); else /* (num_gates > 1) */ x = div(dim.z, num_gates); if (x.rem == 0) { /* ideal case, things make sense */ if (num_frames > 1) dim.t = num_frames; else /* (num_gates > 1) */ dim.g = num_gates; dim.z = x.quot; figured_out_dimz = TRUE; } if ((!figured_out_dimz) && (num_slices > 1)) { /* inconsistency in our data set.... let's assume num_gates or num frames off, and see if we can use the num_slices parameter to recover */ x = div(dim.z, num_slices); if (x.rem == 0) { /* try to recover based on what the DICOM file thinks is the number of slices per frame */ amitk_append_str_with_newline(perror_buf, _("Cannot evenly divide the number of slices (%d) by the number of reported %s (%d) for data set %s - will try with %d %s"), dim.z, num_frames > 1 ? _("frames") : _("gates"), num_frames > 1 ? num_frames : num_gates, AMITK_OBJECT_NAME(slice_ds), x.quot, num_frames > 1 ? _("frames") : _("gates")); if (num_frames > 1) dim.t = x.quot; else /* (num_gates > 1) */ dim.g = x.quot; dim.z = num_slices; figured_out_dimz = TRUE; } } if (!figured_out_dimz) { /* still have inconsistency in our data set.... */ /* if we have a num_slices parameter, we'll end up using that */ if (num_slices > 1) x.quot = num_slices; amitk_append_str_with_newline(perror_buf, _("Cannot evenly divide the number of slices (%d) by the number of %s (%d) for data set %s - will load first %d slices"), dim.z, num_frames > 1 ? _("frames") : _("gates"), num_frames > 1 ? num_frames : num_gates, AMITK_OBJECT_NAME(slice_ds), (x.quot > 0) ? x.quot : dim.z); /* failure */ if (num_frames > 1) dim.t = num_frames = 1; else /* (num_gates > 1) */ dim.g = num_gates = 1; if (x.quot > 0) dim.z = x.quot; figured_out_dimz = TRUE; } } /* dynamic/gated data */ ds = AMITK_DATA_SET(amitk_object_copy(AMITK_OBJECT(slice_ds))); /* unref and remalloc what we need */ if (ds->raw_data != NULL) g_object_unref(ds->raw_data); ds->raw_data = amitk_raw_data_new_with_data(AMITK_DATA_SET_FORMAT(slice_ds), dim); if (ds->raw_data == NULL) { g_warning("Could not allocate memory for raw data with dimensions %d x %d x %d x %d x %d", dim.g, dim.t, dim.z, dim.y, dim.x); goto error; } if (ds->distribution != NULL) g_object_unref(ds->distribution); ds->distribution = NULL; /* if we're loading up multiple files, each file has a separate scale factor, so we'll use per slice (2D) scaling. If we're loading up a single file with multiple data frames in it, there's only one scaling factor, so per frame (3D) scaling */ if (num_files > 1) ds->scaling_type = AMITK_SCALING_TYPE_2D_WITH_INTERCEPT; else ds->scaling_type = AMITK_SCALING_TYPE_1D_WITH_INTERCEPT; scaling_dim=one_voxel; scaling_dim.z = (num_files > 1) ? dim.z : 1; scaling_dim.g = dim.g; scaling_dim.t = dim.t; if (ds->internal_scaling_factor != NULL) g_object_unref(ds->internal_scaling_factor); ds->internal_scaling_factor = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, scaling_dim); if (ds->internal_scaling_intercept != NULL) g_object_unref(ds->internal_scaling_intercept); ds->internal_scaling_intercept = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, scaling_dim); if (ds->current_scaling_factor != NULL) g_object_unref(ds->current_scaling_factor); ds->current_scaling_factor=NULL; if (ds->frame_max != NULL) g_free(ds->frame_max); ds->frame_max = amitk_data_set_get_frame_min_max_mem(ds); if (ds->frame_min != NULL) g_free(ds->frame_min); ds->frame_min = amitk_data_set_get_frame_min_max_mem(ds); if (ds->frame_duration != NULL) g_free(ds->frame_duration); if ((ds->frame_duration = amitk_data_set_get_frame_duration_mem(ds)) == NULL) { g_warning(_("couldn't allocate space for the frame duration info")); goto error; } if (ds->gate_time != NULL) g_free(ds->gate_time); if ((ds->gate_time = amitk_data_set_get_gate_time_mem(ds)) == NULL) { g_warning(_("couldn't allocate space for the gate time info")); goto error; } initial_offset = AMITK_SPACE_OFFSET(slice_ds); /* and process all the images */ for (i_file=0; i_file < num_files; i_file++) { slice_ds = (AmitkDataSet *) g_list_nth_data(slices,i_file); x = div(i_file, dim.z); i=zero_voxel; if (num_gates > 1) i.g = x.quot; else i.t = x.quot; i.z = x.rem; transfer_slice(ds, slice_ds, i); /* record frame/gate duration if needed */ if (i.z == 0) { amitk_data_set_set_frame_duration(ds, i.t, amitk_data_set_get_frame_duration(slice_ds, 0)); amitk_data_set_set_gate_time(ds, i.g, amitk_data_set_get_gate_time(slice_ds, 0)); } if (i_file != 0) { /* figure out which direction the slices are going */ if (i_file == 1) { offset = AMITK_SPACE_OFFSET(slice_ds); POINT_SUB(offset, initial_offset, diff); true_thickness = POINT_MAGNITUDE(diff); old_thickness = AMITK_DATA_SET_VOXEL_SIZE_Z(ds); if (true_thickness > EPSILON) /* correct for differences in thickness */ if (!REAL_EQUAL(true_thickness, old_thickness)) { voxel_size = AMITK_DATA_SET_VOXEL_SIZE(ds); voxel_size.z = true_thickness; amitk_data_set_set_voxel_size(ds, voxel_size); /* whether to bother complaining */ if (!REAL_CLOSE(true_thickness, old_thickness)) screwed_up_thickness = TRUE; } } // if (i_file != 0) { /* check if we've crossed a frame boundary */ // if (!REAL_EQUAL(last_scan_start, AMITK_DATA_SET_SCAN_START(slice_ds))) { // if (is_dynamic) { // num_frames++; // if (num_frames > 1) { // if (!REAL_EQUAL(AMITK_DATA_SET_SCAN_START(slice_ds)-last_scan_start, duration)) // screwed_up_timing=TRUE; // duration = amitk_data_set_get_frame_duration(slice_ds, 0); // g_array_append_val(durations, duration); // last_scan_start = AMITK_DATA_SET_SCAN_START(slice_ds); // } // } // } /* check if the curtains match the rug */ if ((i.z == 0) && (i.t > 0)) { if (!REAL_CLOSE(AMITK_DATA_SET_SCAN_START(slice_ds)-amitk_data_set_get_start_time(ds, i.t-1), amitk_data_set_get_frame_duration(ds, i.t-1))) { screwed_up_timing=TRUE; amitk_data_set_set_frame_duration(ds,i.t-1, AMITK_DATA_SET_SCAN_START(slice_ds)- amitk_data_set_get_start_time(ds, i.t-1)); } } } // last_offset = AMITK_SPACE_OFFSET(slice_ds); } /* i_file loop */ if (screwed_up_timing) amitk_append_str_with_newline(perror_buf, _("Detected discontinous frames in data set %s - frame durations have been adjusted to remove interframe time gaps"), AMITK_OBJECT_NAME(ds)); if (screwed_up_thickness) amitk_append_str_with_newline(perror_buf, _("Slice thickness (%5.3f mm) not equal to slice spacing (%5.3f mm) in data set %s - will use slice spacing for thickness"), old_thickness, true_thickness, AMITK_OBJECT_NAME(ds)); /* detected a dynamic data set, massage the data appropriately */ // if (num_frames > 1) { // x = div(dim.z, num_frames); // if (x.rem != 0) { // g_warning(_("Cannot evenly divide the number of slices by the number of frames for data set %s - ignoring dynamic data"), AMITK_OBJECT_NAME(ds)); // } else { /* hack the data set sizes */ // ds->raw_data->dim.t = num_frames; // ds->raw_data->dim.z = x.quot; // // ds->internal_scaling_factor->dim.t = num_frames; // ds->internal_scaling_factor->dim.z = x.quot; // // ds->internal_scaling_intercept->dim.t = num_frames; // ds->internal_scaling_intercept->dim.z = x.quot; /* free the frame max/min arrays - will be realloc's by set_calc_min_max */ // g_free(ds->frame_max); // ds->frame_max=NULL; // g_free(ds->frame_min); // ds->frame_min=NULL; /* and set the frame durations */ // if (ds->frame_duration != NULL) // g_free(ds->frame_duration); // if ((ds->frame_duration = amitk_data_set_get_frame_duration_mem(ds)) == NULL) { // g_warning(_("couldn't allocate space for the frame duration info")); // amitk_object_unref(ds); // return NULL; // } // // for (j=0; j < AMITK_DATA_SET_NUM_FRAMES(ds); j++) // ds->frame_duration[j] = g_array_index(durations,amide_time_t, j); // } // } // g_array_free(durations, TRUE); /* correct for a datset where the z direction is reveresed */ // if (reversed_z) { // void * buffer; // amide_data_t temp_val; // buffer = g_try_malloc(num_bytes_per_slice); // if (buffer == NULL) { // g_warning("could not malloc temp buffer"); // goto error; // } // k = zero_voxel; // for (i.t = 0,k.t=0; i.t < AMITK_DATA_SET_DIM_T(ds); i.t++,k.t++) { // for (i.g = 0,k.g=0; i.g < AMITK_DATA_SET_DIM_G(ds); i.g++,k.g++) { // for (i.z = 0,k.z=AMITK_DATA_SET_DIM_Z(ds)-1; i.z < AMITK_DATA_SET_DIM_Z(ds); i.z++,k.z--) { /* exchange the slices*/ // ds_pointer = amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), i); // slice_pointer = amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), k); // memcpy(buffer, ds_pointer, num_bytes_per_slice); // memcpy(ds_pointer, slice_pointer, num_bytes_per_slice); // memcpy(slice_pointer, buffer, num_bytes_per_slice); // /* exchange the scale factors */ // temp_val = AMITK_RAW_DATA_DOUBLE_CONTENT(ds->internal_scaling_factor, i); // AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->internal_scaling_factor, i) = // AMITK_RAW_DATA_DOUBLE_CONTENT(ds->internal_scaling_factor, k); // AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->internal_scaling_factor, k) = // temp_val; /* exchange the scale offsets */ // temp_val = AMITK_RAW_DATA_DOUBLE_CONTENT(ds->internal_scaling_intercept, i); // AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->internal_scaling_intercept, i) = // AMITK_RAW_DATA_DOUBLE_CONTENT(ds->internal_scaling_intercept, k); // AMITK_RAW_DATA_DOUBLE_SET_CONTENT(ds->internal_scaling_intercept, k) = // temp_val; // // } // } // } // // g_free(buffer); // } /* make sure remaining values have been calculated */ amitk_data_set_set_scale_factor(ds, 1.0); /* set the external scaling factor */ amitk_data_set_calc_far_corner(ds); /* set the far corner of the volume */ amitk_data_set_calc_min_max(ds, update_func, update_data); goto end; error: if (ds != NULL) { amitk_object_unref(ds); ds = NULL; } end: return ds; } static GList * free_slices(GList * slices) { AmitkDataSet * slice_ds; while (slices != NULL) { slice_ds = AMITK_DATA_SET(g_list_nth_data(slices,0)); slices = g_list_remove(slices, slice_ds); amitk_object_unref(slice_ds); } return slices; } static GList * organize_and_import_slices_as_datasets(GList ** premaining_slices, gint num_frames, gint num_gates, gint num_slices, AmitkUpdateFunc update_func, gpointer update_data, gchar **perror_buf) { GList * slices_to_combine = NULL; GList * returned_sets = NULL; GList * additional_sets = NULL; AmitkDataSet * ds=NULL; /* find all the slices that appear to match into one dataset */ slices_to_combine = find_slices_that_match(premaining_slices); /* sort list based on the slice's time and z position */ if (num_frames > 1) slices_to_combine = g_list_sort(slices_to_combine, sort_slices_func_with_time); else if (num_gates > 1) slices_to_combine = g_list_sort(slices_to_combine, sort_slices_func_with_gate); else { slices_to_combine = g_list_sort(slices_to_combine, sort_slices_func); /* throw out any slices that are duplicated in terms of orientation */ slices_to_combine = separate_duplicate_slices(slices_to_combine, premaining_slices); } /* load in the primary data set */ ds = import_slices_as_dataset(slices_to_combine, num_frames, num_gates, num_slices, update_func, update_data, perror_buf); if (ds != NULL) returned_sets = g_list_append(returned_sets, ds); free_slices(slices_to_combine); /* and recurse to try loading in any remaining data sets */ if (*premaining_slices != NULL) { additional_sets = organize_and_import_slices_as_datasets(premaining_slices, num_frames, num_gates, num_slices, update_func, update_data, perror_buf); if (additional_sets != NULL) returned_sets = g_list_concat(returned_sets, additional_sets); } return returned_sets; } static GList * import_files_as_datasets(GList * image_files, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data, gchar **perror_buf) { GList * returned_sets=NULL; AmitkDataSet * slice_ds=NULL; div_t x; gchar * slice_name; gint image; gint num_frames=1; gint num_gates=1; gint num_slices=-1; gint num_files; GList * slices=NULL; gboolean continue_work=TRUE; gint divider; num_files = g_list_length(image_files); g_return_val_if_fail(num_files != 0, NULL); if (update_func != NULL) continue_work = (*update_func)(update_data, _("Importing File(s) Through DCMTK"), (gdouble) 0.0); divider = (num_files/AMITK_UPDATE_DIVIDER < 1.0) ? 1 : (gint) rint(num_files/AMITK_UPDATE_DIVIDER); for (image=0; (image < num_files) && (continue_work); image++) { if (update_func != NULL) { x = div(image,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image)/((gdouble) num_files)); } slice_name = (gchar *) g_list_nth_data(image_files,image); slice_ds = read_dicom_file(slice_name, pstudyname,preferences, &num_frames, &num_gates, &num_slices, NULL, NULL, perror_buf); if (slice_ds == NULL) { goto cleanup; } else if ((AMITK_DATA_SET_DIM_Z(slice_ds) != 1) && (num_files > 1)) { /* can handle multiple dicom files each with a single slice, or one dicom file with multiple slices, can't handle multiple files each with multiple slices */ g_warning(_("no support for multislice files within DICOM directory format")); amitk_object_unref(slice_ds); slice_ds = NULL; goto cleanup; } slices = g_list_append(slices, slice_ds); } if (!continue_work) goto cleanup; if ((num_frames > 1) && (num_gates > 1)) g_warning("Don't know how to deal with multi-gate and multi-frame data, results will be undefined"); returned_sets = organize_and_import_slices_as_datasets(&slices, num_frames, num_gates, num_slices, update_func, update_data, perror_buf); cleanup: if (update_func != NULL) /* remove progress bar */ (*update_func) (update_data, NULL, (gdouble) 2.0); slices = free_slices(slices); return returned_sets; } typedef struct slice_info_t { gchar * filename; gchar * series_instance_uid; gchar * modality; gchar * series_description; gchar * patient_id; gchar * patient_name; gint series_number; } slice_info_t; static void free_slice_info(slice_info_t * info) { if (info->filename != NULL) g_free(info->filename); if (info->series_instance_uid != NULL) g_free(info->series_instance_uid); if (info->modality != NULL) g_free(info->modality); if (info->series_description != NULL) g_free(info->series_description); if (info->patient_id != NULL) g_free(info->patient_id); if (info->patient_name != NULL) g_free(info->patient_name); g_free(info); return; } static slice_info_t * slice_info_new(void) { slice_info_t * info; info = g_try_new(slice_info_t, 1); info->filename=NULL; info->series_instance_uid=NULL; info->modality=NULL; info->series_description=NULL; info->patient_id=NULL; info->patient_name=NULL; info->series_number = -1; return info; } static slice_info_t * get_slice_info(const gchar * filename) { OFCondition result; DcmFileFormat dcm_format; DcmDataset * dcm_dataset; const char * return_str=NULL; slice_info_t * info=NULL; Sint32 return_sint32; result = dcm_format.loadFile(filename); if (result.bad()) return NULL; dcm_dataset = dcm_format.getDataset(); if (dcm_dataset == NULL) return NULL; info = slice_info_new(); info->filename = g_strdup(filename); dcm_dataset->findAndGetString(DCM_SeriesInstanceUID, return_str, OFTrue); if (return_str != NULL) info->series_instance_uid = g_strdup(return_str); dcm_dataset->findAndGetString(DCM_Modality, return_str, OFTrue); if (return_str != NULL) info->modality = g_strdup(return_str); dcm_dataset->findAndGetString(DCM_SeriesDescription, return_str, OFTrue); if (return_str != NULL) info->series_description = g_strdup(return_str); dcm_dataset->findAndGetString(DCM_PatientID, return_str, OFTrue); if (return_str != NULL) info->patient_id = g_strdup(return_str); dcm_dataset->findAndGetString(DCM_PatientName, return_str, OFTrue); if (return_str != NULL) info->patient_name = g_strdup(return_str); if (dcm_dataset->findAndGetSint32(DCM_SeriesNumber, return_sint32).good()) info->series_number = return_sint32; return info; } static gboolean check_str(gchar * str1, gchar * str2) { if ((str1 == NULL) && (str2 == NULL)) return TRUE; if ((str1 == NULL) || (str2 == NULL)) return FALSE; if (strcmp(str1, str2) == 0) return TRUE; return FALSE; } static gboolean check_same(slice_info_t * slice1, slice_info_t * slice2) { gint j, count; gchar ** slice1_uid_split=NULL; gchar ** slice2_uid_split=NULL; gboolean same_dataset; if ((slice1->series_instance_uid == NULL) || (slice2->series_instance_uid == NULL)) return FALSE; else if ((slice1->series_instance_uid != NULL) && (slice2->series_instance_uid != NULL)) { slice1_uid_split = g_strsplit(slice1->series_instance_uid, ".", -1); slice2_uid_split = g_strsplit(slice2->series_instance_uid, ".", -1); count=0; while (slice1_uid_split[count] != NULL) count++; /* check all but last number in series instance uid */ same_dataset=TRUE; for (j=0; (j<(count-1) && same_dataset); j++) { if (slice2_uid_split[j] == NULL) same_dataset=FALSE; else if (strcmp(slice1_uid_split[j], slice2_uid_split[j]) != 0) same_dataset=FALSE; } if (slice1_uid_split != NULL) g_strfreev(slice1_uid_split); if (slice2_uid_split != NULL) g_strfreev(slice2_uid_split); if (!same_dataset) return FALSE; } if (!check_str(slice1->series_description, slice2->series_description)) return FALSE; if (slice1->series_number != slice2->series_number) return FALSE; if (!check_str(slice1->modality, slice2->modality)) return FALSE; if (!check_str(slice1->patient_id, slice2->patient_id)) { return FALSE; } if (!check_str(slice1->patient_name, slice2->patient_name)) { return FALSE; } return TRUE; } static gint sort_raw_info(gconstpointer a, gconstpointer b) { const slice_info_t * slicea = (slice_info_t *) a; const slice_info_t * sliceb = (slice_info_t *) b; /* sort by series if we've got the data */ if ((slicea->series_number >=0) && (sliceb->series_number >=0)) { if (slicea->series_number > sliceb->series_number) return 1; else if (slicea->series_number < sliceb->series_number) return -1; } return strcmp(slicea->filename, sliceb->filename); } static gint sort_datasets_by_dicom_params(gconstpointer a, gconstpointer b) { g_return_val_if_fail(a != NULL, 0); g_return_val_if_fail(b != NULL, 0); /* first sort by series number */ if (AMITK_DATA_SET_SERIES_NUMBER(a) > AMITK_DATA_SET_SERIES_NUMBER(b)) return 1; else if (AMITK_DATA_SET_SERIES_NUMBER(a) < AMITK_DATA_SET_SERIES_NUMBER(b)) return -1; /* then sort by echo time if we have that parameter */ if (!isnan(AMITK_DATA_SET_ECHO_TIME(a)) && !isnan(AMITK_DATA_SET_ECHO_TIME(b))) { if (AMITK_DATA_SET_ECHO_TIME(a) > AMITK_DATA_SET_ECHO_TIME(b)) return 1; else if (AMITK_DATA_SET_ECHO_TIME(a) < AMITK_DATA_SET_ECHO_TIME(b)) return -1; } return 0; } static GList * import_files(const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { AmitkDataSet * ds; GList * data_sets = NULL; GList * returned_sets = NULL; GList * image_files=NULL; GList * raw_info=NULL; GList * all_slices=NULL; /* list of lists */ GList * temp_all_slices; GList * sorted_slices=NULL; /* pointer to a list in all_slices */ gchar * image_name; gchar * error_buf=NULL; slice_info_t * info=NULL; slice_info_t * current_info=NULL; gchar * dirname=NULL; gchar * basename=NULL; gchar * regularized_filename; gchar * new_filename; DIR* dir; struct dirent* entry; gboolean continue_work=TRUE; gboolean all_datasets; gboolean use_this_one; GtkWidget * question; gint return_val; /* note, I generate a "regularized_filename" rather than just using filename, to insure that when the filenames get sorted alphabetically, they're all of the same "./filename" form. */ dirname = g_path_get_dirname(filename); basename = g_path_get_basename(filename); if (dirname == NULL) regularized_filename = g_strdup_printf("%s", filename); else regularized_filename = g_strdup_printf("%s%s%s", dirname, G_DIR_SEPARATOR_S,basename); /* get the intially requested file */ info = get_slice_info(regularized_filename); if (info == NULL) { g_warning(_("could not find dataset in DICOM file %s\n"), regularized_filename); return NULL; } raw_info = g_list_append(raw_info, info); /* ------- find all dicom files in the directory ------------ */ if (update_func != NULL) continue_work = (*update_func)(update_data, _("Scanning Files to find additional DICOM Slices"), (gdouble) 0.0); if ((dir = opendir(dirname))!=NULL) { while (((entry = readdir(dir)) != NULL) && (continue_work)) { if (update_func != NULL) continue_work = (*update_func)(update_data, NULL, -1.0); if (dirname == NULL) new_filename = g_strdup_printf("%s", entry->d_name); else new_filename = g_strdup_printf("%s%s%s", dirname, G_DIR_SEPARATOR_S,entry->d_name); if (strcmp(basename, entry->d_name) != 0) { /* we've already got the initial filename */ if (dcmtk_test_dicom(new_filename)) { info = get_slice_info(new_filename); if (info != NULL) raw_info = g_list_append(raw_info, info); /* we have a match */ } } g_free(new_filename); } if (dir != NULL) closedir(dir); } if (dirname != NULL) g_free(dirname); if (basename != NULL) g_free(basename); if (update_func != NULL) /* remove progress bar */ (*update_func) (update_data, NULL, (gdouble) 2.0); /* sort by series number, then filename */ raw_info = g_list_sort(raw_info, sort_raw_info); /* ------------ sort the files ---------------- */ while (raw_info != NULL) { current_info = (slice_info_t *) raw_info->data; raw_info = g_list_remove(raw_info, current_info); /* go through the list of slice lists, find one that matches */ temp_all_slices = all_slices; while ((temp_all_slices != NULL) && (current_info != NULL)){ sorted_slices = (GList *) temp_all_slices->data; g_assert(sorted_slices->data != NULL); info = (slice_info_t *) sorted_slices->data; /* current slice matches the first slice in the current list, add it to this list */ if (check_same(current_info, info)) { sorted_slices = g_list_append(sorted_slices, current_info); current_info = NULL; } temp_all_slices = temp_all_slices->next; } /* current info doesn't match anything, add it on as a new list */ if (current_info != NULL) all_slices = g_list_append(all_slices, g_list_append(NULL, current_info)); } g_assert(all_slices != NULL); /* check if we want to load in everything or not */ all_datasets=FALSE; if (g_list_length(all_slices) > 1) { /* make sure we really want to delete */ question = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Multiple data sets were found in the same directory as the specified file. In addition to the dataset corresponding to the specified file, would you like to load in these additional datasets?")); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val == GTK_RESPONSE_YES) all_datasets=TRUE; } while (all_slices != NULL) { sorted_slices = (GList *) all_slices->data; all_slices = g_list_remove(all_slices, sorted_slices); use_this_one = FALSE; /* transfer file names */ image_files = NULL; while (sorted_slices != NULL) { info = (slice_info_t *) sorted_slices->data; /* see if this group of filenames contains the filename we initially started with */ if (strcmp(regularized_filename, info->filename) == 0) use_this_one = TRUE; sorted_slices = g_list_remove(sorted_slices, info); image_files = g_list_append(image_files, info->filename); info->filename=NULL; free_slice_info(info); } if (all_datasets || (use_this_one)) { returned_sets = import_files_as_datasets(image_files, pstudyname, preferences, update_func, update_data, &error_buf); while (returned_sets != NULL) { ds = AMITK_DATA_SET(returned_sets->data); data_sets = g_list_append(data_sets, ds); returned_sets = g_list_remove(returned_sets, ds); } } /* cleanup */ while (image_files != NULL) { image_name = (gchar *) g_list_nth_data(image_files,0); image_files = g_list_remove(image_files, image_name); g_free(image_name); } } /* and sort datasets by series number, echo time, etc.*/ data_sets = g_list_sort(data_sets, sort_datasets_by_dicom_params); /* cleanup */ if (error_buf != NULL) { g_warning("%s",error_buf); g_free(error_buf); } if (regularized_filename != NULL) g_free(regularized_filename); return data_sets; } /* read in a DICOMDIR type file */ static GList * import_dir(const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { GList * data_sets=NULL; GList * returned_sets=NULL; DcmDirectoryRecord * dcm_root_record; DcmDirectoryRecord * patient_record=NULL; DcmDirectoryRecord * study_record=NULL; DcmDirectoryRecord * series_record=NULL; DcmDirectoryRecord * image_record=NULL; OFCondition result; AmitkDataSet * ds=NULL; const char * return_str=NULL; const char * record_name[3]; const char * patient_id; gchar * dirname=NULL; gchar * object_name=NULL; gchar * temp_name; gchar * temp_name2; GList * image_files=NULL; gint j; gchar * error_buf=NULL; gchar * image_name1; gchar * image_name2; gchar * lowercase_image_name1=NULL;; gchar * lowercase_image_name2=NULL;; gboolean valid_filename; gboolean ignore_missing_files = FALSE; gboolean use_alternative; gboolean always_use_alternative = FALSE; GtkWidget * question; gint return_val; /* first try loading it as a DIRFILE */ DcmDicomDir dcm_dir(filename); /* dcm_dir.print(cout); */ dirname = g_path_get_dirname(filename); dcm_root_record = &(dcm_dir.getRootRecord()); /* dcm_root_record->print(cout);*/ /* go through the whole directory */ while ((patient_record = dcm_root_record->nextSub(patient_record)) != NULL) { patient_record->findAndGetString(DCM_PatientName, record_name[0]); patient_record->findAndGetString(DCM_PatientID, patient_id, OFTrue); while ((study_record= patient_record->nextSub(study_record)) != NULL) { study_record->findAndGetString(DCM_StudyDescription, record_name[1]); while ((series_record = study_record->nextSub(series_record)) != NULL) { series_record->findAndGetString(DCM_SeriesDescription, record_name[2]); /* concat the names that aren't NULL */ for (j=0; j<3; j++) { if (record_name[j] != NULL) { temp_name2 = g_strdup(record_name[j]); g_strstrip(temp_name2); if (object_name != NULL) { temp_name = object_name; object_name = g_strdup_printf("%s - %s", temp_name, temp_name2); g_free(temp_name); } else object_name = g_strdup(temp_name2); g_free(temp_name2); } } while ((image_record=series_record->nextSub(image_record)) != NULL) { if (image_record->findAndGetString(DCM_ReferencedFileID, return_str).good()) { image_name1 = g_strdup(return_str); g_strdelimit(image_name1, "\\", G_DIR_SEPARATOR); /* remove separators */ image_name2 = g_strdup_printf("%s%s%s", dirname, G_DIR_SEPARATOR_S,image_name1); /* check if there's a upper vs lower case issue, seems to happen with GE exported DICOMDIR files, likely due to some filesystems not being case aware */ valid_filename = dcmtk_test_dicom(image_name2); if ((!valid_filename) && (!ignore_missing_files)) { use_alternative=FALSE; lowercase_image_name1 = g_ascii_strdown(image_name1,-1); lowercase_image_name2 = g_strdup_printf("%s%s%s", dirname, G_DIR_SEPARATOR_S, lowercase_image_name1); g_free(lowercase_image_name1); if (!dcmtk_test_dicom(lowercase_image_name2)) { question = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("For series: %s\n\nListed in DICOMDIR: %s\n\nCould not read DICOM file: %s"), object_name, filename, image_name2); gtk_dialog_add_button(GTK_DIALOG(question), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_add_button(GTK_DIALOG(question), _("OK, ignore similar errors"),1); return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val == 1) ignore_missing_files = TRUE; } else if (!always_use_alternative) { question = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("For series: %s\n\nListed in DICOMDIR: %s\n\nCould not read DICOM file: %s\n\nFound possible alternative file: %s"), object_name, filename, image_name2, lowercase_image_name2); gtk_dialog_add_button(GTK_DIALOG(question), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_add_button(GTK_DIALOG(question), _("OK, ignore similar errors"), 1); gtk_dialog_add_button(GTK_DIALOG(question), _("Use alternative"), 2); gtk_dialog_add_button(GTK_DIALOG(question), _("Always use alternative"), 3); return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val == 1) ignore_missing_files = TRUE; if (return_val == 2) use_alternative=TRUE; if (return_val == 3) always_use_alternative = TRUE; } if (use_alternative || always_use_alternative) { g_free(image_name2); image_name2=lowercase_image_name2; valid_filename=TRUE; } else { g_free(lowercase_image_name2); } } g_free(image_name1); if (valid_filename) image_files = g_list_append(image_files, image_name2); } } #if AMIDE_DEBUG g_print("object name: %s with %d files (images)\n", object_name, g_list_length(image_files)); #endif /* read in slices as dataset(s) */ if (g_list_length(image_files) != 0) returned_sets = import_files_as_datasets(image_files, pstudyname, preferences, update_func, update_data, &error_buf); while (returned_sets != NULL) { ds = AMITK_DATA_SET(returned_sets->data); /* If the actual dicom file didn't have these entries, we try using the corresponding enteries from the DICOMDIR file */ if (AMITK_OBJECT_NAME(ds) == NULL) { if (record_name[2] != NULL) amitk_object_set_name(AMITK_OBJECT(ds), record_name[2]); else amitk_object_set_name(AMITK_OBJECT(ds), object_name); } if (AMITK_DATA_SET_SUBJECT_NAME(ds) == NULL) { if (record_name[0] != NULL) amitk_data_set_set_subject_name(ds, record_name[0]); } if (AMITK_DATA_SET_SUBJECT_ID(ds) == NULL) { if (patient_id != NULL) amitk_data_set_set_subject_id(ds, patient_id); } data_sets = g_list_append(data_sets, ds); returned_sets = g_list_remove(returned_sets, ds); } /* cleanup */ while (image_files != NULL) { image_name2 = (gchar *) g_list_nth_data(image_files,0); image_files = g_list_remove(image_files, image_name2); g_free(image_name2); } g_free(object_name); object_name=NULL; } } } /* and sort datasets by series number, echo time, etc.*/ data_sets = g_list_sort(data_sets, sort_datasets_by_dicom_params); /* more cleanup */ if (dirname != NULL) g_free(dirname); if (error_buf != NULL) { g_warning("%s",error_buf); g_free(error_buf); } return data_sets; } GList * dcmtk_import(const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { GList * data_sets=NULL; gboolean is_dir=FALSE; DcmFileFormat dcm_format; DcmMetaInfo * dcm_metainfo; OFCondition result; const char * return_str=NULL; if (!dcmDataDict.isDictionaryLoaded()) { g_warning(_("Could not find a DICOM Data Dictionary. Reading may fail. Consider defining the environmental variable DCMDICTPATH to the dicom.dic file.")); } result = dcm_format.loadFile(filename); if (result.bad()) { g_warning(_("could not read DICOM file %s, dcmtk returned %s"),filename, result.text()); return NULL; } dcm_metainfo = dcm_format.getMetaInfo(); if (dcm_metainfo == NULL) { g_warning("could not find metainfo for DICOM file %s\n", filename); return NULL; } dcm_metainfo->findAndGetString(DCM_MediaStorageSOPClassUID, return_str, OFTrue); if (return_str != NULL) { if (strcmp(return_str, UID_MediaStorageDirectoryStorage) == 0) is_dir= TRUE; /* we've got a DICOMDIR file */ } if (is_dir) { data_sets = import_dir(filename, pstudyname, preferences, update_func, update_data); } else { data_sets = import_files(filename, pstudyname, preferences, update_func, update_data); } return data_sets; } static void insert_str(DcmItem * dcm_item, const DcmTag& tag, const gchar * str) { OFCondition status; status = dcm_item->putAndInsertString(tag, str); if (status.bad()) g_error("Error %s: failed writing tag of type %s\n", status.text(), tag.getVRName()); return; } static void insert_int_str(DcmItem * dcm_item, const DcmTag& tag, gint value) { gchar * temp_str; temp_str = g_strdup_printf("%d",value); insert_str(dcm_item, tag, temp_str); g_free(temp_str); return; } static void insert_double_str(DcmItem * dcm_item, const DcmTag& tag, gdouble value) { gchar * temp_str; temp_str = g_strdup_printf("%f",value); insert_str(dcm_item,tag,temp_str); g_free(temp_str); return; } static void insert_double2_str(DcmItem * dcm_item, const DcmTag& tag, gdouble value1, gdouble value2) { gchar * temp_str; temp_str = g_strdup_printf("%f\\%f",value1,value2); insert_str(dcm_item,tag,temp_str); g_free(temp_str); return; } static void insert_double3_str(DcmItem * dcm_item, const DcmTag& tag, gdouble value1, gdouble value2, gdouble value3) { gchar * temp_str; temp_str = g_strdup_printf("%f\\%f\\%f",value1,value2,value3); insert_str(dcm_item,tag,temp_str); g_free(temp_str); return; } static void insert_double6_str(DcmItem * dcm_item, const DcmTag& tag, gdouble value1, gdouble value2, gdouble value3, gdouble value4, gdouble value5, gdouble value6) { gchar * temp_str; temp_str = g_strdup_printf("%f\\%f\\%f\\%f\\%f\\%f", value1,value2,value3,value4,value5,value6); insert_str(dcm_item,tag,temp_str); g_free(temp_str); return; } /* take a stab at converting the study date and frame information into strings appropriate for the dicom header. date_str and time_str will have to be free'd */ static void generate_dicom_date_and_time(const gchar * date, const amide_time_t frame_offset, gchar ** pdate_str, gchar ** ptime_str) { struct tm time_structure; time_t time_in_seconds; gboolean valid = FALSE; if(date != NULL) { #ifdef HAVE_STRPTIME valid = (strptime(date,"%c",&time_structure) != NULL); if (!valid) /* try a less locale specific format string */ valid = (strptime(date,"%a %b %d %T %Y",&time_structure) != NULL); #endif } if (!valid) { time_structure.tm_year = 0; /* 1900 */ time_structure.tm_mon = 0; /* January */ time_structure.tm_mday = 1; /* first */ time_structure.tm_hour = 0; time_structure.tm_min = 0; time_structure.tm_sec = 0; } time_structure.tm_isdst = -1; /* make mktime figure out daylight savings times issues */ time_in_seconds = mktime(&time_structure); /* convert the dates to seconds since 1970 */ time_in_seconds += frame_offset; /* add the frame offset time */ #if !defined(G_PLATFORM_WIN32) localtime_r(&time_in_seconds, &time_structure); #else /* win32 doesn't have localtime_r */ { struct tm *ptm = localtime (&time_in_seconds); if (ptm != NULL) memcpy ((void *) &time_structure, (void *) ptm, sizeof(struct tm)); else valid = FALSE; } #endif *ptime_str = g_strdup_printf("%02d%02d%02d", time_structure.tm_hour, time_structure.tm_min, time_structure.tm_sec); if (valid) *pdate_str = g_strdup_printf("%04d%02d%02d", time_structure.tm_year+1900, time_structure.tm_mon+1, time_structure.tm_mday); else if (date != NULL) *pdate_str = g_strdup(date); /* if we couldn't figure out the date string, just propogate it */ else *pdate_str = g_strdup("19000101"); return; } /* dirname is usually the name of the directory that the dicomdir file will go into, it can also be the name of a preexisting dicomdir file, in which case the exported data will be appended */ gboolean dcmtk_export(AmitkDataSet * ds, const gchar * dir_or_filename, const gchar * studyname, const gboolean resliced, const AmitkPoint resliced_voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data) { DicomDirInterface dcm_dir; DcmDataset * dcm_ds; DcmFileFormat dcm_format; DcmMetaInfo * dcm_metainfo; DcmItem * dcm_item; char uid[100]; OFCondition status; struct stat file_info; gchar * subdirname=NULL; gchar * full_subdirname=NULL; gchar * filename=NULL; gchar * dirname=NULL; gchar * dcmdir_filename=NULL; gchar * full_filename=NULL; gchar * temp_str=NULL; gint i; AmitkVolume * output_volume=NULL; AmitkDataSet * slice = NULL; AmitkVoxel dim; AmitkPoint corner; AmitkVoxel i_voxel, j_voxel; gboolean format_changing; gboolean format_size_short; gpointer buffer = NULL; amitk_format_SSHORT_t * sshort_buffer; gdouble min,max; gint buffer_size; div_t x; gint divider; gint total_planes; gboolean continue_work=TRUE; AmitkPoint output_start_pt; AmitkCanvasPoint pixel_size; AmitkPoint new_offset; amide_data_t value; gint image_num; gchar * saved_time_locale; gchar * saved_numeric_locale; AmitkAxes axes; AmitkPoint dicom_offset; AmitkPoint voxel_size; gboolean successful = FALSE; gchar * date_str; gchar * time_str; saved_time_locale = g_strdup(setlocale(LC_TIME,NULL)); saved_numeric_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_TIME,"POSIX"); setlocale(LC_NUMERIC,"POSIX"); /* figure out if we've been given a directory, or a DICOMDIR filename */ /* very simplistic, we assume the directory file will be called DICOMDIR if it's anything else, we assume we've been given a directory to create a new DICOMDIR file in */ dcmdir_filename = g_path_get_basename(dir_or_filename); if (g_strcmp0(dcmdir_filename, "DICOMDIR") == 0) if (dcmtk_test_dicom(dir_or_filename)) dirname = g_path_get_dirname(dir_or_filename); /* otherwise */ if (dirname == NULL) { dirname = g_strdup(dir_or_filename); } if (dcmdir_filename != NULL) g_free(dcmdir_filename); dcmdir_filename = g_strdup_printf("%s/DICOMDIR",dirname); /* make the directory we'll output the dicom data in if it doesn't already exist */ if (stat(dirname, &file_info) == 0) { if (!S_ISDIR(file_info.st_mode)) { g_warning(_("File already exists with name: %s"), dirname); goto cleanup; } } else { if (g_mkdir(dirname,0766) != 0) { g_warning(_("Couldn't create directory: %s"),dirname); goto cleanup; } } /* create the DICOMDIR, unless already made in which case we'll append to it */ if (stat(dcmdir_filename,&file_info) == 0) { if (!S_ISREG(file_info.st_mode)) { g_warning(_("Existing DICOMDIR file %s is not a regular file"),dcmdir_filename); goto cleanup; } status = dcm_dir.appendToDicomDir(DicomDirInterface::AP_Default,dcmdir_filename); if (status.bad()) { g_warning(_("Existing DICOMDIR file %s exists but is not appendable, error %s"),dcmdir_filename, status.text()); goto cleanup; } } else { status = dcm_dir.createNewDicomDir(DicomDirInterface::AP_Default,dcmdir_filename); if (status.bad()) { g_warning(_("Could not create DICOMDIR file %s, error %s"),dcmdir_filename, status.text()); goto cleanup; } } /* find a unique directory name */ i=0; temp_str = NULL; do { if (subdirname != NULL) g_free(subdirname); if (full_subdirname != NULL) g_free(full_subdirname); subdirname = g_strdup_printf("DCM%03d", i); full_subdirname = g_strdup_printf("%s%s%s",dirname,G_DIR_SEPARATOR_S,subdirname); i++; } while (stat(full_subdirname, &file_info) == 0); #if AMIDE_DEBUG g_print("selected subdirname %s\n", subdirname); #endif if (g_mkdir(full_subdirname,0766) != 0) { g_warning(_("Couldn't create directory: %s"),full_subdirname); } /* figure out our dimensions */ dim = AMITK_DATA_SET_DIM(ds); if (resliced) { if (bounding_box != NULL) output_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(bounding_box))); else output_volume = amitk_volume_new(); if (output_volume == NULL) goto cleanup; if (bounding_box != NULL) { corner = AMITK_VOLUME_CORNER(output_volume); } else { AmitkCorners corners; amitk_volume_get_enclosing_corners(AMITK_VOLUME(ds), AMITK_SPACE(output_volume), corners); corner = point_diff(corners[0], corners[1]); amitk_space_set_offset(AMITK_SPACE(output_volume), amitk_space_s2b(AMITK_SPACE(output_volume), corners[0])); } voxel_size = resliced_voxel_size; pixel_size.x = voxel_size.x; pixel_size.y = voxel_size.y; dim.x = (amide_intpoint_t) ceil(corner.x/voxel_size.x); dim.y = (amide_intpoint_t) ceil(corner.y/voxel_size.y); dim.z = (amide_intpoint_t) ceil(corner.z/voxel_size.z); corner.z = voxel_size.z; #ifdef AMIDE_DEBUG g_print("output dimensions %d %d %d, voxel size %f %f %f\n", dim.x, dim.y, dim.z, voxel_size.x, voxel_size.y, voxel_size.z); #else g_warning(_("dimensions of output data set will be %dx%dx%d, voxel size of %fx%fx%f"), dim.x, dim.y, dim.z, voxel_size.x, voxel_size.y, voxel_size.z); #endif } else { output_volume = amitk_volume_new(); amitk_space_copy_in_place(AMITK_SPACE(output_volume), AMITK_SPACE(ds)); voxel_size = AMITK_DATA_SET_VOXEL_SIZE(ds); corner = AMITK_VOLUME_CORNER(ds); } amitk_volume_set_corner(output_volume, corner); output_start_pt = AMITK_SPACE_OFFSET(output_volume); /* create the dicom data structure */ dcm_ds = dcm_format.getDataset(); dcm_metainfo = dcm_format.getMetaInfo(); dcm_metainfo->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage); /* required dicom entries */ insert_str(dcm_ds,DCM_SeriesInstanceUID,dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); /* if we're appending to a DICOMDIR, it would be a little better to copy the studyinstanceuid and frameofreferenceuid from whatever DICOM files are already stored... but it's simpler to just regenerate these values */ insert_str(dcm_ds,DCM_StudyInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); insert_str(dcm_ds,DCM_FrameOfReferenceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); insert_str(dcm_ds, DCM_StudyID,"0"); if (AMITK_DATA_SET_SERIES_NUMBER(dcm_ds) > 0) insert_int_str(dcm_ds, DCM_SeriesNumber, AMITK_DATA_SET_SERIES_NUMBER(dcm_ds)); else insert_str(dcm_ds, DCM_SeriesNumber,"0"); /* other stuff */ if (AMITK_DATA_SET_SUBJECT_NAME(ds) != NULL) insert_str(dcm_ds,DCM_PatientName, AMITK_DATA_SET_SUBJECT_NAME(ds)); if (AMITK_DATA_SET_SUBJECT_ID(ds) != NULL) insert_str(dcm_ds,DCM_PatientID, AMITK_DATA_SET_SUBJECT_ID(ds)); if (AMITK_DATA_SET_SUBJECT_DOB(ds) != NULL) insert_str(dcm_ds,DCM_PatientBirthDate, AMITK_DATA_SET_SUBJECT_DOB(ds)); /* set StudyDescription */ if (studyname != NULL) insert_str(dcm_ds,DCM_StudyDescription, studyname); else insert_str(dcm_ds,DCM_StudyDescription, AMITK_OBJECT_NAME(ds)); /* set SeriesDescription */ if (AMITK_OBJECT_NAME(ds) != NULL) insert_str(dcm_ds,DCM_SeriesDescription, AMITK_OBJECT_NAME(ds)); insert_double_str(dcm_ds,DCM_PatientWeight, AMITK_DATA_SET_SUBJECT_WEIGHT(ds)); switch(AMITK_DATA_SET_SUBJECT_SEX(ds)) { case AMITK_SUBJECT_SEX_MALE: insert_str(dcm_ds, DCM_PatientSex, "M"); break; case AMITK_SUBJECT_SEX_FEMALE: insert_str(dcm_ds, DCM_PatientSex, "F"); break; case AMITK_SUBJECT_SEX_UNKNOWN: default: insert_str(dcm_ds, DCM_PatientSex, "O"); break; } switch(AMITK_DATA_SET_SUBJECT_ORIENTATION(ds)) { case AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST: insert_str(dcm_ds,DCM_PatientPosition, "HFS"); break; case AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST: insert_str(dcm_ds,DCM_PatientPosition, "FFS"); break; case AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST: insert_str(dcm_ds,DCM_PatientPosition, "HFP"); break; case AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST: insert_str(dcm_ds,DCM_PatientPosition, "FFP"); break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST: insert_str(dcm_ds,DCM_PatientPosition, "HFDR"); break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST: insert_str(dcm_ds,DCM_PatientPosition, "FFDR"); break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST: insert_str(dcm_ds,DCM_PatientPosition, "HFDL"); break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST: insert_str(dcm_ds,DCM_PatientPosition, "FFDL"); break; case AMITK_SUBJECT_ORIENTATION_UNKNOWN: default: break; } switch(AMITK_DATA_SET_MODALITY(ds)) { case AMITK_MODALITY_PET: insert_str(dcm_ds,DCM_Modality, "PT"); dcm_metainfo->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_PositronEmissionTomographyImageStorage); break; case AMITK_MODALITY_SPECT: insert_str(dcm_ds,DCM_Modality, "ST"); dcm_metainfo->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_NuclearMedicineImageStorage); break; case AMITK_MODALITY_CT: insert_str(dcm_ds,DCM_Modality, "CT"); dcm_metainfo->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_CTImageStorage); break; case AMITK_MODALITY_MRI: insert_str(dcm_ds,DCM_Modality, "MR"); dcm_metainfo->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_MRImageStorage); break; case AMITK_MODALITY_OTHER: default: insert_str(dcm_ds,DCM_Modality, "OT"); dcm_metainfo->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_SecondaryCaptureImageStorage); break; } /* modality specific items */ switch(AMITK_DATA_SET_MODALITY(ds)) { case AMITK_MODALITY_PET: case AMITK_MODALITY_SPECT: /* create a radiopharmaceutical information sequence if we have the data */ if (!isnan(AMITK_DATA_SET_INJECTED_DOSE(ds))) { if (dcm_ds->findOrCreateSequenceItem(DCM_RadiopharmaceuticalInformationSequence, dcm_item, 0).good()) { insert_double_str(dcm_item, DCM_RadionuclideTotalDose, AMITK_DATA_SET_INJECTED_DOSE(ds)); } } insert_str(dcm_ds, DCM_DecayCorrection, "START"); /* assume things were decay corrected from the start of the scan */ break; case AMITK_MODALITY_MRI: if (!isnan(AMITK_DATA_SET_INVERSION_TIME(ds))) insert_double_str(dcm_ds, DCM_InversionTime, AMITK_DATA_SET_INVERSION_TIME(ds)); if (!isnan(AMITK_DATA_SET_ECHO_TIME(ds))) insert_double_str(dcm_ds, DCM_EchoTime, AMITK_DATA_SET_ECHO_TIME(ds)); if (!isnan(AMITK_DATA_SET_DIFFUSION_B_VALUE(ds))) { insert_double_str(dcm_ds, DCM_DiffusionBValue, AMITK_DATA_SET_DIFFUSION_B_VALUE(ds)); dcm_ds->putAndInsertFloat64(DCM_DiffusionGradientOrientation, AMITK_DATA_SET_DIFFUSION_DIRECTION(ds).x, 0, OFTrue); dcm_ds->putAndInsertFloat64(DCM_DiffusionGradientOrientation, AMITK_DATA_SET_DIFFUSION_DIRECTION(ds).y, 1, OFTrue); dcm_ds->putAndInsertFloat64(DCM_DiffusionGradientOrientation, AMITK_DATA_SET_DIFFUSION_DIRECTION(ds).z, 2, OFTrue); } break; default: break; } dcm_ds->putAndInsertUint16(DCM_Columns, dim.x); dcm_ds->putAndInsertUint16(DCM_Rows, dim.y); dcm_ds->putAndInsertUint16(DCM_NumberOfSlices, dim.z); /* number of planes per frame, not per file */ /* retired entry dcm_ds->putAndInsertUint16(DCM_Planes, 1); */ /* we save one plane per file */ /* past in the image type if we have that info*/ if (AMITK_DATA_SET_DICOM_IMAGE_TYPE(ds) != NULL) { dcm_metainfo->putAndInsertString(DCM_ImageType, AMITK_DATA_SET_DICOM_IMAGE_TYPE(ds)); } else { /* technically, ImageType is a required entry, so we should probably guess something */ dcm_metainfo->putAndInsertString(DCM_ImageType, "DERIVED\\SECONDARY"); } /* tag required for PET data, but we don't currently keep track of the data set underlying units */ dcm_ds->putAndInsertString(DCM_Units, "NONE"); /* add some dicom required stuff */ dcm_ds->putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2"); dcm_ds->putAndInsertUint16(DCM_SamplesPerPixel, 1); /* all our data is monochrome, 3 would be rgb */ /* if gated study, put in the gate information */ if (AMITK_DATA_SET_DIM_G(ds) > 1) { insert_str(dcm_ds,DCM_SeriesType, "GATED\\IMAGE"); dcm_ds->putAndInsertUint16(DCM_NumberOfTimeSlots, AMITK_DATA_SET_DIM_G(ds)); /* used for PET */ dcm_ds->putAndInsertSint32(DCM_NumberOfTemporalPositions, AMITK_DATA_SET_DIM_G(ds)); /* used for MR */ } if (AMITK_DATA_SET_DIM_T(ds) > 1) insert_str(dcm_ds,DCM_SeriesType, "DYNAMIC"); dcm_ds->putAndInsertUint16(DCM_NumberOfTimeSlices, AMITK_DATA_SET_DIM_T(ds)); /* figure out the format we'll be saving in */ if (!resliced) { switch (AMITK_DATA_SET_FORMAT(ds)) { case AMITK_FORMAT_SBYTE: case AMITK_FORMAT_UBYTE: format_changing=FALSE; format_size_short=FALSE; break; case AMITK_FORMAT_SSHORT: case AMITK_FORMAT_USHORT: format_changing=FALSE; format_size_short=TRUE; break; case AMITK_FORMAT_FLOAT: case AMITK_FORMAT_DOUBLE: case AMITK_FORMAT_SINT: case AMITK_FORMAT_UINT: format_changing=TRUE; /* well save as signed shorts */ format_size_short=TRUE; break; default: format_changing=TRUE; format_size_short=TRUE; g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } } else { format_changing=TRUE; format_size_short=TRUE; } dcm_ds->putAndInsertUint16(DCM_BitsAllocated, format_changing ? 8*amitk_format_sizes[AMITK_FORMAT_SSHORT] : 8*amitk_format_sizes[AMITK_DATA_SET_FORMAT(ds)]); dcm_ds->putAndInsertUint16(DCM_BitsStored, format_changing ? 8*amitk_format_sizes[AMITK_FORMAT_SSHORT] : 8*amitk_format_sizes[AMITK_DATA_SET_FORMAT(ds)]); dcm_ds->putAndInsertUint16(DCM_HighBit, format_changing ? 8*amitk_format_sizes[AMITK_FORMAT_SSHORT]-1 : 8*amitk_format_sizes[AMITK_DATA_SET_FORMAT(ds)]-1); dcm_ds->putAndInsertUint16(DCM_PixelRepresentation, format_changing ? amitk_format_signed[AMITK_FORMAT_SSHORT] : amitk_format_signed[AMITK_DATA_SET_FORMAT(ds)]); buffer_size = dim.y*dim.x*(format_changing ? amitk_format_sizes[AMITK_FORMAT_SSHORT] : amitk_format_sizes[AMITK_DATA_SET_FORMAT(ds)]); insert_double2_str(dcm_ds, DCM_PixelSpacing,voxel_size.y,voxel_size.x); insert_double_str(dcm_ds, DCM_SpacingBetweenSlices, voxel_size.z); insert_double_str(dcm_ds, DCM_SliceThickness, voxel_size.z); /* take a stab at converting the study date and putting it into the dicom header */ generate_dicom_date_and_time(AMITK_DATA_SET_SCAN_DATE(ds), 0.0, &date_str, &time_str); insert_str(dcm_ds, DCM_StudyDate, date_str); insert_str(dcm_ds, DCM_SeriesDate, date_str); insert_str(dcm_ds, DCM_AcquisitionDate, date_str); g_free(date_str); insert_str(dcm_ds, DCM_StudyTime, time_str); insert_str(dcm_ds, DCM_SeriesTime, time_str); insert_str(dcm_ds, DCM_AcquisitionTime, time_str); insert_str(dcm_ds, DCM_RadiopharmaceuticalStartTime,time_str); /* dose already corrected to start time */ g_free(time_str); /* put in orientation - see note in read_dicom_file about AMIDE versus DICOM orientation */ /* do flips for dicom convention */ amitk_axes_copy_in_place(axes, AMITK_SPACE_AXES(output_volume)); axes[AMITK_AXIS_X].y *= -1.0; axes[AMITK_AXIS_X].z *= -1.0; axes[AMITK_AXIS_Y].y *= -1.0; axes[AMITK_AXIS_Y].z *= -1.0; insert_double6_str(dcm_ds, DCM_ImageOrientationPatient, axes[AMITK_AXIS_X].x,axes[AMITK_AXIS_X].y,axes[AMITK_AXIS_X].z, axes[AMITK_AXIS_Y].x,axes[AMITK_AXIS_Y].y,axes[AMITK_AXIS_Y].z); /* and finally, get to the real work */ if (update_func != NULL) { temp_str = g_strdup_printf(_("Exporting File Through DCMTK:\n %s"), dirname); continue_work = (*update_func)(update_data, temp_str, (gdouble) 0.0); g_free(temp_str); } total_planes = dim.z*dim.g*dim.t; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (gint) rint(total_planes/AMITK_UPDATE_DIVIDER); image_num=0; j_voxel = zero_voxel; i_voxel = zero_voxel; for (i_voxel.t = 0; (i_voxel.t < dim.t) && (continue_work); i_voxel.t++) { insert_int_str(dcm_ds, DCM_ActualFrameDuration, (int) (1000*amitk_data_set_get_frame_duration(ds,i_voxel.t))); /* into ms */ insert_double_str(dcm_ds,DCM_FrameReferenceTime, 1000.0*amitk_data_set_get_start_time(ds,i_voxel.t)); /* ContentDate/Time is actually when the pixel data is generated, not when the acquisition is started... so technically the below is wrong. Only including this because ContentDate/Time is apparently a Type 1 (required) parameter. */ generate_dicom_date_and_time(AMITK_DATA_SET_SCAN_DATE(ds), amitk_data_set_get_start_time(ds, i_voxel.t), &date_str, &time_str); insert_str(dcm_ds, DCM_ContentDate, date_str); insert_str(dcm_ds, DCM_ContentTime, time_str); g_free(date_str); g_free(time_str); for (i_voxel.g = 0 ; (i_voxel.g < dim.g) && (continue_work); i_voxel.g++) { /* if gated study, write in gate info */ if (AMITK_DATA_SET_DIM_G(ds) > 1) { insert_int_str(dcm_ds, DCM_TemporalPositionIdentifier, i_voxel.g+1); /* starts at 1, not 0 */ insert_double_str(dcm_ds,DCM_TriggerTime, 1000.0*amitk_data_set_get_gate_time(ds,i_voxel.g)); /* into ms */ } /* reset the output slice */ amitk_space_set_offset(AMITK_SPACE(output_volume), output_start_pt); for (i_voxel.z = 0 ; (i_voxel.z < dim.z) && (continue_work); i_voxel.z++, image_num++) { if (update_func != NULL) { x = div(image_num,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } /* get our transfer buffer */ buffer = g_try_malloc0(buffer_size); if (buffer == NULL) { g_warning(_("Could not malloc transfer buffer")); goto cleanup; } /* set things up if resliced or format changing */ if (resliced) { slice = amitk_data_set_get_slice(ds, amitk_data_set_get_start_time(ds,i_voxel.t), amitk_data_set_get_frame_duration(ds,i_voxel.t), i_voxel.g, pixel_size, output_volume); if ((AMITK_DATA_SET_DIM_X(slice) != dim.x) || (AMITK_DATA_SET_DIM_Y(slice) != dim.y)) { g_warning(_("Error in generating resliced data, %dx%d != %dx%d"), AMITK_DATA_SET_DIM_X(slice), AMITK_DATA_SET_DIM_Y(slice), dim.x, dim.y); goto cleanup; } min = amitk_data_set_get_global_min(slice); max = amitk_data_set_get_global_max(slice); } else if (format_changing) { amitk_data_set_slice_calc_min_max(ds, i_voxel.t, i_voxel.g, i_voxel.z, &min, &max); } /* transfer into the new buffer */ if (format_changing) { max = MAX(fabs(min), max); sshort_buffer = (amitk_format_SSHORT_t *) buffer; i=0; for (i_voxel.y=0, j_voxel.y=0; i_voxel.y < dim.y; i_voxel.y++, j_voxel.y++) for (i_voxel.x=0, j_voxel.x = 0; i_voxel.x < dim.x; i_voxel.x++, j_voxel.x++,i++) { if (resliced) value = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice, j_voxel); else value = amitk_data_set_get_value(ds, i_voxel); sshort_buffer[i] = (amitk_format_SSHORT_t) rint(amitk_format_max[AMITK_FORMAT_SSHORT]*value/max); } } else { /* short or char type */ i_voxel.y = 0; i_voxel.x = 0; memcpy(buffer, amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), i_voxel), buffer_size); } /* convert to little endian */ /* note, ushort conversion is exactly the same as sshort, so the below works */ if (format_size_short) { i=0; sshort_buffer = (amitk_format_SSHORT_t *) buffer; for (i_voxel.y=0; i_voxel.y < dim.y; i_voxel.y++) for (i_voxel.x=0; i_voxel.x < dim.x; i_voxel.x++,i++) sshort_buffer[i] = GINT16_TO_LE(sshort_buffer[i]); } /* and store */ dcm_ds->putAndInsertUint8Array(DCM_PixelData, (Uint8*) buffer, buffer_size); dcm_ds->putAndInsertUint16(DCM_ImageIndex, image_num); /* store the scaling factor and offset */ insert_double_str(dcm_ds,DCM_RescaleSlope, (resliced || format_changing) ? max/amitk_format_max[AMITK_FORMAT_SSHORT] : amitk_data_set_get_scaling_factor(ds,i_voxel)); insert_double_str(dcm_ds,DCM_RescaleIntercept, (resliced || format_changing) ? 0.0 : amitk_data_set_get_scaling_factor(ds,i_voxel)*amitk_data_set_get_scaling_intercept(ds,i_voxel)); /* and get it an identifier */ dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT); insert_str(dcm_ds,DCM_SOPInstanceUID,uid); /* set the meta info as well */ dcm_metainfo->putAndInsertString(DCM_MediaStorageSOPInstanceUID,uid); /* and some other data */ insert_int_str(dcm_ds,DCM_InstanceNumber, image_num); /* and save it's position in space - see note in dicom_read_file about DICOM versus AMIDE conventions */ dicom_offset = AMITK_SPACE_OFFSET(output_volume); dicom_offset.y = -1.0*dicom_offset.y; /* DICOM specifies y axis in wrong direction */ dicom_offset.z = -1.0*dicom_offset.z; /* DICOM specifies z axis in wrong direction */ insert_double3_str(dcm_ds, DCM_ImagePositionPatient, dicom_offset.x,dicom_offset.y, dicom_offset.z); insert_double_str(dcm_ds, DCM_SliceLocation, dicom_offset.z); /* and write it on out */ filename = g_strdup_printf("%s%sIMG%05d",subdirname,G_DIR_SEPARATOR_S,image_num); full_filename = g_strdup_printf("%s%s%s",dirname, G_DIR_SEPARATOR_S,filename); status = dcm_format.saveFile(full_filename, EXS_LittleEndianExplicit); if (status.bad()) { g_warning(_("couldn't write out file %s, error %s"), full_filename, status.text()); goto cleanup; } /* add it to the DICOMDIR file */ status = dcm_dir.addDicomFile(filename,dirname); if (status.bad()) { g_warning(_("couldn't append file %s to DICOMDIR %s, error %s"), filename, dirname, status.text()); goto cleanup; } /* cleanups */ if (filename != NULL) { g_free(filename); filename = NULL; } if (full_filename != NULL) { g_free(full_filename); full_filename = NULL; } if (buffer != NULL) { g_free(buffer); buffer = NULL; } if (slice != NULL) slice = AMITK_DATA_SET(amitk_object_unref(slice)); /* advance for next iteration */ new_offset = zero_point; new_offset.z += voxel_size.z; amitk_space_set_offset(AMITK_SPACE(output_volume), amitk_space_s2b(AMITK_SPACE(output_volume), new_offset)); } /* i_voxel.z */ } /* i_voxel.g */ } /* i_voxel.t */ status = dcm_dir.writeDicomDir(); if (status.bad()) { g_warning(_("Failed to write DICOMDIR file, error %s\n"), status.text()); goto cleanup; } successful = TRUE; /* whew! made it */ cleanup: if (output_volume != NULL) output_volume = AMITK_VOLUME(amitk_object_unref(output_volume)); if (slice != NULL) slice = AMITK_DATA_SET(amitk_object_unref(slice)); if (buffer != NULL) g_free(buffer); if (filename != NULL) g_free(filename); if (full_filename != NULL) g_free(full_filename); if (subdirname != NULL) g_free(subdirname); if (full_subdirname != NULL) g_free(full_subdirname); if (dirname != NULL) g_free(dirname); if (dcmdir_filename != NULL) g_free(dcmdir_filename); if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); setlocale(LC_NUMERIC, saved_time_locale); setlocale(LC_NUMERIC, saved_numeric_locale); g_free(saved_time_locale); g_free(saved_numeric_locale); return successful; } #ifdef AMIDE_LIBOPENJP2_SUPPORT /* Read num_bytes from user_data (from stream) into buffer. Note that user_data may be of any type, * it is our responsibility to extract the data from it. In our case user_data has been set to comp_buffer * and we expect this function to be called only once with num_bytes == comp_lenght... */ static OPJ_SIZE_T opj_input_memory_stream_read(void * buffer, OPJ_SIZE_T num_bytes, void * user_data) { memcpy(buffer, user_data, num_bytes); return num_bytes; } /* decompress comp_buffer (comp_length bytes) into raw_buffer (raw_length) * TODO J2K format assumed */ static gboolean j2k_decompress(guint32 comp_length, const guint8 *comp_buffer, guint32 raw_length, guint8 *raw_buffer) { gboolean return_val = FALSE; /* openjpeg stuff */ opj_codec_t * codec=NULL; opj_image_t * image=NULL; opj_stream_t * stream=NULL; opj_dparameters_t param; // Decoder parameters OPJ_UINT32 tile_index; // J2K images may contain several tiles OPJ_UINT32 tile_size; OPJ_INT32 current_tile_x0, current_tile_y0, current_tile_x1, current_tile_y1; // tile coordinates OPJ_UINT32 num_comps; // Number of components in tile (not used)) OPJ_BOOL go_on = OPJ_TRUE; // Indicates more tiles to process guint8 *pdata; guint32 tile; stream = opj_stream_create(comp_length, OPJ_TRUE); // Internal buffer can hold the whole stream in one read call if (!stream) { goto error; } opj_stream_set_user_data(stream, (void *)comp_buffer, NULL); opj_stream_set_user_data_length(stream, (OPJ_UINT64)comp_length); opj_stream_set_read_function(stream, opj_input_memory_stream_read); /* Set the default decoding parameters*/ opj_set_default_decoder_parameters(¶m); /* do not use layer decoding limitations */ param.cp_layer = 0; /* do not use resolutions reductions */ param.cp_reduce = 0; /* to decode only a part of the image data */ /*opj_restrict_decoding(&l_param,0,0,1000,1000);*/ /* Get a decoder handle */ if ((codec = opj_create_decompress(OPJ_CODEC_J2K)) == NULL) { goto error; } /* Setup the decoder decoding parameters using user parameters */ if (!opj_setup_decoder(codec, ¶m)) { goto error; } /* Read the main header of the codestream and if necessary the JP2 boxes */ if (!opj_read_header(stream, codec, &image)) { goto error; } // g_debug("J2K image grid (x0, y0, x1, y1): (%d, %d, %d, %d), components: %d", image->x0, image->y0, image->x1, image->y1, image->numcomps); /* We do not yet support color images */ if (image->numcomps > 1) { g_warning(_("JPEG 2000 color images not supported")); goto error; } /* decode the whole image area by default */ pdata = raw_buffer; tile = 0; while (go_on) { if (!opj_read_tile_header(codec, stream, &tile_index, &tile_size, ¤t_tile_x0, ¤t_tile_y0, ¤t_tile_x1, ¤t_tile_y1, &num_comps, &go_on)) { goto error; } if (go_on) { tile++; if (pdata + tile_size > raw_buffer + raw_length) { g_warning(_("raw_buffer size exceeded when decoding tile %u"), tile); goto error; } if (!opj_decode_tile_data(codec, tile_index, (OPJ_BYTE *)pdata, tile_size, stream)) { goto error; } pdata+= tile_size; /** now should inspect image to know the reduction factor and then how to behave with data */ } } // g_debug("J2K processed %u tiles", tile); return_val = opj_end_decompress(codec, stream); error: /* Free memory */ if (image) opj_image_destroy(image); if (codec) opj_destroy_codec(codec); if (stream) opj_stream_destroy(stream); return return_val; } /* Extract JPEG 2000 encoding PixelData from the DcmDataset and return the buffer containing * decompressed image(s). Note that MultiFrame DICOM files nor multi-tile JPEG 2000 images * have been tested because of lack of sample data. */ static void * j2k_to_raw(DcmDataset *dcm_data, AmitkDataSet const *ds) { /* Amitk stuff */ AmitkRawData *raw_data; gint format_size; amide_intpoint_t z; guint32 data_size; // overall buffer size for X * Y * Z dimensions guint32 image_size; // for one decompressed image guint8 *data = NULL; // our buffer to hold the z * decompressed images guint8 *pdata; /* DCMTK stuff */ DcmElement *element; DcmPixelData *pixel_data; DcmPixelSequence *pixel_sequence; // = NULL; E_TransferSyntax transfer_syntax; // = EXS_Unknown; const DcmRepresentationParameter *representation_parameter; // = NULL; DcmPixelItem *pixel_item; // = NULL; Uint8 *pixel_buffer; // to hold one compressed frame fragment Uint32 pixel_length; Uint32 num_frames; // Number of frames within PixelData Uint32 frame; // current frame Uint32 *frame_offset; // Pointer to an array of frame offset Uint32 offset; // current offset gboolean frame_in_progress; Uint8 *temp_buffer = NULL; // temporary buffer to process current frame Uint32 temp_length = 0; // temporary buffer length, may increase if several fragments (= 0 to avoid -Wmaybe-uninitialized) Uint8 *temp_buffer_tmp; Uint32 old_temp_length; OFCondition result; raw_data = ds->raw_data; format_size = amitk_format_sizes[AMITK_RAW_DATA_FORMAT(raw_data)]; z = AMITK_DATA_SET_DIM_Z(ds); image_size = format_size * AMITK_RAW_DATA_DIM_X(raw_data) * AMITK_RAW_DATA_DIM_Y(raw_data); data_size = image_size * AMITK_RAW_DATA_DIM_Z(raw_data); data = (guint8 *)g_try_malloc(data_size); if (data == NULL) { g_warning(_("Couldn't allocate space for the data structure to hold data %d bytes"), data_size); goto error; } result = dcm_data->findAndGetElement(DCM_PixelData, element); if (result.bad()) { goto error; } pixel_data = OFstatic_cast(DcmPixelData*, element); // Find the key that is needed to access the right representation of the data within DCMTK pixel_data->getOriginalRepresentationKey(transfer_syntax, representation_parameter); // Access original data representation and get result within pixel sequence result = pixel_data->getEncapsulatedRepresentation(transfer_syntax, representation_parameter, pixel_sequence); if (result != EC_Normal) { goto error; } // First item is offset table result = pixel_sequence->getItem(pixel_item, 0); if (result.bad()) { goto error; } pixel_length = pixel_item->getLength(); if (pixel_length == 0) { // MonoFrame num_frames = 1; } else { num_frames = pixel_length / 4; } if (num_frames != (Uint32)z) { g_warning(_("Number of frames expected (%d) do not tally found (%d)"), z, num_frames); goto error; } // Get the array of frame offset result = pixel_item->getUint32Array(frame_offset); if (result.bad()) { // Surpisingly this would return bad even if there is an offset table for a single fragment frame_offset = NULL; } /* TODO pass transfer_syntax to j2k_decompress for proper handling (here assumed EXS_JPEG2000) */ pdata = data; offset = 0; frame = 0; frame_in_progress = FALSE; for (int frag = 1; ; frag++) { result = pixel_sequence->getItem(pixel_item, frag); if (result.bad()) { // indicates sequence end break; } // Get the length of this pixel item (i.e. fragment) pixel_length = pixel_item->getLength(); if (pixel_length == 0) { g_warning(_("Expecting a not empty fragment")); goto error; } // get the compressed data fragment for this pixel item result = pixel_item->getUint8Array(pixel_buffer); if (result != EC_Normal) { goto error; } if (frame_in_progress) { // Has the offset exceeded the current frame ? if (!frame_offset || (frame == num_frames -1) || (offset < frame_offset[frame+1])) { // No or no frame_offset table or last frame // realloc old_temp_length = temp_length; temp_length += pixel_length; temp_buffer_tmp = (Uint8 *)g_try_realloc(temp_buffer, temp_length); if (temp_buffer_tmp == NULL) { g_warning(_("Couldn't allocate space for thetemp_buffer_tmp structure to hold data %d bytes"), temp_length); goto error; } temp_buffer = temp_buffer_tmp; // append pixel_buffer memcpy(temp_buffer+old_temp_length, pixel_buffer, pixel_length); } else { // yes or no frame_offset table if (!j2k_decompress(temp_length, temp_buffer, image_size, pdata)) { goto error; } pdata+= image_size; frame++; g_free(temp_buffer); // allocate a new temp buffer temp_length = pixel_length; temp_buffer = (Uint8 *)g_try_malloc(temp_length); if (temp_buffer == NULL) { g_warning(_("Couldn't allocate space for the temp_buffer to hold data %d bytes"), temp_length); goto error; } memcpy(temp_buffer, pixel_buffer, temp_length); } } else { // first frame // malloc temp_buffer temp_length = pixel_length; temp_buffer = (Uint8 *)g_try_malloc(temp_length); if (temp_buffer == NULL) { g_warning(_("Couldn't allocate space for the temp_buffer to hold data %d bytes"), temp_length); goto error; } // copy pixel_buffer memcpy(temp_buffer, pixel_buffer, temp_length); frame_in_progress = TRUE; } // update offset offset+= pixel_length + 8; // must account for Item tag + Item length // sanity check frame < num_frames if (frame >= num_frames) { // We have a problem g_warning(_("Too many frames: %d ! Expected %d"), frame+1, num_frames); goto error; } } if (frame_in_progress) { // should be the case... // decompress if (!j2k_decompress(temp_length, temp_buffer, image_size, pdata)) { goto error; } pdata+= image_size; frame++; g_free(temp_buffer); } else { g_warning(_("Expecting more fragments to come...")); goto error; } return data; error: if (temp_buffer) g_free(temp_buffer); if (data) g_free(data); return NULL; } #endif /* AMIDE_LIBOPENJP2_SUPPORT */ #endif /* AMIDE_LIBDCMDATA_SUPPORT */ amide-1.0.6/amide-current/src/dcmtk_interface.h000066400000000000000000000033031423227705100214200ustar00rootroot00000000000000/* dcmtk_interface.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2005-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBDCMDATA_SUPPORT #ifndef __DCMTK_INTERFACE_H__ #define __DCMTK_INTERFACE_H__ /* includes always needed with this file */ #include "amitk_data_set.h" G_BEGIN_DECLS extern const gchar * dcmtk_version; /* external functions */ gboolean dcmtk_test_dicom(const gchar * filename); GList * dcmtk_import(const gchar * filename, gchar ** pstudyname, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data); gboolean dcmtk_export(AmitkDataSet * ds, const gchar * dir_or_filename, const gchar * studyname, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data); G_END_DECLS #endif /* __DCMTK_INTERFACE_H__ */ #endif /* AMIDE_LIBDCMDATA_SUPPORT */ amide-1.0.6/amide-current/src/fads.c000066400000000000000000002113061423227705100172120ustar00rootroot00000000000000/* fads.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBGSL_SUPPORT #include #include #include #include #include "fads.h" #include "amitk_data_set_FLOAT_0D_SCALING.h" #define FINAL_MU 1e-07 gchar * fads_minimizer_algorithm_name[NUM_FADS_MINIMIZERS] = { // N_("Steepest Descent"), N_("Fletcher-Reeves conjugate gradient"), N_("Polak-Ribiere conjugate gradient"), // N_("vector BFGS conjugate gradient") }; gchar * fads_type_name[] = { N_("Principle Component Analysis"), N_("Penalized Least Squares Factor Analysis"), N_("2 compartment model") }; gchar * fads_type_explanation[] = { N_("Priniciple Component Analysis based on singular value " "decomposition."), N_("Principle component analysis with positivity constraints " "and a penalized least squares objective, an adaptation " "of Sitek, et al., IEEE Trans. Med. Imag., 2002. If beta " "is set to zero, this is normal factor analysis, similar to " "Di Paola, et al., IEEE Trans. Nuc. Sci., 1982"), N_("Standard 2 compartment model") }; #include "../pixmaps/two_compartment.h" const guint8 * fads_type_icon[NUM_FADS_TYPES] = { NULL, NULL, two_compartment }; static gint perform_svd(gsl_matrix * a, gsl_matrix * v, gsl_vector * s) { gint status; gsl_vector * w; w = gsl_vector_alloc(s->size); g_return_val_if_fail(w != NULL, -1); status = gsl_linalg_SV_decomp(a, v, s, w); gsl_vector_free(w); return status; } void fads_svd_factors(AmitkDataSet * data_set, gint * pnum_factors, gdouble ** pfactors) { gsl_matrix * matrix_a=NULL; gsl_matrix * matrix_v=NULL; gsl_vector * vector_s=NULL; AmitkVoxel dim, i_voxel; gint m,n, i; amide_data_t value; gdouble * factors; gint status; g_return_if_fail(AMITK_IS_DATA_SET(data_set)); dim = AMITK_DATA_SET_DIM(data_set); n = dim.t; m = dim.x*dim.y*dim.z*dim.g; if (n == 1) { g_warning(_("need dynamic data set in order to perform factor analysis")); goto ending; } /* do all the memory allocations upfront */ if ((matrix_a = gsl_matrix_alloc(m,n)) == NULL) { g_warning(_("Failed to allocate %dx%d array"), m,n); goto ending; } if ((matrix_v = gsl_matrix_alloc(n,n)) == NULL) { g_warning(_("Failed to allocate %dx%d array"), n,n); goto ending; } if ((vector_s = gsl_vector_alloc(n)) == NULL) { g_warning(_("Failed to allocate %d vector"), n); goto ending; } /* fill in the a matrix */ for (i_voxel.t = 0; i_voxel.t < dim.t; i_voxel.t++) { i = 0; for (i_voxel.g = 0; i_voxel.g < dim.g; i_voxel.g++) { for (i_voxel.z = 0; i_voxel.z < dim.z; i_voxel.z++) for (i_voxel.y = 0; i_voxel.y < dim.y; i_voxel.y++) for (i_voxel.x = 0; i_voxel.x < dim.x; i_voxel.x++, i++) { value = amitk_data_set_get_value(data_set, i_voxel); gsl_matrix_set(matrix_a, i, i_voxel.t, value); } } } /* get the singular value decomposition of the correlation matrix -> matrix_a = U*S*Vt notes: the function will place the value of U into matrix_a gsl_linalg_SV_decomp_jacobi will return an unsuitable matrix_v, don't use it */ status = perform_svd(matrix_a, matrix_v, vector_s); if (status != 0) g_warning(_("SV decomp returned error: %s"), gsl_strerror(status)); /* transferring data */ if (pnum_factors != NULL) *pnum_factors = n; if (pfactors != NULL) { factors = g_try_new(gdouble, n); if (factors == NULL) { g_warning(_("Failed to allocate %d factor array"), n); goto ending; } *pfactors=factors; for (i=0; i= 0) { if (status == GSL_SUCCESS) fprintf(file_pointer, "# found minimal after %d iterations\n", iter); else if (status == GSL_CONTINUE) fprintf(file_pointer, "# user terminated minization after %d iterations.\n", iter); else { fprintf(file_pointer, "# No minimum after %d iterations, exited with:\n", iter); fprintf(file_pointer, "# %s\n", gsl_strerror(status)); } fprintf(file_pointer, "#\n"); } return; } static gsl_multimin_fdfminimizer * alloc_fdfminimizer(fads_minimizer_algorithm_t minimizer_algorithm, gint num_variables) { switch(minimizer_algorithm) { // case FADS_MINIMIZER_STEEPEST_DESCENT: // return gsl_multimin_fdfminimizer_alloc(gsl_multimin_fdfminimizer_steepest_descent, // num_variables); // break; case FADS_MINIMIZER_CONJUGATE_FR: return gsl_multimin_fdfminimizer_alloc(gsl_multimin_fdfminimizer_conjugate_fr, num_variables); break; case FADS_MINIMIZER_CONJUGATE_PR: return gsl_multimin_fdfminimizer_alloc(gsl_multimin_fdfminimizer_conjugate_pr, num_variables); break; // case FADS_MINIMIZER_VECTOR_BFGS: // return gsl_multimin_fdfminimizer_alloc(gsl_multimin_fdfminimizer_vector_bfgs, // num_variables); // break; default: g_error("no such minimizer algorithm %d\n", minimizer_algorithm); return NULL; break; } } static void perform_pca(AmitkDataSet * data_set, gint num_factors, gsl_matrix ** return_u, gsl_vector ** return_s, gsl_matrix ** return_v) { AmitkVoxel dim, i_voxel; guint num_voxels, num_frames; gsl_matrix * u = NULL; gsl_matrix * v = NULL; gsl_vector * s = NULL; gsl_matrix * small_u; gsl_matrix * small_v; gsl_vector * small_s; guint i, f, j; gint status; gdouble total; dim = AMITK_DATA_SET_DIM(data_set); num_voxels = dim.x*dim.y*dim.z*dim.g; num_frames = dim.t; u = gsl_matrix_alloc(num_voxels, num_frames); if (u == NULL) { g_warning(_("failed to alloc matrix, size %dx%d"), num_voxels, num_frames); goto ending; } if ((v = gsl_matrix_alloc(num_frames,num_frames)) == NULL) { g_warning(_("Failed to allocate %dx%d array"), num_frames, num_frames); goto ending; } if ((s = gsl_vector_alloc(num_frames)) == NULL) { g_warning(_("Failed to allocate %d vector"), num_frames); goto ending; } /* copy the info into the matrix */ for (i_voxel.t = 0; i_voxel.t < num_frames; i_voxel.t++) { i = 0; for (i_voxel.g = 0; i_voxel.g < dim.g; i_voxel.g++) for (i_voxel.z = 0; i_voxel.z < dim.z; i_voxel.z++) for (i_voxel.y = 0; i_voxel.y < dim.y; i_voxel.y++) for (i_voxel.x = 0; i_voxel.x < dim.x; i_voxel.x++, i++) gsl_matrix_set(u, i, i_voxel.t, amitk_data_set_get_value(data_set, i_voxel)); } /* do Singular Value decomposition */ status = perform_svd(u, v, s); if (status != 0) g_warning(_("SV decomp returned error: %s"), gsl_strerror(status)); /* do some obvious flipping */ for (f=0; fsum_factors_equal_one) { for (k=0, i=p->alpha_offset; k < p->num_voxels; k++, i+=p->num_factors) { total = -1.0; for (f=0; fnum_factors; f++) total += gsl_vector_get(v, i+f); p->ec_a[k] = total; } } /* blood curve constraints */ for (i=0; inum_blood_curve_constraints; i++) { bc = gsl_vector_get(v, p->blood_curve_constraint_frame[i]); p->ec_bc[i] = bc - p->blood_curve_constraint_val[i]; } } static void pls_calc_forward_error(pls_params_t * p, const gsl_vector *v) { gint i, k, f; AmitkVoxel i_voxel; gdouble inner; gdouble alpha; gdouble factor; for (i_voxel.t=0; i_voxel.tdim.t; i_voxel.t++) { i=p->alpha_offset; /* what to skip in v to get to the coefficients */ k=0; for (i_voxel.g=0; i_voxel.gdim.g; i_voxel.g++) { for (i_voxel.z=0; i_voxel.zdim.z; i_voxel.z++) { for (i_voxel.y=0; i_voxel.ydim.y; i_voxel.y++) { for (i_voxel.x=0; i_voxel.xdim.x; i_voxel.x++, i+=p->num_factors, k+=p->num_frames) { inner = 0.0; for (f=0; f< p->num_factors; f++) { alpha = gsl_vector_get(v, i+f); factor = gsl_vector_get(v, f*p->num_frames+i_voxel.t); inner += alpha*factor; } p->forward_error[k+i_voxel.t] = inner - amitk_data_set_get_value(p->data_set,i_voxel); } } } } } return; } static gdouble pls_calc_function(pls_params_t * p, const gsl_vector *v) { gdouble ls_answer=0.0; gdouble neg_answer=0.0; gdouble orth_answer=0.0; gdouble blood_answer=0.0; gdouble temp, lambda, factor, alpha; gint i, j, f, l; /* the Least Squares objective */ ls_answer = 0.0; for (j=0; jnum_frames; j++) { for (i=0; inum_voxels; i++) { temp = p->forward_error[i*p->num_frames+j]; ls_answer += p->weight[j]*temp*temp; } } p->ls = ls_answer; /* the non-negativity constraints */ neg_answer = 0.0; for (f=0; fnum_factors; f++) { for (j=0; jnum_frames; j++) { factor = gsl_vector_get(v, f*p->num_frames+j); lambda = p->lmi_f[f*p->num_frames+j]; if ((factor-p->mu*lambda) < 0.0) neg_answer += factor*(factor/(2.0*p->mu) - lambda); else neg_answer -= lambda*lambda*p->mu/2.0; } } for (l=0, i=p->alpha_offset; lnum_voxels; l++, i+=p->num_factors) { for (f=0; fnum_factors; f++) { alpha = gsl_vector_get(v, i+f); lambda = p->lmi_a[l*p->num_factors+f]; if ((alpha-p->mu*lambda) < 0.0) neg_answer += alpha*(alpha/(2.0*p->mu) - lambda); else neg_answer -= lambda*lambda*p->mu/2.0; } } /* the sum of alpha's == 1 constraint */ if (p->sum_factors_equal_one) { for (i=0; i< p->num_voxels; i++) neg_answer += p->ec_a[i]*(p->ec_a[i]/(2.0*p->mu) - p->lme_a[i]); } p->neg = neg_answer; /* the orthogonality objective */ orth_answer = 0.0; #if 0 for (l=0; lnum_voxels; l++) if ((p->coef_total[l] < 1.0) && (p->coef_total[l] > 0)) orth_answer += (2*p->coef_total[l]-p->coef_squared_total[l]-p->coef_total[l]*p->coef_total[l]); orth_answer *= 0.5; p->orth = orth_answer; orth_answer *= 0.5*p->b; /* weight this objective by b */ #endif /* blood curve constraints */ blood_answer = 0; for (i=0; inum_blood_curve_constraints; i++) blood_answer += p->ec_bc[i]*(p->ec_bc[i]/(2.0*p->mu) - p->lme_bc[i]); p->blood = blood_answer; return ls_answer+neg_answer+orth_answer+blood_answer; } static void pls_calc_derivative(pls_params_t * p, const gsl_vector *v, gsl_vector *df) { gdouble ls_answer=0.0; gdouble neg_answer=0.0; gdouble orth_answer; gdouble blood_answer=0.0; gdouble factor, alpha, lambda; gint i, j, k, l, q; //f /* calculate first for the factor variables */ for (q= 0; q < p->num_factors; q++) { for (j=0; jnum_frames; j++) { factor = gsl_vector_get(v, q*p->num_frames+j); /* the Least Squares objective */ ls_answer = 0.0; /* p->coef_offset is what to skip in v to get to the coefficients */ for (i=p->alpha_offset, k=0; k < p->num_frames*p->num_voxels; i+=p->num_factors, k+=p->num_frames) { alpha = gsl_vector_get(v, i+q); ls_answer += alpha*p->forward_error[k+j]; } ls_answer *= 2.0*p->weight[j]; /* the non-negativity objective */ lambda = p->lmi_f[q*p->num_frames+j]; if ((factor - p->mu*lambda) < 0.0) neg_answer = factor/p->mu-lambda; else neg_answer = 0; /* blood curve constraints */ blood_answer = 0; if (q == 0) /* 1st factor is blood curve */ for (i=0; inum_blood_curve_constraints; i++) if (p->blood_curve_constraint_frame[i] == j) blood_answer += p->ec_bc[i]/p->mu - p->lme_bc[i]; gsl_vector_set(df, q*p->num_frames+j, ls_answer+neg_answer+blood_answer); } } /* now calculate for the coefficient variables */ for (q= 0; q < p->num_factors; q++) { for (i=p->alpha_offset, k=0, l=0; i < p->num_variables; i+=p->num_factors, k+=p->num_frames, l++) { alpha = gsl_vector_get(v, i+q); /* the Least Squares objective */ ls_answer = 0; for (j=0; jnum_frames; j++) { factor = gsl_vector_get(v, q*p->num_frames+j); ls_answer += p->weight[j]*p->forward_error[k+j]*factor; } ls_answer *= 2.0; /* the non-negativity and <= 1 objective */ lambda = p->lmi_a[l*p->num_factors+q]; if ((alpha-p->mu*lambda) < 0.0) neg_answer = alpha/p->mu-lambda; else neg_answer = 0; /* the sum of alpha's == 1 constraint */ if (p->sum_factors_equal_one) { neg_answer += p->ec_a[l]/p->mu - p->lme_a[l]; } /* the orthogonality objective */ #if 0 if ((p->coef_total[l] < 1.0) && (p->coef_total[l] > 0)) orth_answer = p->b*(1.0-alpha-p->coef_total[l]); else #endif orth_answer = 0; gsl_vector_set(df, i+q, ls_answer+neg_answer+orth_answer); } } return; } /* calculate the penalized least squares objective function */ static double pls_f (const gsl_vector *v, void *params) { pls_params_t * p = params; pls_calc_constraints(p,v); pls_calc_forward_error(p, v); return pls_calc_function(p, v); } /* The gradient of f, df = (df/dCip, df/dFpt). */ static void pls_df (const gsl_vector *v, void *params, gsl_vector *df) { pls_params_t * p = params; pls_calc_constraints(p,v); pls_calc_forward_error(p, v); pls_calc_derivative(p, v, df); return; } /* Compute both f and df together. */ static void pls_fdf (const gsl_vector *v, void *params, double *f, gsl_vector *df) { pls_params_t * p = params; pls_calc_constraints(p,v); pls_calc_forward_error(p, v); *f = pls_calc_function(p,v); pls_calc_derivative(p, v, df); return; } /* run the penalized least squares algorithm for factor analysis. -this method is described in: Sitek, et al., IEEE Trans Med Imaging, 21, 2002, pages 216-225 differences in my version: 1-instead of reweighting the coefficents at the end of the fitting, the coefficients are penalized for being greater then 1, and their total for each voxel has to equal 1. 2-weights the least square terms by their respective frame duration Constrained optimization is done by using an augmented lagrangian method, see Chapter 17.4 of "Numerical Optimization" - Nocedal & Wright. gsl supports minimizing on only a single vector space, so that vector is setup as follows M = num_voxels; N = num_frames F = num_factors; factors = [F*N] coefficients = [M*F] x = [factor(1,1) factor(1,2) ...... factor(1,N) factor(2,1) factor(2,2) ...... factor(2,N) .. .. .. factor(F,1 factor(F,2) ...... factor(F,N) alpha(1,1) alpha(1,2) ...... alpha(1,F) alpha(2,1) alpha(2,2) ...... alpha(2,F) .. .. .. alpha(M,1) alpha(M,2) ...... alpha(M,F)] forward_error is [M*N] */ void fads_pls(AmitkDataSet * data_set, gint num_factors, fads_minimizer_algorithm_t minimizer_algorithm, gint max_iterations, gdouble stopping_criteria, gboolean sum_factors_equal_one, gdouble beta, gchar * output_filename, gint num_blood_curve_constraints, gint * blood_curve_constraint_frame, gdouble * blood_curve_constraint_val, GArray * initial_curves, AmitkUpdateFunc update_func, gpointer update_data) { gsl_multimin_fdfminimizer * multimin_minimizer = NULL; gsl_multimin_function_fdf multimin_func; AmitkVoxel dim; pls_params_t p; gint inner_iter=0; gint outer_iter=0; gsl_vector * initial=NULL; gint i, f, j; gint status; FILE * file_pointer=NULL; gchar * temp_string; gboolean continue_work=TRUE; gdouble alpha, factor; amide_time_t frame_midpoint, frame_duration; gdouble init_value; gdouble magnitude; AmitkDataSet * new_ds; AmitkVoxel i_voxel; gdouble current_beta=0.0; AmitkViewMode i_view_mode; GTimer * timer=NULL; gboolean new_outer; #if AMIDE_DEBUG div_t x; #endif g_return_if_fail(AMITK_IS_DATA_SET(data_set)); dim = AMITK_DATA_SET_DIM(data_set); g_return_if_fail(num_factors <= dim.t); /* initialize our parameter structure */ p.data_set = data_set; p.dim = dim; p.mu = 1000; p.b = 0.0; p.ls = 0.0; p.neg = 0.0; p.orth = 0.0; p.blood = 0.0; p.num_voxels = dim.g*dim.z*dim.y*dim.x; p.num_frames = dim.t; p.num_factors = num_factors; p.alpha_offset = p.num_factors*p.num_frames; p.num_variables = p.alpha_offset+p.num_factors*p.num_voxels; p.sum_factors_equal_one = sum_factors_equal_one; p.num_blood_curve_constraints = num_blood_curve_constraints; p.blood_curve_constraint_frame = blood_curve_constraint_frame; p.blood_curve_constraint_val = blood_curve_constraint_val; p.forward_error = NULL; p.weight = NULL; p.ec_a = NULL; p.ec_bc = NULL; p.lme_a = NULL; p.lme_bc = NULL; p.lmi_a = NULL; p.lmi_f = NULL; /* more sanity checks */ for (i=0; ilen < p.num_frames*p.num_factors) { g_warning(_("Supplied initial curves have %d elements, need %d x %d = %d elements"), initial_curves->len, p.num_frames, p.num_factors, p.num_frames*p.num_factors); goto ending; } } p.forward_error = g_try_new(gdouble, p.num_frames*p.num_voxels); if (p.forward_error == NULL) { g_warning(_("failed forward error malloc")); goto ending; } /* calculate the weights and magnitude */ p.weight = calc_weights(p.data_set); if (p.weight == NULL) { g_warning(_("failed weight malloc")); goto ending; } magnitude = calc_magnitude(p.data_set, p.weight); if (p.sum_factors_equal_one) { p.ec_a = g_try_new(gdouble, p.num_voxels); if (p.ec_a == NULL) { g_warning(_("failed equality constraint alpha malloc")); goto ending; } } p.ec_bc = g_try_new(gdouble, p.num_blood_curve_constraints); if ((p.ec_bc == NULL) && (p.num_blood_curve_constraints > 0)) { g_warning(_("failed equality constraint blood curve malloc")); goto ending; } if (p.sum_factors_equal_one) { p.lme_a = g_try_new(gdouble, p.num_voxels); if (p.lme_a == NULL) { g_warning(_("failed malloc for equality lagrange multiplier - alpha")); goto ending; } for (i=0; i 0)) { g_warning(_("failed malloc for equality lagrange multiplier - blood curve")); goto ending; } for (i=0; igradient, stopping_criteria); if (timer != NULL) { /* we only update things if at least 1 second has passed or we're at the start of a new loop */ if ((g_timer_elapsed(timer,NULL) > 1.0) || (new_outer)) { new_outer = FALSE; if (update_func != NULL) continue_work = (*update_func)(update_data, NULL, (gdouble) inner_iter/max_iterations); g_timer_start(timer); /* reset the timer */ #if AMIDE_DEBUG g_print("iter %d-%d\t%10.9g = %5.3g + %5.3g + %5.3g + %5.3g\t%g\t%g \r", outer_iter, inner_iter, 100.0*gsl_multimin_fdfminimizer_minimum(multimin_minimizer)/magnitude, 100.0*p.ls/magnitude, 100.0*p.neg/magnitude, 100.0*p.b*p.orth/magnitude, 100.0*p.blood/magnitude, p.mu, (beta > 0) ? 100*(current_beta/beta) : 0.0); #endif /* AMIDE_DEBUG */ } #if AMIDE_DEBUG x = div(inner_iter,1000); if (x.rem == 0) g_print("\n"); #endif /* AMIDE_DEBUG */ } if (inner_iter >= max_iterations) status = GSL_EMAXITER; if (isnan(gsl_multimin_fdfminimizer_minimum(multimin_minimizer))) status = GSL_ERUNAWAY; else gsl_vector_memcpy(initial, multimin_minimizer->x); } while ((status == GSL_CONTINUE) && continue_work); /* inner loop */ #if AMIDE_DEBUG g_print("\n"); #endif /* AMIDE_DEBUG */ /* adjust lagrangian conditions */ if (((status == GSL_SUCCESS) || (status == GSL_ENOPROG) || (status == GSL_ERUNAWAY)) && continue_work && ((p.mu > FINAL_MU) || (current_beta < beta))) { #if AMIDE_DEBUG if (status == GSL_ENOPROG) g_print("--- previous iteration was not making progress towards a solution ---\n"); else if (status == GSL_ERUNAWAY) g_print("--- previous iteration ran away, reseting to last good value ---\n"); #endif if (status == GSL_ERUNAWAY) { /* need to recompute ec's */ pls_calc_constraints(&p, initial); } /* adjust lagrangian's */ for (i=0; i FINAL_MU) p.mu *= 0.7; status = GSL_CONTINUE; } } while ((status == GSL_CONTINUE) && continue_work); /* outer loop */ #if AMIDE_DEBUG if (status == GSL_SUCCESS) g_print("Minimum found after %d iterations\n", inner_iter); else if (status == GSL_CONTINUE) g_print("terminated minization \n"); else g_print("No minimum found after %d iterations, exited with: %s\n", inner_iter,gsl_strerror(status)); #endif /* AMIDE_DEBUG */ if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); /* add the different coefficients to the tree */ dim.t = 1; i_voxel.t = 0; for (f=0; fsum_factors_equal_one) { for (k=0, i=p->alpha_offset; k < p->num_voxels; k++, i+=p->num_factors) { total = -1.0; for (f=0; fnum_factors; f++) total += gsl_vector_get(v, i+f); p->ec_a[k] = total; } } /* blood curve constraints */ for (i=0; inum_blood_curve_constraints; i++) { bc = gsl_vector_get(v, p->blood_curve_constraint_frame[i]); p->ec_bc[i] = bc-p->blood_curve_constraint_val[i];; } } static void two_comp_calc_compartments(two_comp_params_t * p, const gsl_vector *v) { gint j, k, t; gdouble convolution_value, kernel; gdouble k12, bc; for (t=0; tnum_tissues; t++) { k12 = gsl_vector_get(v, p->k12_offset+t); for (j=0; jnum_frames; j++) { convolution_value=0; for (k=0; k < j; k++) { bc = gsl_vector_get(v, p->bc_offset+k); if (fabs(k12) < EPSILON) kernel = p->end[k]-p->start[k]; else kernel = (exp(-k12*(p->midpt[j]-p->end[k]))-exp(-k12*(p->midpt[j]-p->start[k])))/k12; convolution_value += bc*kernel; } /* k == j */ bc = gsl_vector_get(v, p->bc_offset+j); if (fabs(k12) < EPSILON) kernel = p->midpt[j]-p->start[j]; else kernel = (1-exp(-k12*(p->midpt[j]-p->start[j])))/k12; convolution_value += bc*kernel; p->tc_unscaled[j*p->num_tissues+t] = convolution_value; } } return; } static void two_comp_calc_forward_error(two_comp_params_t * p, const gsl_vector *v) { gint i, k, t; AmitkVoxel i_voxel; gdouble bc; gdouble k21; gdouble inner, alpha; for (i_voxel.t=0; i_voxel.tdim.t; i_voxel.t++) { i=p->alpha_offset; k=0; bc = gsl_vector_get(v, p->bc_offset+i_voxel.t); for (i_voxel.g=0; i_voxel.gdim.g; i_voxel.g++) { for (i_voxel.z=0; i_voxel.zdim.z; i_voxel.z++) { for (i_voxel.y=0; i_voxel.ydim.y; i_voxel.y++) { for (i_voxel.x=0; i_voxel.xdim.x; i_voxel.x++, k++, i+=p->num_factors) { inner=0; for (t=0; t < p->num_tissues; t++) { k21 = gsl_vector_get(v, p->k21_offset+t); alpha = gsl_vector_get(v, i+t); inner += alpha*k21*p->tc_unscaled[i_voxel.t*p->num_tissues+t]; } alpha = gsl_vector_get(v, i+p->num_tissues); p->forward_error[k*p->num_frames+i_voxel.t] = alpha*bc+inner-amitk_data_set_get_value(p->data_set,i_voxel); } } } } } return; } static gdouble two_comp_calc_function(two_comp_params_t * p, const gsl_vector *v) { gdouble ls_answer=0.0; gdouble neg_answer=0.0; gdouble blood_answer=0.0; gdouble temp, bc, k12, k21, alpha, lambda; gint i, k, j, f, t; /* the Least Squares objective */ ls_answer = 0.0; for (i=0; inum_voxels; i++) { for (j=0; jnum_frames; j++) { temp = p->forward_error[i*p->num_frames+j]; ls_answer += p->weight[j]*temp*temp; } } neg_answer = 0.0; /* non negativity for the k12's */ for (t=0; tnum_tissues; t++) { k12 = gsl_vector_get(v, p->k12_offset+t); lambda = p->lmi_k12[t]; if ((k12-p->mu*lambda) < 0.0) neg_answer += k12*(k12/(2.0*p->mu)-lambda); else neg_answer -= lambda*lambda*p->mu/2.0; } /* non negativity for the k21's */ for (t=0; tnum_tissues; t++) { k21 = gsl_vector_get(v, p->k21_offset+t); lambda = p->lmi_k21[t]; if ((k21-p->mu*lambda) < 0.0) neg_answer += k21*(k21/(2.0*p->mu)-lambda); else neg_answer -= lambda*lambda*p->mu/2.0; } /* non-negativity for the blood curve */ for (j=0; jnum_frames; j++) { bc = gsl_vector_get(v, p->bc_offset+j); lambda = p->lmi_bc[j]; if ((bc-p->mu*lambda) < 0.0) neg_answer += bc*(bc/(2.0*p->mu) - lambda); else neg_answer -= lambda*lambda*p->mu/2.0; } /* non-negativity for the alpha's */ for (k=0, i=p->alpha_offset; knum_voxels; k++, i+=p->num_factors) { for (f=0; fnum_factors; f++) { alpha = gsl_vector_get(v, i+f); lambda = p->lmi_a[k*p->num_factors+f]; if ((alpha-p->mu*lambda) < 0.0) neg_answer += alpha*(alpha/(2.0*p->mu) - lambda); else neg_answer -= lambda*lambda*p->mu/2.0; } } /* the sum of alpha's == 1 constraint */ if (p->sum_factors_equal_one) { for (k=0; k< p->num_voxels; k++) neg_answer += p->ec_a[k]*(p->ec_a[k]/(2.0*p->mu) - p->lme_a[k]); } /* blood curve constraints */ blood_answer = 0; for (i=0; inum_blood_curve_constraints; i++) blood_answer += p->ec_bc[i]*(p->ec_bc[i]/(2.0*p->mu) - p->lme_bc[i]); /* keep track of the three */ p->ls = ls_answer; p->neg = neg_answer; p->blood = blood_answer; return ls_answer+neg_answer+blood_answer; } static void two_comp_calc_derivative(two_comp_params_t * p, const gsl_vector *v, gsl_vector *df) { gdouble ls_answer, neg_answer, blood_answer; gint f, i, j, k, t; gdouble k12, k21, bc, inner, kernel, alpha; gdouble delta1, delta2, lambda; /* partial derivative of f wrt to the k12's */ for (t=0; tnum_tissues; t++) { k12 = gsl_vector_get(v, p->k12_offset+t); k21 = gsl_vector_get(v, p->k21_offset+t); ls_answer=0; for (i=0; inum_voxels; i++) { for (j=0; jnum_frames; j++) { inner = 0; for (k=0; kmidpt[j]-p->end[k]; delta2 = p->midpt[j]-p->start[k]; if (fabs(k12) < EPSILON) kernel = 0.5*(delta1*delta1-delta2*delta2); else kernel = (-delta1*exp(-k12*delta1)+delta2*exp(-k12*delta2))/k12; bc = gsl_vector_get(v, p->bc_offset+k); inner += bc*kernel; } /* k == j */ delta2 = p->midpt[j]-p->start[j]; if (fabs(k12) < EPSILON) kernel = -0.5*(delta2*delta2); else kernel = (delta2*exp(-k12*delta2))/k12; bc = gsl_vector_get(v, p->bc_offset+j); inner += bc*kernel; if (fabs(k12) > EPSILON) inner -= p->tc_unscaled[j*p->num_tissues+t]/k12; alpha = gsl_vector_get(v, p->alpha_offset+i*p->num_factors+t); ls_answer += p->weight[j]*p->forward_error[i*p->num_frames+j] * alpha*k21*inner; } } ls_answer *=2; /* the non-negatvity objective */ lambda = p->lmi_k12[t]; if ((k12 - p->mu*lambda) < 0.0) neg_answer = k12/p->mu - lambda; else neg_answer = 0.0; gsl_vector_set(df, p->k12_offset+t, ls_answer+neg_answer); } /* partial derivative of f wrt to the k21's */ for (t=0; tnum_tissues; t++) { k21 = gsl_vector_get(v, p->k21_offset+t); ls_answer=0; for (i=0; inum_voxels; i++) { alpha = gsl_vector_get(v, p->alpha_offset+i*p->num_factors +t); for (j=0; jnum_frames; j++) { ls_answer += p->weight[j]* p->forward_error[i*p->num_frames+j] * alpha* p->tc_unscaled[j*p->num_tissues+t]; } } ls_answer *=2; /* the non-negatvity objective */ lambda = p->lmi_k21[t]; if ((k21 - p->mu*lambda) < 0.0) neg_answer = k21/p->mu - lambda; else neg_answer = 0.0; gsl_vector_set(df, p->k21_offset+t, ls_answer+neg_answer); } /* partial derivative of f wrt to the blood curve */ for (j=0; jnum_frames; j++) { bc = gsl_vector_get(v, p->bc_offset+j); ls_answer=0; for (i=0; inum_voxels; i++) { /* k == j */ inner = gsl_vector_get(v, p->alpha_offset+i*p->num_factors+p->num_tissues); for (t=0; t< p->num_tissues; t++) { alpha = gsl_vector_get(v, p->alpha_offset+i*p->num_factors+t); k12 = gsl_vector_get(v, p->k12_offset+t); k21 = gsl_vector_get(v, p->k21_offset+t); if (fabs(k12) < EPSILON) { kernel = p->midpt[j]-p->start[j]; } else { kernel = (1-exp(-k12*(p->midpt[j]-p->start[j])))/k12; } inner += alpha*k21*kernel; } ls_answer += p->weight[j]*p->forward_error[i*p->num_frames+j]*inner; /* k > j */ for (k=j+1; knum_frames; k++) { inner = 0; for (t=0; t< p->num_tissues; t++) { alpha = gsl_vector_get(v, p->alpha_offset+i*p->num_factors+t); k12 = gsl_vector_get(v, p->k12_offset+t); k21 = gsl_vector_get(v, p->k21_offset+t); if (fabs(k12) < EPSILON) { kernel = p->end[j]-p->start[j]; } else { kernel = (exp(-k12*(p->midpt[k]-p->end[j]))-exp(-k12*(p->midpt[k]-p->start[j])))/k12; } inner += alpha*k21*kernel; } ls_answer += p->weight[k]*p->forward_error[i*p->num_frames+k]*inner; } } ls_answer *= 2; /* the non-negatvity objective */ lambda = p->lmi_bc[j]; if ((bc - p->mu*lambda) < 0.0) neg_answer = bc/p->mu - lambda; else neg_answer = 0.0; /* blood curve constraints */ blood_answer = 0; for (i=0; inum_blood_curve_constraints; i++) if (p->blood_curve_constraint_frame[i] == j) blood_answer += p->ec_bc[i]/p->mu - p->lme_bc[i]; gsl_vector_set(df, p->bc_offset+j, ls_answer+neg_answer+blood_answer); } /* partial derivative of f wrt to the alpha's */ for (i=0; inum_voxels; i++) { for (f=0; f< p->num_factors; f++) { alpha = gsl_vector_get(v, p->alpha_offset+i*p->num_factors+f); ls_answer = 0; for (j=0; j< p->num_frames; j++) { if (f < p->num_tissues) { k21 = gsl_vector_get(v, p->k21_offset+f); inner = k21*p->tc_unscaled[j*p->num_tissues+f]; } else { bc = gsl_vector_get(v, p->bc_offset+j); inner = bc; } ls_answer += p->weight[j]*p->forward_error[i*p->num_frames+j]*inner; } ls_answer *=2; /* the non-negatvity and <= 1 objective */ lambda = p->lmi_a[i*p->num_factors+f]; if ((alpha - p->mu*lambda) < 0.0) neg_answer = alpha/p->mu - lambda; else neg_answer = 0.0; /* the sum of alpha's == 1 constraint */ if (p->sum_factors_equal_one) { neg_answer += p->ec_a[i]/p->mu - p->lme_a[i]; } gsl_vector_set(df, p->alpha_offset+i*p->num_factors+f, ls_answer + neg_answer); } } return; } /* calculate the two compartment objective function */ static double two_comp_f (const gsl_vector *v, void *params) { two_comp_params_t * p = params; two_comp_calc_constraints(p, v); two_comp_calc_compartments(p,v); two_comp_calc_forward_error(p, v); return two_comp_calc_function(p, v); } /* The gradient of f, df = (df/dQt, df/dKij, df/dTi). */ static void two_comp_df (const gsl_vector *v, void *params, gsl_vector *df) { two_comp_params_t * p = params; two_comp_calc_constraints(p, v); two_comp_calc_compartments(p,v); two_comp_calc_forward_error(p, v); two_comp_calc_derivative(p, v, df); return; } /* Compute both f and df together. */ static void two_comp_fdf (const gsl_vector *v, void *params, double *f, gsl_vector *df) { two_comp_params_t * p = params; two_comp_calc_constraints(p, v); two_comp_calc_compartments(p,v); two_comp_calc_forward_error(p, v); *f = two_comp_calc_function(p,v); two_comp_calc_derivative(p, v, df); return; } /* run a two compartment algorithm for factor analysis gsl supports minimizing on only a single vector space, so that vector is setup as follows M = num_voxels; N = num_frames F = num_factors (the last factor is the blood curve) bc = blood curve alpha = coefficent's x = [k12(1) k12(2) ...... k12(F-1) k21(1) k21(2) ...... k21(F-1) bc(1) bc(2) ...... bc(N) alpha(1,1) alpha(1,2) ...... alpha(1, F) alpha(2,1) alpha(2,2) ...... alpha(2, F) ...... alpha(M,1) alpha(M,2) ...... alpha(M, F) ] forward_error is [M*N] tc_unscaled is [N*F] */ void fads_two_comp(AmitkDataSet * data_set, fads_minimizer_algorithm_t minimizer_algorithm, gint max_iterations, gint tissue_types, gdouble supplied_k12, gdouble supplied_k21, gdouble stopping_criteria, gboolean sum_factors_equal_one, gchar * output_filename, gint num_blood_curve_constraints, gint * blood_curve_constraint_frame, gdouble * blood_curve_constraint_val, AmitkUpdateFunc update_func, gpointer update_data) { gsl_multimin_fdfminimizer * multimin_minimizer = NULL; gsl_multimin_function_fdf multimin_func; AmitkVoxel dim; two_comp_params_t p; gint outer_iter=0; gint inner_iter=0; gsl_vector * initial=NULL; gint i, f, j, t; gint status; FILE * file_pointer=NULL; gchar * temp_string; gboolean continue_work=TRUE; gdouble temp, bc; amide_time_t frame_midpoint, frame_duration; amide_time_t time_constant; amide_time_t time_start; AmitkDataSet * new_ds; AmitkVoxel i_voxel; gdouble magnitude, k12, k21; gdouble init_value, alpha; AmitkViewMode i_view_mode; GTimer * timer=NULL; gboolean new_outer; #if AMIDE_DEBUG div_t x; #endif g_return_if_fail(AMITK_IS_DATA_SET(data_set)); dim = AMITK_DATA_SET_DIM(data_set); g_return_if_fail(tissue_types >= 1); /* initialize our parameter structure */ p.data_set = data_set; p.dim = dim; p.mu = 1000.0; p.ls = 0.0; p.neg = 0.0; p.blood = 0.0; p.num_voxels = dim.g*dim.z*dim.y*dim.x; p.num_frames = dim.t; p.num_factors = tissue_types+1; p.num_tissues = tissue_types; p.k12_offset = 0; p.k21_offset = p.k12_offset + p.num_tissues; p.bc_offset = p.k21_offset + p.num_tissues; p.alpha_offset = p.bc_offset+p.num_frames; p.num_variables = p.alpha_offset + p.num_factors*p.num_voxels; p.tc_unscaled = NULL; p.forward_error = NULL; p.start = NULL; p.end = NULL; p.ec_a = NULL; p.ec_bc = NULL; p.lme_a = NULL; p.lme_bc = NULL; p.lmi_a = NULL; p.lmi_bc = NULL; p.lmi_k12 = NULL; p.lmi_k12 = NULL; p.sum_factors_equal_one = sum_factors_equal_one; p.num_blood_curve_constraints = num_blood_curve_constraints; p.blood_curve_constraint_frame = blood_curve_constraint_frame; p.blood_curve_constraint_val = blood_curve_constraint_val; /* more sanity checks */ for (i=0; i 0)) { g_warning(_("failed malloc for equality constraint on blood curve")); goto ending; } if (p.sum_factors_equal_one) { p.lme_a = g_try_new(gdouble, p.num_voxels); if (p.lme_a == NULL) { g_warning(_("failed malloc for equality lagrange multiplier - alpha")); goto ending; } for (i=0; i 0)) { g_warning(_("failed malloc for equality lagrange multiplier - blood curve")); goto ending; } for (i=0; igradient, stopping_criteria); if (timer != NULL) { /* we only update things if at least 1 second has passed or we're at the start of a new loop */ if ((g_timer_elapsed(timer,NULL) > 1.0) || (new_outer)) { new_outer = FALSE; if (update_func != NULL) continue_work = (*update_func)(update_data, NULL, (gdouble) inner_iter/max_iterations); g_timer_start(timer); /* reset the timer */ #if AMIDE_DEBUG g_print("iter %d %d %10.9g=%5.3g+%5.3g+%5.3g mu=%g k12=%g k21=%g \r", outer_iter, inner_iter, 100.0*gsl_multimin_fdfminimizer_minimum(multimin_minimizer)/magnitude, 100.0*p.ls/magnitude, 100.0*p.neg/magnitude, 100.0*p.blood/magnitude, p.mu, gsl_vector_get(multimin_minimizer->x, p.k12_offset), gsl_vector_get(multimin_minimizer->x, p.k21_offset)); // g_print("bc %g %g tc %g %g alpha %g %g\n", // gsl_vector_get(multimin_minimizer->x, p.bc_offset), // gsl_vector_get(multimin_minimizer->x, p.bc_offset+1), // p.tc_unscaled[0], p.tc_unscaled[1], // gsl_vector_get(multimin_minimizer->x, p.alpha_offset), // gsl_vector_get(multimin_minimizer->x, p.alpha_offset+1)); #endif /* AMIDE_DEBUG */ } #if AMIDE_DEBUG x = div(inner_iter,1000); if (x.rem == 0) g_print("\n"); #endif /* AMIDE_DEBUG */ } if (inner_iter >= max_iterations) status = GSL_EMAXITER; if (isnan(gsl_multimin_fdfminimizer_minimum(multimin_minimizer))) status = GSL_ERUNAWAY; else gsl_vector_memcpy(initial, multimin_minimizer->x); } while ((status == GSL_CONTINUE) && continue_work); /* inner loop */ #if AMIDE_DEBUG g_print("\n"); #endif /* adjust lagrangian conditions */ if (((status == GSL_SUCCESS) || (status == GSL_ENOPROG) || (status == GSL_ERUNAWAY)) && continue_work && (p.mu > FINAL_MU)) { #if AMIDE_DEBUG if (status == GSL_ENOPROG) g_print("--- previous iteration was not making progress towards a solution ---\n"); else if (status == GSL_ERUNAWAY) g_print("--- previous iteration ran away, reseting to last good value ---\n"); #endif if (status == GSL_ERUNAWAY) { /* need to recompute ec's */ two_comp_calc_constraints(&p, initial); } /* adjust lagrangian's */ for (i=0; i FINAL_MU) { p.mu *= 0.7; } status = GSL_CONTINUE; } } while ((status == GSL_CONTINUE) && continue_work); /* outer loop */ #if AMIDE_DEBUG if (status == GSL_SUCCESS) g_print(_("Minimum found after %d iterations\n"), inner_iter); else if (status == GSL_CONTINUE) g_print(_("terminated minization \n")); else g_print(_("No minimum found after %d iterations, exited with: %s\n"), inner_iter,gsl_strerror(status)); #endif /* AMIDE_DEBUG */ if (update_func != NULL) /* remove progress bar */ continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); /* add the different coefficients to the tree */ dim.t = 1; i_voxel.t = 0; for (f=0; f < p.num_factors; f++) { new_ds = amitk_data_set_new_with_data(NULL, AMITK_DATA_SET_MODALITY(data_set), AMITK_FORMAT_FLOAT, dim, AMITK_SCALING_TYPE_0D); if (new_ds == NULL) { g_warning(_("failed to allocate new_ds")); goto ending; } for (i_view_mode = 0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) amitk_data_set_set_color_table(new_ds, i_view_mode, AMITK_DATA_SET_COLOR_TABLE(data_set, i_view_mode)); i=p.alpha_offset; /* what to skip in v to get to the coefficients */ for (i_voxel.g=0; i_voxel.g */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBGSL_SUPPORT #ifndef __FADS_H__ #define __FADS_H__ /* header files that are always needed with this file */ #include "amitk_data_set.h" typedef enum { FADS_TYPE_PCA, FADS_TYPE_PLS, FADS_TYPE_TWO_COMPARTMENT, NUM_FADS_TYPES } fads_type_t; typedef enum { /* FADS_MINIMIZER_STEEPEST_DESCENT, */ FADS_MINIMIZER_CONJUGATE_FR, FADS_MINIMIZER_CONJUGATE_PR, /* FADS_MINIMIZER_VECTOR_BFGS, */ NUM_FADS_MINIMIZERS } fads_minimizer_algorithm_t; extern gchar * fads_minimizer_algorithm_name[]; extern gchar * fads_type_name[]; extern gchar * fads_type_explanation[]; extern const guint8 * fads_type_icon[]; void fads_svd_factors(AmitkDataSet * data_set, gint * pnum_factors, gdouble ** pfactors); void fads_pca(AmitkDataSet * data_set, gint num_factors, gchar * output_filename, AmitkUpdateFunc update_func, gpointer update_data); void fads_pls(AmitkDataSet * data_set, gint num_factors, fads_minimizer_algorithm_t minimizer_algorithm, gint max_iterations, gdouble stopping_criteria, gboolean sum_factors_equal_one, gdouble beta, gchar * output_filename, gint num_blood_curve_constraints, gint * blood_curve_constraint_frame, gdouble * blood_curve_constraint_val, GArray * initial_curves, AmitkUpdateFunc update_func, gpointer update_data); void fads_two_comp(AmitkDataSet * data_set, fads_minimizer_algorithm_t minimizer_algorithm, gint max_iterations, gint tissue_types, gdouble k12, gdouble k21, gdouble stopping_criteria, gboolean sum_factors_equal_one, gchar * output_filename, gint num_blood_curve_constraints, gint * blood_curve_constraint_frame, gdouble * blood_curve_constraint_val, AmitkUpdateFunc update_func, gpointer update_data); #endif /* __FADS_H__ */ #endif /* AMIDE_LIBGSL_SUPPORT */ amide-1.0.6/amide-current/src/image.c000066400000000000000000001066351423227705100173670ustar00rootroot00000000000000/* image.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "image.h" #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include "amitk_study.h" #define OBJECT_ICON_XSIZE 24 #define OBJECT_ICON_YSIZE 24 guchar CT_icon_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 17, 43, 35, 35, 43, 43, 43, 26, 35, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 79, 105, 105, 131, 149, 158, 149, 149, 105, 149, 79, 52, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 96, 149, 175, 123, 105, 114, 246, 140, 105, 123, 123, 149, 131, 79, 0, 0, 0, 0, 0, 0, 0, 0, 52, 96, 175, 123, 70, 61, 70, 87, 96, 96, 105, 105, 96, 87, 114, 131, 61, 0, 0, 0, 0, 0, 0, 17, 105, 114, 114, 43, 70, 87, 87, 96, 105, 96, 96, 96, 96, 96, 79, 149, 114, 8, 0, 0, 17, 26, 0, 61, 105, 96, 26, 52, 79, 87, 96, 96, 96, 96, 96, 96, 96, 96, 96, 158, 105, 52, 0, 0, 70, 61, 79, 96, 105, 43, 26, 70, 87, 87, 87, 87, 96, 96, 96, 96, 96, 96, 105, 123, 96, 87, 35, 0, 43, 79, 96, 123, 158, 17, 43, 79, 87, 87, 87, 87, 87, 96, 96, 96, 96, 96, 87, 79, 140, 105, 79, 0, 17, 87, 96, 123, 131, 8, 52, 70, 87, 87, 87, 87, 79, 79, 79, 87, 87, 79, 52, 8, 123, 158, 114, 8, 35, 96, 96, 114, 52, 26, 61, 70, 87, 87, 87, 79, 70, 70, 70, 61, 61, 52, 17, 0, 114, 131, 96, 26, 8, 70, 96, 184, 26, 26, 61, 70, 70, 87, 96, 79, 61, 61, 61, 52, 52, 43, 35, 17, 79, 114, 87, 43, 0, 52, 96, 184, 17, 26, 52, 61, 70, 79, 96, 79, 52, 52, 43, 43, 43, 43, 35, 17, 61, 211, 140, 35, 0, 61, 96, 96, 17, 8, 26, 43, 52, 70, 87, 52, 26, 26, 17, 26, 26, 8, 8, 0, 87, 158, 96, 0, 0, 17, 96, 114, 35, 8, 17, 26, 8, 17, 35, 8, 26, 17, 8, 8, 0, 0, 8, 35, 114, 87, 52, 0, 0, 8, 96, 175, 123, 0, 0, 8, 8, 0, 52, 8, 8, 17, 8, 35, 8, 26, 8, 26, 193, 105, 17, 0, 0, 0, 70, 114, 140, 26, 17, 8, 8, 26, 26, 8, 17, 17, 17, 17, 26, 17, 0, 87, 202, 114, 0, 0, 0, 0, 43, 96, 105, 43, 8, 17, 17, 26, 17, 0, 52, 43, 0, 8, 26, 8, 43, 140, 79, 26, 0, 0, 0, 0, 8, 70, 96, 96, 52, 17, 8, 8, 8, 35, 184, 79, 8, 17, 52, 61, 79, 96, 79, 0, 0, 0, 0, 0, 0, 8, 79, 96, 175, 158, 35, 17, 61, 219, 255, 228, 87, 96, 202, 228, 131, 96, 17, 0, 0, 0, 0, 0, 0, 0, 43, 105, 149, 184, 149, 123, 131, 211, 131, 237, 149, 114, 96, 123, 114, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 79, 96, 105, 105, 114, 228, 228, 228, 131, 105, 105, 105, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 61, 79, 96, 114, 140, 167, 123, 123, 105, 87, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 79, 96, 105, 105, 105, 87, 70, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 70, 35, 17, 17, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; guchar PET_icon_data[] = { 3, 8, 25, 35, 21, 22, 50, 96, 148, 171, 134, 109, 145, 177, 156, 134, 86, 54, 42, 40, 42, 25, 11, 3, 8, 27, 29, 25, 24, 53, 120, 162, 187, 216, 224, 184, 211, 224, 198, 185, 147, 108, 61, 33, 34, 32, 26, 10, 28, 34, 18, 25, 88, 129, 160, 154, 166, 214, 234, 203, 210, 211, 185, 176, 169, 156, 133, 83, 37, 21, 28, 26, 37, 24, 21, 75, 158, 161, 154, 142, 180, 234, 255, 224, 221, 220, 212, 186, 162, 160, 169, 165, 101, 32, 18, 37, 28, 25, 70, 139, 163, 141, 122, 147, 197, 226, 242, 196, 195, 218, 206, 200, 148, 116, 155, 188, 153, 72, 24, 41, 29, 45, 107, 165, 171, 136, 116, 160, 198, 203, 216, 165, 158, 201, 189, 193, 155, 125, 153, 168, 171, 125, 53, 36, 45, 104, 147, 172, 173, 141, 100, 122, 157, 179, 190, 153, 147, 181, 166, 134, 102, 97, 122, 163, 187, 179, 124, 43, 76, 163, 184, 178, 158, 116, 73, 76, 89, 121, 154, 137, 138, 144, 102, 83, 70, 80, 114, 170, 195, 200, 162, 64, 80, 158, 168, 165, 148, 104, 74, 81, 76, 81, 93, 96, 94, 85, 66, 65, 62, 69, 96, 145, 179, 193, 174, 91, 85, 158, 173, 169, 132, 104, 93, 93, 96, 101, 82, 67, 58, 70, 75, 83, 77, 83, 113, 153, 174, 190, 180, 101, 74, 158, 166, 176, 172, 170, 144, 120, 128, 150, 138, 89, 82, 122, 157, 139, 107, 140, 165, 182, 187, 184, 171, 102, 61, 152, 178, 181, 186, 185, 163, 132, 137, 200, 195, 147, 128, 176, 217, 161, 115, 148, 168, 195, 193, 178, 162, 89, 30, 117, 164, 168, 170, 157, 155, 137, 117, 184, 187, 145, 138, 174, 164, 125, 120, 147, 160, 169, 188, 176, 129, 52, 26, 99, 160, 174, 177, 162, 150, 130, 118, 118, 102, 89, 81, 96, 120, 108, 126, 162, 173, 155, 165, 171, 125, 43, 42, 84, 156, 177, 162, 164, 157, 130, 97, 102, 73, 53, 56, 68, 102, 114, 114, 148, 168, 173, 174, 166, 108, 37, 41, 69, 133, 179, 186, 165, 147, 122, 99, 96, 60, 50, 50, 48, 88, 110, 130, 158, 158, 176, 185, 145, 85, 42, 36, 41, 99, 171, 187, 174, 157, 122, 91, 62, 51, 66, 69, 53, 66, 93, 146, 165, 177, 185, 196, 108, 42, 38, 43, 35, 72, 157, 180, 160, 126, 106, 82, 75, 83, 94, 100, 83, 65, 89, 134, 153, 154, 179, 184, 92, 30, 28, 33, 24, 38, 108, 176, 179, 139, 98, 85, 114, 144, 146, 147, 130, 93, 82, 110, 126, 150, 195, 152, 46, 21, 22, 22, 33, 34, 53, 163, 187, 153, 129, 107, 140, 172, 169, 168, 161, 117, 92, 132, 173, 184, 165, 92, 34, 30, 13, 16, 29, 30, 19, 104, 177, 197, 180, 156, 158, 177, 168, 169, 169, 141, 136, 181, 210, 172, 81, 36, 33, 29, 6, 5, 6, 13, 17, 41, 81, 152, 179, 193, 170, 178, 165, 162, 165, 164, 181, 187, 163, 86, 13, 19, 26, 12, 3, 3, 3, 6, 29, 41, 33, 49, 89, 133, 154, 155, 118, 140, 164, 166, 138, 86, 44, 24, 26, 26, 9, 5, 3, 3, 8, 18, 21, 24, 37, 34, 26, 40, 60, 62, 36, 51, 73, 61, 50, 25, 22, 29, 22, 12, 5, 6, 6 }; guchar MRI_icon_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 6, 10, 16, 14, 15, 13, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 22, 19, 32, 58, 24, 22, 50, 16, 19, 12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 24, 42, 153, 222, 133, 111, 108, 160, 162, 99, 22, 22, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 24, 80, 150, 147, 169, 122, 164, 141, 116, 113, 170, 156, 40, 21, 1, 0, 0, 0, 0, 0, 0, 0, 0, 19, 47, 169, 134, 132, 148, 157, 139, 120, 116, 120, 146, 116, 174, 15, 21, 0, 0, 0, 0, 0, 0, 0, 5, 21, 175, 230, 165, 138, 199, 204, 202, 179, 152, 135, 116, 141, 155, 87, 20, 4, 0, 0, 0, 0, 0, 0, 14, 70, 146, 213, 152, 149, 178, 206, 148, 159, 152, 155, 150, 120, 141, 185, 35, 12, 0, 0, 0, 0, 0, 0, 24, 112, 135, 134, 132, 223, 185, 150, 120, 148, 137, 232, 193, 121, 139, 105, 102, 11, 0, 0, 0, 0, 0, 0, 23, 142, 147, 133, 134, 184, 240, 141, 121, 116, 181, 241, 148, 110, 96, 116, 104, 13, 0, 0, 0, 0, 0, 7, 28, 158, 152, 144, 142, 115, 129, 168, 202, 196, 157, 124, 93, 117, 92, 101, 105, 12, 0, 0, 0, 0, 0, 7, 14, 147, 122, 129, 205, 116, 131, 143, 222, 201, 122, 111, 134, 152, 90, 116, 108, 14, 0, 0, 0, 0, 0, 3, 12, 111, 111, 192, 195, 122, 96, 120, 217, 181, 102, 94, 131, 197, 96, 85, 79, 20, 0, 0, 0, 0, 0, 0, 16, 70, 114, 186, 203, 164, 134, 101, 225, 185, 78, 132, 150, 207, 156, 123, 37, 20, 0, 0, 0, 0, 0, 0, 17, 23, 138, 181, 207, 148, 165, 183, 228, 210, 164, 164, 155, 223, 125, 111, 15, 21, 0, 0, 0, 0, 0, 0, 15, 15, 122, 206, 197, 192, 174, 210, 208, 206, 187, 164, 213, 252, 148, 94, 28, 16, 0, 0, 0, 0, 0, 0, 17, 48, 40, 132, 106, 162, 172, 201, 196, 186, 190, 175, 156, 183, 144, 53, 37, 3, 0, 0, 0, 0, 0, 0, 7, 48, 37, 73, 24, 71, 122, 167, 186, 190, 165, 128, 70, 29, 76, 37, 52, 0, 0, 0, 0, 0, 0, 0, 0, 44, 31, 59, 48, 71, 68, 25, 165, 123, 42, 62, 53, 35, 40, 52, 38, 0, 0, 0, 0, 0, 0, 0, 0, 12, 41, 53, 144, 149, 99, 35, 110, 51, 75, 107, 176, 84, 28, 59, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 83, 253, 255, 123, 108, 68, 61, 69, 198, 253, 203, 37, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 22, 186, 205, 61, 25, 58, 32, 64, 144, 224, 178, 26, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 14, 30, 13, 25, 21, 29, 17, 49, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 31, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; guchar SPECT_icon_data[] = { 17, 17, 36, 56, 51, 46, 36, 31, 29, 31, 39, 63, 93, 115, 147, 147, 102, 78, 41, 22, 17, 17, 19, 12, 12, 24, 61, 125, 102, 80, 71, 63, 53, 58, 51, 73, 95, 132, 152, 139, 112, 80, 39, 22, 17, 17, 19, 12, 2, 17, 66, 166, 139, 102, 78, 76, 76, 83, 71, 73, 102, 134, 139, 115, 98, 73, 34, 17, 17, 17, 12, 7, 4, 22, 98, 203, 174, 139, 117, 107, 110, 112, 100, 98, 122, 139, 134, 107, 90, 58, 22, 17, 17, 12, 4, 0, 9, 29, 61, 102, 115, 112, 100, 105, 115, 132, 132, 132, 139, 137, 129, 98, 85, 46, 19, 17, 14, 9, 2, 0, 17, 31, 29, 39, 51, 78, 53, 44, 51, 71, 115, 139, 137, 132, 147, 107, 78, 31, 19, 17, 14, 4, 0, 0, 14, 46, 110, 129, 112, 117, 107, 95, 76, 56, 90, 132, 120, 110, 144, 117, 76, 34, 22, 19, 17, 2, 0, 0, 12, 41, 156, 250, 232, 191, 164, 159, 166, 127, 85, 122, 122, 120, 125, 110, 73, 39, 26, 14, 17, 9, 0, 0, 19, 41, 112, 178, 213, 228, 196, 144, 171, 186, 110, 137, 122, 117, 127, 110, 85, 73, 61, 31, 19, 14, 2, 0, 31, 76, 95, 98, 127, 147, 152, 129, 169, 178, 120, 127, 100, 100, 125, 107, 98, 107, 115, 95, 51, 22, 9, 2, 46, 112, 112, 95, 110, 152, 201, 191, 203, 198, 171, 152, 112, 110, 201, 129, 83, 78, 85, 110, 112, 53, 19, 2, 36, 115, 142, 125, 142, 191, 205, 203, 255, 235, 205, 178, 183, 201, 250, 142, 63, 58, 71, 98, 156, 156, 63, 14, 14, 71, 107, 120, 164, 149, 122, 100, 159, 210, 147, 98, 90, 76, 83, 76, 61, 63, 61, 90, 147, 178, 120, 34, 24, 63, 115, 154, 156, 125, 110, 105, 169, 188, 98, 46, 51, 44, 44, 39, 44, 49, 58, 80, 120, 139, 154, 71, 58, 112, 147, 166, 159, 110, 107, 110, 152, 154, 88, 46, 46, 46, 39, 31, 34, 29, 41, 49, 71, 98, 152, 98, 78, 149, 142, 139, 134, 90, 98, 95, 63, 44, 41, 53, 61, 53, 44, 41, 41, 41, 44, 46, 53, 80, 149, 112, 66, 149, 110, 95, 83, 76, 71, 61, 39, 34, 36, 39, 49, 44, 44, 49, 41, 44, 49, 46, 61, 93, 152, 102, 31, 120, 105, 85, 80, 76, 61, 58, 51, 41, 34, 36, 39, 36, 36, 36, 36, 41, 49, 61, 80, 110, 156, 78, 7, 83, 110, 110, 76, 66, 53, 53, 56, 51, 49, 51, 51, 36, 36, 36, 36, 39, 53, 68, 88, 137, 134, 46, 4, 39, 102, 137, 100, 71, 63, 53, 58, 66, 71, 63, 61, 53, 46, 36, 44, 51, 56, 78, 110, 149, 80, 14, 2, 7, 49, 120, 144, 107, 78, 78, 73, 76, 76, 85, 85, 66, 63, 63, 66, 73, 80, 107, 147, 112, 34, 4, 0, 0, 7, 51, 115, 159, 125, 107, 100, 95, 98, 105, 100, 88, 93, 93, 90, 110, 139, 149, 102, 36, 7, 0, 0, 0, 0, 7, 36, 102, 144, 166, 154, 139, 142, 132, 120, 122, 127, 137, 149, 154, 125, 76, 29, 7, 2, 0, 0, 0, 0, 0, 0, 12, 49, 98, 127, 159, 174, 166, 166, 171, 159, 147, 117, 68, 29, 9, 2, 0, 2, 0 }; /* callback function used for freeing the pixel data in a gdkpixbuf */ static void image_free_rgb_data(guchar * pixels, gpointer data) { g_free(pixels); return; } /* note, return offset and corner are in base coordinate frame */ GdkPixbuf * image_slice_intersection(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_size, #ifdef AMIDE_LIBGNOMECANVAS_AA const gdouble transparency, #else const gboolean fill_roi, #endif rgba_t color, AmitkPoint * return_offset, AmitkPoint * return_corner) { GdkPixbuf * temp_image; AmitkDataSet * intersection; AmitkVoxel i; guchar * rgba_data; AmitkVoxel dim; #ifdef AMIDE_LIBGNOMECANVAS_AA guchar transparency_byte; transparency_byte = transparency * 0xFF; #endif intersection = amitk_roi_get_intersection_slice(roi, canvas_slice, pixel_size #ifndef AMIDE_LIBGNOMECANVAS_AA , fill_roi #endif ); if (intersection == NULL) return NULL; dim = AMITK_DATA_SET_DIM(intersection); if ((dim.x == 0) && (dim.y ==0)) { amitk_object_unref(intersection); return NULL; } if ((rgba_data = g_try_new(guchar,4*dim.x*dim.y)) == NULL) { g_warning(_("couldn't allocate memory for rgba_data for roi image")); amitk_object_unref(intersection); return NULL; } i.z = i.g = i.t = 0; for (i.y=0 ; i.y < dim.y; i.y++) for (i.x=0 ; i.x < dim.x; i.x++) if (AMITK_RAW_DATA_UBYTE_CONTENT(intersection->raw_data, i) == 1) { rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+0] = color.r; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+1] = color.g; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+2] = color.b; #ifdef AMIDE_LIBGNOMECANVAS_AA rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+3] = color.a; #else rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+3] = 0xFF; #endif #ifdef AMIDE_LIBGNOMECANVAS_AA } else if (AMITK_RAW_DATA_UBYTE_CONTENT(intersection->raw_data, i) == 2) { rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+0] = color.r; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+1] = color.g; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+2] = color.b; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+3] = transparency_byte; #endif } else { rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+0] = 0x00; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+1] = 0x00; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+2] = 0x00; rgba_data[(dim.y-i.y-1)*dim.x*4 + i.x*4+3] = 0x00; } temp_image = gdk_pixbuf_new_from_data(rgba_data, GDK_COLORSPACE_RGB, TRUE,8, dim.x,dim.y,dim.x*4*sizeof(guchar), image_free_rgb_data, NULL); if (return_offset != NULL) *return_offset = AMITK_SPACE_OFFSET(intersection); if (return_corner != NULL) *return_corner = amitk_space_s2b(AMITK_SPACE(intersection), AMITK_VOLUME_CORNER(intersection)); amitk_object_unref(intersection); return temp_image; } /* function to return a blank image */ GdkPixbuf * image_blank(const amide_intpoint_t width, const amide_intpoint_t height, rgba_t image_color) { GdkPixbuf * temp_image; amide_intpoint_t i,j; guchar * rgb_data; if ((rgb_data = g_try_new(guchar, 3*width*height)) == NULL) { g_warning(_("couldn't allocate memory for rgb_data for blank image")); return NULL; } for (i=0 ; i < height; i++) for (j=0; j < width; j++) { rgb_data[i*width*3+j*3+0] = image_color.r; rgb_data[i*width*3+j*3+1] = image_color.g; rgb_data[i*width*3+j*3+2] = image_color.b; } temp_image = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE,8,width,height,width*3*sizeof(guchar), image_free_rgb_data, NULL); return temp_image; } /* function returns a GdkPixbuf from 8 bit data */ GdkPixbuf * image_from_8bit(const guchar * image, const amide_intpoint_t width, const amide_intpoint_t height, const AmitkColorTable color_table) { GdkPixbuf * temp_image; amide_intpoint_t i,j; guchar * rgb_data; rgba_t rgba_temp; guint location; if ((rgb_data = g_try_new(guchar,3*width*height)) == NULL) { g_warning(_("couldn't allocate memory for image from 8 bit data")); return NULL; } for (i=0 ; i < height; i++) for (j=0; j < width; j++) { /* note, line below compensates for X's origin being top left, not bottom left */ rgba_temp = amitk_color_table_lookup(image[(height-i-1)*width+j], color_table, 0, 0xFF); location = i*width*3+j*3; rgb_data[location+0] = rgba_temp.r; rgb_data[location+1] = rgba_temp.g; rgb_data[location+2] = rgba_temp.b; } /* generate the GdkPixbuf from the rgb_data */ temp_image = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE,8,width,height,width*3*sizeof(guchar), image_free_rgb_data, NULL); return temp_image; } #ifdef AMIDE_LIBVOLPACK_SUPPORT /* function returns a GdkPixbuf from a rendering context */ GdkPixbuf * image_from_renderings(renderings_t * renderings, gint16 image_width, gint16 image_height, AmideEye eyes, gdouble eye_angle, gint16 eye_width) { gint image_num; guint32 total_alpha; rgba16_t * rgba16_data; guchar * char_data; AmitkVoxel i; rgba_t rgba_temp; guint location; GdkPixbuf * temp_image; gint total_width; gdouble rot; AmideEye i_eye; gint j; total_width = image_width+(eyes-1)*eye_width; /* allocate and initialize space for a temporary storage buffer */ if ((rgba16_data = g_try_new(rgba16_t,total_width * image_height)) == NULL) { g_warning(_("couldn't allocate memory for rgba16_data for transferring rendering to image")); return NULL; } for (j=0; jrendering); } else { rot = (-0.5 + i_eye*1.0) * eye_angle; rot = M_PI*rot/180; /* convert to radians */ rendering_set_rotation(renderings->rendering, AMITK_AXIS_Y, -rot); rendering_render(renderings->rendering); rendering_set_rotation(renderings->rendering, AMITK_AXIS_Y, rot); } i.t = i.g = i.z = 0; for (i.y = 0; i.y < image_height; i.y++) for (i.x = 0; i.x < image_width; i.x++) { rgba_temp = amitk_color_table_lookup(renderings->rendering->image[i.x+i.y*image_width], renderings->rendering->color_table, 0, RENDERING_DENSITY_MAX); /* compensate for the fact that X defines the origin as top left, not bottom left */ location = (image_height-i.y-1)*total_width+i.x+i_eye*eye_width; total_alpha = rgba16_data[location].a + rgba_temp.a; if (i_eye == 0) image_num = 1; else if ((i.x+i_eye*eye_width) >= image_width) image_num = 1; else image_num = 2; if (total_alpha == 0) { rgba16_data[location].r = (((image_num-1)*rgba16_data[location].r + rgba_temp.r)/ ((gdouble) image_num)); rgba16_data[location].g = (((image_num-1)*rgba16_data[location].g + rgba_temp.g)/ ((gdouble) image_num)); rgba16_data[location].b = (((image_num-1)*rgba16_data[location].b + rgba_temp.b)/ ((gdouble) image_num)); } else if (rgba16_data[location].a == 0) { rgba16_data[location].r = rgba_temp.r; rgba16_data[location].g = rgba_temp.g; rgba16_data[location].b = rgba_temp.b; rgba16_data[location].a = rgba_temp.a; } else if (rgba_temp.a != 0) { rgba16_data[location].r = ((rgba16_data[location].r*rgba16_data[location].a + rgba_temp.r*rgba_temp.a)/ ((gdouble) total_alpha)); rgba16_data[location].g = ((rgba16_data[location].g*rgba16_data[location].a + rgba_temp.g*rgba_temp.a)/ ((gdouble) total_alpha)); rgba16_data[location].b = ((rgba16_data[location].b*rgba16_data[location].a + rgba_temp.b*rgba_temp.a)/ ((gdouble) total_alpha)); rgba16_data[location].a = total_alpha; } } } renderings = renderings->next; } /* allocate space for the true rgb buffer */ if ((char_data = g_try_new(guchar,3*image_height * total_width)) == NULL) { g_warning(_("couldn't allocate memory for char_data for rendering image")); g_free(rgba16_data); return NULL; } /* now convert our temp rgb data to real rgb data */ for (j=0; j max) max = *AMITK_RAW_DATA_DOUBLE_POINTER(distribution,j); if (max/IMAGE_DISTRIBUTION_WIDTH != 0.0) scale = ((gdouble) IMAGE_DISTRIBUTION_WIDTH)/max; else scale = 0; /* figure out what the rgb data is */ j.t = j.g = j.z = j.y = 0; for (l=0 ; l < dim_x ; l++) { j.x = dim_x-l-1; for (k=0; k < floor(((gdouble) IMAGE_DISTRIBUTION_WIDTH)- scale*(*AMITK_RAW_DATA_DOUBLE_POINTER(distribution,j))) ; k++) { rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+0] = 0x00; rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+1] = 0x00; rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+2] = 0x00; rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+3] = 0x00; } for ( ; k < IMAGE_DISTRIBUTION_WIDTH ; k++) { rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+0] = fg.r; rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+1] = fg.g; rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+2] = fg.b; rgba_data[l*IMAGE_DISTRIBUTION_WIDTH*4+k*4+3] = 0xFF; } } } /* generate the pixbuf image */ temp_image = gdk_pixbuf_new_from_data(rgba_data, GDK_COLORSPACE_RGB, TRUE,8,IMAGE_DISTRIBUTION_WIDTH, dim_x, IMAGE_DISTRIBUTION_WIDTH*4*sizeof(guchar), image_free_rgb_data, NULL); if (temp_image == NULL) g_error("NULL Distribution Image created\n"); return temp_image; } /* function to make the color_strip image */ GdkPixbuf * image_from_colortable(const AmitkColorTable color_table, const amide_intpoint_t width, const amide_intpoint_t height, const amide_data_t min, const amide_data_t max, const amide_data_t data_set_min, const amide_data_t data_set_max, const gboolean horizontal) { amide_intpoint_t i,j; rgba_t rgba; GdkPixbuf * temp_image; amide_data_t datum; guchar * rgb_data; if ((rgb_data = g_try_new(guchar,3*width*height)) == NULL) { g_warning(_("couldn't allocate memory for rgb_data for color_strip")); return NULL; } if (horizontal) { for (i=0; i < width; i++) { datum = ((((gdouble) width-i)/width) * (data_set_max-data_set_min))+data_set_min; datum = (data_set_max-data_set_min)*(datum-min)/(max-min)+data_set_min; rgba = amitk_color_table_lookup(datum, color_table, data_set_min, data_set_max); for (j=0; j < height; j++) { rgb_data[j*width*3+i*3+0] = rgba.r; rgb_data[j*width*3+i*3+1] = rgba.g; rgb_data[j*width*3+i*3+2] = rgba.b; } } } else { for (j=0; j < height; j++) { datum = ((((gdouble) height-j)/height) * (data_set_max-data_set_min))+data_set_min; datum = (data_set_max-data_set_min)*(datum-min)/(max-min)+data_set_min; rgba = amitk_color_table_lookup(datum, color_table, data_set_min, data_set_max); for (i=0; i < width; i++) { rgb_data[j*width*3+i*3+0] = rgba.r; rgb_data[j*width*3+i*3+1] = rgba.g; rgb_data[j*width*3+i*3+2] = rgba.b; } } } temp_image = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE,8,width,height,width*3*sizeof(guchar), image_free_rgb_data, NULL); return temp_image; } GdkPixbuf * image_from_projection(AmitkDataSet * projection) { guchar * rgb_data; AmitkVoxel i; AmitkVoxel dim; amide_data_t max,min; GdkPixbuf * temp_image; rgba_t rgba_temp; AmitkColorTable color_table; /* sanity checks */ g_return_val_if_fail(AMITK_IS_DATA_SET(projection), NULL); dim = AMITK_DATA_SET_DIM(projection); if ((rgb_data = g_try_new(guchar,3*dim.x*dim.y)) == NULL) { g_warning(_("couldn't allocate memory for rgba_data for projection image")); return NULL; } amitk_data_set_get_thresholding_min_max(projection, projection, AMITK_DATA_SET_SCAN_START(projection), amitk_data_set_get_frame_duration(projection,0), &min, &max); color_table = AMITK_DATA_SET_COLOR_TABLE(projection, AMITK_VIEW_MODE_SINGLE); i.t = i.g = i.z = 0; for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { rgba_temp = amitk_color_table_lookup(AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(projection,i), color_table,min, max); /* compensate for the fact that X defines the origin as top left, not bottom left */ rgb_data[(dim.y-i.y-1)*dim.x*3 + i.x*3+0] = rgba_temp.r; rgb_data[(dim.y-i.y-1)*dim.x*3 + i.x*3+1] = rgba_temp.g; rgb_data[(dim.y-i.y-1)*dim.x*3 + i.x*3+2] = rgba_temp.b; } /* from the rgb_data, generate a GdkPixbuf */ temp_image = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE,8,dim.x,dim.y,dim.x*3*sizeof(guchar), image_free_rgb_data, NULL); return temp_image; } GdkPixbuf * image_from_slice(AmitkDataSet * slice, AmitkViewMode view_mode) { guchar * rgba_data; AmitkVoxel i; AmitkVoxel dim; amide_data_t max,min; GdkPixbuf * temp_image; guint index; rgba_t rgba_temp; AmitkColorTable color_table; /* sanity checks */ g_return_val_if_fail(AMITK_IS_DATA_SET(slice), NULL); g_return_val_if_fail(AMITK_DATA_SET_SLICE_PARENT(slice) != NULL, NULL); dim = AMITK_DATA_SET_DIM(slice); if ((rgba_data = g_try_new(guchar,4*dim.x*dim.y)) == NULL) { g_warning(_("couldn't allocate memory for rgba_data for slice image")); return NULL; } amitk_data_set_get_thresholding_min_max(AMITK_DATA_SET_SLICE_PARENT(slice), AMITK_DATA_SET(slice), AMITK_DATA_SET_SCAN_START(slice), amitk_data_set_get_frame_duration(slice,0), &min, &max); color_table = amitk_data_set_get_color_table_to_use(AMITK_DATA_SET_SLICE_PARENT(slice), view_mode); i.t = i.g = i.z = 0; index=0; /* compensate for the fact that X defines the origin as top left, not bottom left */ for (i.y = dim.y-1; i.y >= 0; i.y--) for (i.x = 0; i.x < dim.x; i.x++, index+=4) { rgba_temp = amitk_color_table_lookup(AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice,i), color_table,min, max); rgba_data[index+0] = rgba_temp.r; rgba_data[index+1] = rgba_temp.g; rgba_data[index+2] = rgba_temp.b; rgba_data[index+3] = rgba_temp.a; } /* from the rgb_data, generate a GdkPixbuf */ temp_image = gdk_pixbuf_new_from_data(rgba_data, GDK_COLORSPACE_RGB, TRUE,8,dim.x,dim.y,dim.x*4*sizeof(guchar), image_free_rgb_data, NULL); return temp_image; } /* note, generally call this function with gate -1, only use the gate parameter if you want to override the data set's specified gate */ GdkPixbuf * image_from_data_sets(GList ** pdisp_slices, GList ** pslice_cache, const gint max_slice_cache_size, GList * objects, const AmitkDataSet * active_ds, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const amide_real_t pixel_size, const AmitkVolume * view_volume, const AmitkFuseType fuse_type, const AmitkViewMode view_mode) { gint slice_num; guint32 total_alpha; guchar * rgb_data; rgba16_t * rgba16_data; guint location; AmitkVoxel i; AmitkVoxel dim; amide_data_t max,min; GdkPixbuf * temp_image; rgba_t rgba_temp; GList * slices; GList * temp_slices; AmitkDataSet * slice; AmitkColorTable color_table; AmitkDataSet * overlay_slice = NULL; gint j; AmitkCanvasPoint pixel_size2; /* sanity checks */ g_return_val_if_fail(objects != NULL, NULL); pixel_size2.x = pixel_size2.y = pixel_size; slices = amitk_data_sets_get_slices(objects, pslice_cache, max_slice_cache_size, start, duration, gate, pixel_size2,view_volume); g_return_val_if_fail(slices != NULL, NULL); /* get the dimensions. since all slices have the same dimensions, we'll just get the first */ dim = AMITK_DATA_SET_DIM(slices->data); /* allocate and initialize space for a temporary storage buffer */ rgba16_data = g_try_new(rgba16_t,dim.y*dim.x); g_return_val_if_fail(rgba16_data != NULL, NULL); for (j=0; jdata; if ((fuse_type == AMITK_FUSE_TYPE_OVERLAY) && (AMITK_DATA_SET_SLICE_PARENT(slice) == active_ds)) { overlay_slice = slice; } else { /* blend this slice */ slice_num++; amitk_data_set_get_thresholding_min_max(AMITK_DATA_SET_SLICE_PARENT(slice), AMITK_DATA_SET(slice), start, duration, &min, &max); color_table = amitk_data_set_get_color_table_to_use(AMITK_DATA_SET_SLICE_PARENT(slice), view_mode); /* now add this slice into the rgba16 data */ i.t = i.g = i.z = 0; location=0; /* compensate for the fact that X defines the origin as top left, not bottom left */ for (i.y = dim.y-1; i.y >= 0; i.y--) for (i.x = 0; i.x < dim.x; i.x++, location++) { rgba_temp = amitk_color_table_lookup(AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice,i), color_table,min, max); total_alpha = rgba16_data[location].a + rgba_temp.a; if (total_alpha == 0) { rgba16_data[location].r = (((slice_num-1)*rgba16_data[location].r + rgba_temp.r)/ ((gdouble) slice_num)); rgba16_data[location].g = (((slice_num-1)*rgba16_data[location].g + rgba_temp.g)/ ((gdouble) slice_num)); rgba16_data[location].b = (((slice_num-1)*rgba16_data[location].b + rgba_temp.b)/ ((gdouble) slice_num)); } else if (rgba16_data[location].a == 0) { rgba16_data[location].r = rgba_temp.r; rgba16_data[location].g = rgba_temp.g; rgba16_data[location].b = rgba_temp.b; rgba16_data[location].a = rgba_temp.a; } else if (rgba_temp.a != 0) { rgba16_data[location].r = ((rgba16_data[location].r*rgba16_data[location].a + rgba_temp.r*rgba_temp.a)/ ((gdouble) total_alpha)); rgba16_data[location].g = ((rgba16_data[location].g*rgba16_data[location].a + rgba_temp.g*rgba_temp.a)/ ((gdouble) total_alpha)); rgba16_data[location].b = ((rgba16_data[location].b*rgba16_data[location].a + rgba_temp.b*rgba_temp.a)/ ((gdouble) total_alpha)); rgba16_data[location].a = total_alpha; } } } temp_slices = temp_slices->next; } /* allocate space for the true rgb buffer */ rgb_data = g_try_new(guchar,3*dim.y*dim.x); g_return_val_if_fail(rgb_data != NULL, NULL); /* now convert our temp rgb data to real rgb data */ i.z = 0; location=0; for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++, location++) { rgb_data[3*location+0] = rgba16_data[location].r < 0xFF ? rgba16_data[location].r : 0xFF; rgb_data[3*location+1] = rgba16_data[location].g < 0xFF ? rgba16_data[location].g : 0xFF; rgb_data[3*location+2] = rgba16_data[location].b < 0xFF ? rgba16_data[location].b : 0xFF; } /* if we have a data set we're overlaying, add it in now */ if (overlay_slice != NULL) { amitk_data_set_get_thresholding_min_max(AMITK_DATA_SET_SLICE_PARENT(overlay_slice), AMITK_DATA_SET(overlay_slice), start, duration, &min, &max); color_table = amitk_data_set_get_color_table_to_use(AMITK_DATA_SET_SLICE_PARENT(overlay_slice), view_mode); i.t = i.g = i.z = 0; for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) { rgba_temp = amitk_color_table_lookup(AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(overlay_slice,i), color_table,min, max); /* compensate for the fact that X defines the origin as top left, not bottom left */ location = (dim.y - i.y - 1)*dim.x+i.x; if (rgba_temp.a != 0) { rgb_data[3*location+0] = rgba_temp.r; rgb_data[3*location+1] = rgba_temp.g; rgb_data[3*location+2] = rgba_temp.b; } } } /* from the rgb_data, generate a GdkPixbuf */ temp_image = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE,8,dim.x,dim.y,dim.x*3*sizeof(guchar), image_free_rgb_data, NULL); /* cleanup */ g_free(rgba16_data); if (pdisp_slices != NULL) { amitk_objects_unref((*pdisp_slices)); *pdisp_slices = slices; } else { amitk_objects_unref(slices); } return temp_image; } /* get the icon to use for this modality */ GdkPixbuf * image_get_data_set_pixbuf(AmitkDataSet * ds) { GdkPixbuf * pixbuf; guchar * object_icon_data; g_return_val_if_fail(AMITK_IS_DATA_SET(ds), NULL); switch (AMITK_DATA_SET_MODALITY(ds)) { case AMITK_MODALITY_SPECT: object_icon_data = SPECT_icon_data; break; case AMITK_MODALITY_MRI: object_icon_data = MRI_icon_data; break; case AMITK_MODALITY_PET: object_icon_data = PET_icon_data; break; case AMITK_MODALITY_CT: case AMITK_MODALITY_OTHER: default: object_icon_data = CT_icon_data; break; } pixbuf = image_from_8bit(object_icon_data, OBJECT_ICON_XSIZE,OBJECT_ICON_YSIZE, AMITK_DATA_SET_COLOR_TABLE(ds, AMITK_VIEW_MODE_SINGLE)); return pixbuf; } amide-1.0.6/amide-current/src/image.h000066400000000000000000000061001423227705100173560ustar00rootroot00000000000000/* image.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __IMAGE_H__ #define __IMAGE_H__ /* header files that are always needed with this file */ #include #include "amide.h" #include "amitk_common.h" #include "amitk_study.h" #include "amitk_roi.h" #include "render.h" #define IMAGE_DISTRIBUTION_WIDTH 100 /* external functions */ GdkPixbuf * image_slice_intersection(const AmitkRoi * roi, const AmitkVolume * canvas_slice, const amide_real_t pixel_size, #ifdef AMIDE_LIBGNOMECANVAS_AA const gdouble transparency, #else const gboolean fill_roi, #endif rgba_t color, AmitkPoint * return_offset, AmitkPoint * return_corner); GdkPixbuf * image_blank(const amide_intpoint_t width, const amide_intpoint_t height, rgba_t image_color); GdkPixbuf * image_from_8bit(const guchar * image, const amide_intpoint_t width, const amide_intpoint_t height, const AmitkColorTable color_table); #ifdef AMIDE_LIBVOLPACK_SUPPORT GdkPixbuf * image_from_renderings(renderings_t * renderings, gint16 image_width, gint16 image_height, AmideEye eyes, gdouble eye_angle, gint16 eye_width); #endif GdkPixbuf * image_of_distribution(AmitkDataSet * ds, rgb_t fg, AmitkUpdateFunc update_func, gpointer update_data); GdkPixbuf * image_from_colortable(const AmitkColorTable color_table, const amide_intpoint_t width, const amide_intpoint_t height, const amide_data_t min, const amide_data_t max, const amide_data_t data_set_min, const amide_data_t data_set_max, const gboolean horizontal); GdkPixbuf * image_from_projection(AmitkDataSet * projection); GdkPixbuf * image_from_slice(AmitkDataSet * slice, AmitkViewMode view_mode); GdkPixbuf * image_from_data_sets(GList ** pdisp_slices, GList ** pslice_cache, const gint max_slice_cache_size, GList * objects, const AmitkDataSet * active_ds, const amide_time_t start, const amide_time_t duration, const amide_intpoint_t gate, const amide_real_t pixel_size, const AmitkVolume * view_volume, const AmitkFuseType fuse_type, const AmitkViewMode view_mode); GdkPixbuf * image_get_data_set_pixbuf(AmitkDataSet * ds); #endif /* __IMAGE_H__ */ amide-1.0.6/amide-current/src/legacy.c000066400000000000000000000562571423227705100175550ustar00rootroot00000000000000/* legacy.c - for loading in .xif files previous to the 2.0 format, * these files were generated by amide versions previous to 0.7.0 * * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "legacy.h" /* external variables */ static gchar * roi_type_names[] = { "Ellipsoid", "Elliptic Cylinder", "Box", "2D Isocontour", "3D Isocontour" }; #define NUM_ROI_TYPES 5 static gchar * modality_names[] = { "PET", "SPECT", "CT", "MRI", "Other" }; #define NUM_MODALITIES 5 static gchar * threshold_names[] = { "per slice", "per frame", "interpolated between frames", "global" }; #define LEGACY_COLOR_TABLE_NUM 24 gchar * color_table_legacy_names[] = { "black/white linear", "white/black linear", "black/white/black", "white/black/white", "red temperature", "inverse red temp.", "blue temperature", "inv. blue temp.", "green temperature", "inv. green temp.", "hot metal", "inv. hot metal", "hot blue", "inverse hot blue", "hot green", "inverse hot green", "spectrum", "inverse spectrum", "NIH + white", "inv. NIH + white", "NIH", "inverse NIH", "viridis", "inverse viridis" }; #define NUM_THRESHOLDS 4 static AmitkVoxel voxel3d_read_xml(xmlNodePtr nodes, gchar * descriptor, gchar **perror_buf) { gchar * temp_string; AmitkVoxel return_vp; gint x,y,z; gint error=0; return_vp = zero_voxel; temp_string = xml_get_string(nodes, descriptor); if (temp_string != NULL) { /* convert to a voxel */ error = sscanf(temp_string,"%d\t%d\t%d", &x,&y,&z); g_free(temp_string); return_vp.x = x; return_vp.y = y; return_vp.z = z; return_vp.g = 1; return_vp.t = 1; } if ((temp_string == NULL) || (error == EOF)) { return_vp.x = return_vp.y = return_vp.z = return_vp.g = return_vp.t = 0; amitk_append_str_with_newline(perror_buf,"Couldn't read value for %s, substituting [%d %d %d %d %d]", descriptor, return_vp.x, return_vp.y, return_vp.z, return_vp.g, return_vp.t); } return return_vp; } /* function to load in a raw_data structure from a legacy file */ static AmitkRawData * data_set_load_xml(gchar * data_set_xml_filename, gchar **perror_buf) { xmlDocPtr doc; AmitkRawData * new_data_set; xmlNodePtr nodes; AmitkRawFormat i_raw_data_format, raw_data_format; gchar * temp_string; gchar * data_set_raw_filename; AmitkVoxel dim; /* parse the xml file */ if ((doc = xmlParseFile(data_set_xml_filename)) == NULL) { amitk_append_str_with_newline(perror_buf,"Couldn't Parse AMIDE data_set xml file %s", data_set_xml_filename); return NULL; } /* get the root of our document */ if ((nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf,"Data Set xml file doesn't appear to have a root: %s", data_set_xml_filename); return NULL; } /* get the document tree */ nodes = nodes->children; /* figure out the data format */ temp_string = xml_get_string(nodes, "raw_data_format"); #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_data_format = AMITK_RAW_FORMAT_DOUBLE_64_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_data_format = AMITK_RAW_FORMAT_DOUBLE_64_LE; #endif if (temp_string != NULL) for (i_raw_data_format=0; i_raw_data_format < AMITK_RAW_FORMAT_NUM; i_raw_data_format++) if (g_ascii_strcasecmp(temp_string, amitk_raw_format_legacy_names[i_raw_data_format]) == 0) raw_data_format = i_raw_data_format; g_free(temp_string); /* get the rest of the parameters */ dim = amitk_voxel_read_xml(nodes, "dim", perror_buf); /* get the name of our associated data file */ data_set_raw_filename = xml_get_string(nodes, "raw_data_file"); /* now load in the raw data */ #ifdef AMIDE_DEBUG g_print("reading data from file %s\n", data_set_raw_filename); #endif new_data_set = amitk_raw_data_import_raw_file(data_set_raw_filename, NULL, raw_data_format, dim, 0, NULL, NULL); /* and we're done */ g_free(data_set_raw_filename); xmlFreeDoc(doc); return new_data_set; } /* function to load in an alignment point xml file */ static AmitkFiducialMark * align_pt_load_xml(gchar * pt_xml_filename, gchar **perror_buf, AmitkSpace *space) { xmlDocPtr doc; AmitkFiducialMark * new_pt; AmitkPoint point; xmlNodePtr nodes; gchar * temp_string; /* parse the xml file */ if ((doc = xmlParseFile(pt_xml_filename)) == NULL) { amitk_append_str_with_newline(perror_buf, "Couldn't Parse AMIDE alignment point xml file %s", pt_xml_filename); return NULL; } /* get the root of our document */ if ((nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf,"AMIDE alignment point xml file doesn't appear to have a root: %s", pt_xml_filename); return NULL; } new_pt = amitk_fiducial_mark_new(); /* get the name */ temp_string = xml_get_string(nodes->children, "text"); if (temp_string != NULL) { amitk_object_set_name(AMITK_OBJECT(new_pt), temp_string); g_free(temp_string); } /* get the document tree */ nodes = nodes->children; /* previous to version xif version 2.0, points were defined only with respect to their parent's space*/ amitk_space_copy_in_place(AMITK_SPACE(new_pt), space); /* the "point" option was eliminated in version 0.7.11, just using the space's offset instead */ point = amitk_point_read_xml(nodes, "point", perror_buf); point = amitk_space_s2b(AMITK_SPACE(new_pt), point); amitk_space_set_offset(AMITK_SPACE(new_pt), point); /* and we're done */ xmlFreeDoc(doc); return new_pt; } /* function to load in a list of alignment point xml nodes */ static GList * align_pts_load_xml(xmlNodePtr node_list, gchar **perror_buf, AmitkSpace * space) { gchar * file_name; GList * new_pts; AmitkFiducialMark * new_pt; if (node_list != NULL) { /* first, recurse on through the list */ new_pts = align_pts_load_xml(node_list->next, perror_buf, space); /* load in this node */ file_name = xml_get_string(node_list->children, "text"); new_pt = align_pt_load_xml(file_name, perror_buf, space); new_pts = g_list_prepend(new_pts, new_pt); g_free(file_name); } else new_pts = NULL; return new_pts; } /* function to load in a volume xml file */ static AmitkDataSet * volume_load_xml(gchar * volume_xml_filename, AmitkInterpolation interpolation, gchar ** perror_buf) { xmlDocPtr doc; AmitkDataSet * new_volume; xmlNodePtr nodes; xmlNodePtr pts_nodes; AmitkModality i_modality; AmitkColorTable i_color_table; AmitkThresholding i_thresholding; gchar * temp_string; gchar * scan_date; gchar * data_set_xml_filename; gchar * internal_scaling_xml_filename; GList * align_pts; AmitkSpace * space; AmitkViewMode i_view_mode; /* parse the xml file */ if ((doc = xmlParseFile(volume_xml_filename)) == NULL) { amitk_append_str_with_newline(perror_buf,"Couldn't Parse AMIDE volume xml file %s", volume_xml_filename); return NULL; } /* get the root of our document */ if ((nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf,"AMIDE volume xml file doesn't appear to have a root: %s", volume_xml_filename); return NULL; } new_volume = amitk_data_set_new(NULL, -1); new_volume->interpolation = interpolation; /* get the volume name */ temp_string = xml_get_string(nodes->children, "text"); if (temp_string != NULL) { amitk_object_set_name(AMITK_OBJECT(new_volume),temp_string); g_free(temp_string); } /* get the document tree */ nodes = nodes->children; /* get the date the scan was made */ scan_date = xml_get_string(nodes, "scan_date"); amitk_data_set_set_scan_date(new_volume, scan_date); g_free(scan_date); /* figure out the modality */ temp_string = xml_get_string(nodes, "modality"); if (temp_string != NULL) for (i_modality=0; i_modality < NUM_MODALITIES; i_modality++) if (g_ascii_strcasecmp(temp_string, modality_names[i_modality]) == 0) new_volume->modality = i_modality; g_free(temp_string); /* figure out the color table */ temp_string = xml_get_string(nodes, "color_table"); if (temp_string != NULL) for (i_color_table=0; i_color_table < LEGACY_COLOR_TABLE_NUM; i_color_table++) if (g_ascii_strcasecmp(temp_string, color_table_legacy_names[i_color_table]) == 0) for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) new_volume->color_table[i_view_mode] = i_color_table; g_free(temp_string); /* load in our data set */ data_set_xml_filename = xml_get_string(nodes, "data_set_file"); internal_scaling_xml_filename = xml_get_string(nodes, "internal_scaling_file"); if ((data_set_xml_filename != NULL) && (internal_scaling_xml_filename != NULL)) { new_volume->raw_data = data_set_load_xml(data_set_xml_filename, perror_buf); if (new_volume->internal_scaling_factor != NULL) { g_object_unref(new_volume->internal_scaling_factor); new_volume->internal_scaling_factor = NULL; } new_volume->internal_scaling_factor = data_set_load_xml(internal_scaling_xml_filename, perror_buf); /* the type of internal_scaling has been changed to double as of amide 0.7.1 */ if (new_volume->internal_scaling_factor->format != AMITK_FORMAT_DOUBLE) { AmitkRawData * old_scaling; AmitkVoxel i; amitk_append_str_with_newline(perror_buf,"wrong type found on internal scaling, converting to double"); old_scaling = new_volume->internal_scaling_factor; new_volume->internal_scaling_factor = amitk_raw_data_new_with_data(AMITK_FORMAT_DOUBLE, old_scaling->dim); if (new_volume->internal_scaling_factor == NULL) { amitk_append_str_with_newline(perror_buf,"couldn't allocate memory space for the new scaling structure"); amitk_object_unref(new_volume); return NULL; } for (i.t=0; i.tinternal_scaling_factor->dim.t; i.t++) for (i.g=0; i.ginternal_scaling_factor->dim.g; i.g++) for (i.z=0; i.zinternal_scaling_factor->dim.z; i.z++) for (i.y=0; i.yinternal_scaling_factor->dim.y; i.y++) for (i.x=0; i.xinternal_scaling_factor->dim.x; i.x++) AMITK_RAW_DATA_DOUBLE_SET_CONTENT(new_volume->internal_scaling_factor,i) = amitk_raw_data_get_value(old_scaling, i); g_object_unref(old_scaling); } /* parameters that aren't in older versions and default values aren't good enough*/ amitk_data_set_set_scale_factor(new_volume, xml_get_data(nodes, "external_scaling", perror_buf)); } else { /* ---- legacy cruft previous to .xif version 1.4 ----- */ gchar * raw_data_filename; AmitkRawFormat i_raw_data_format, raw_data_format; AmitkVoxel temp_dim; amitk_append_str_with_newline(perror_buf,"no data_set file, will continue with the assumption of a .xif format previous to 1.4"); /* get the name of our associated data file */ raw_data_filename = xml_get_string(nodes, "raw_data"); /* and figure out the data format */ temp_string = xml_get_string(nodes, "data_format"); #if (G_BYTE_ORDER == G_BIG_ENDIAN) raw_data_format = AMITK_RAW_FORMAT_DOUBLE_64_BE; #else /* (G_BYTE_ORDER == G_LITTLE_ENDIAN) */ raw_data_format = AMITK_RAW_FORMAT_DOUBLE_64_LE; #endif if (temp_string != NULL) for (i_raw_data_format=0; i_raw_data_format < AMITK_RAW_FORMAT_NUM; i_raw_data_format++) if (g_ascii_strcasecmp(temp_string, amitk_raw_format_legacy_names[i_raw_data_format]) == 0) raw_data_format = i_raw_data_format; g_free(temp_string); temp_dim = voxel3d_read_xml(nodes, "dim", perror_buf); temp_dim.t = xml_get_int(nodes, "num_frames", perror_buf); amitk_data_set_set_scale_factor(new_volume, xml_get_data(nodes, "conversion", perror_buf)); /* now load in the raw data */ new_volume->raw_data = amitk_raw_data_import_raw_file(raw_data_filename, NULL, raw_data_format, temp_dim, 0, NULL, NULL); g_free(raw_data_filename); /* -------- end legacy cruft -------- */ } /* figure out the rest of the parameters */ new_volume->voxel_size = amitk_point_read_xml(nodes, "voxel_size", perror_buf); new_volume->scan_start = xml_get_time(nodes, "scan_start", perror_buf); new_volume->frame_duration = xml_get_times(nodes, "frame_duration", AMITK_DATA_SET_NUM_FRAMES(new_volume), perror_buf); new_volume->threshold_max[0] = xml_get_data(nodes, "threshold_max", perror_buf); new_volume->threshold_min[0] = xml_get_data(nodes, "threshold_min", perror_buf); new_volume->threshold_max[1] = xml_get_data(nodes, "threshold_max_1", perror_buf); new_volume->threshold_min[1] = xml_get_data(nodes, "threshold_min_1", perror_buf); new_volume->threshold_ref_frame[0] = xml_get_int(nodes,"threshold_ref_frame_0", perror_buf); new_volume->threshold_ref_frame[1] = xml_get_int(nodes,"threshold_ref_frame_1", perror_buf); space = amitk_space_read_xml(nodes, "coord_frame", perror_buf); amitk_space_copy_in_place(AMITK_SPACE(new_volume), space); g_object_unref(space); /* figure out the thresholding */ temp_string = xml_get_string(nodes, "threshold_type"); if (temp_string != NULL) for (i_thresholding=0; i_thresholding < NUM_THRESHOLDS; i_thresholding++) if (g_ascii_strcasecmp(temp_string, threshold_names[i_thresholding]) == 0) new_volume->thresholding = i_thresholding; g_free(temp_string); /* figure out the scaling type */ if (new_volume->internal_scaling_factor->dim.z > 1) new_volume->scaling_type = AMITK_SCALING_TYPE_2D; else if (new_volume->internal_scaling_factor->dim.t > 1) new_volume->scaling_type = AMITK_SCALING_TYPE_1D; else new_volume->scaling_type = AMITK_SCALING_TYPE_0D; /* recalc the temporary parameters */ amitk_data_set_calc_far_corner(new_volume); /* and load in any alignment points */ pts_nodes = xml_get_node(nodes, "Alignment_points"); if (pts_nodes != NULL) { pts_nodes = pts_nodes->children; if (pts_nodes != NULL) { align_pts = align_pts_load_xml(pts_nodes, perror_buf, AMITK_SPACE(new_volume)); amitk_object_add_children(AMITK_OBJECT(new_volume), align_pts); amitk_objects_unref(align_pts); } } /* and we're done */ xmlFreeDoc(doc); return new_volume; } /* function to load in a list of volume xml nodes */ static GList * volumes_load_xml(xmlNodePtr node_list, AmitkInterpolation interpolation, gchar **perror_buf) { gchar * file_name; GList * new_data_sets; AmitkDataSet * new_ds; if (node_list != NULL) { /* first, recurse on through the list */ new_data_sets = volumes_load_xml(node_list->next, interpolation, perror_buf); /* load in this node */ file_name = xml_get_string(node_list->children, "text"); new_ds = volume_load_xml(file_name, interpolation, perror_buf); new_data_sets = g_list_prepend(new_data_sets, new_ds); g_free(file_name); } else new_data_sets = NULL; return new_data_sets; } /* function to load in an ROI xml file */ AmitkRoi * roi_load_xml(gchar * roi_xml_filename, gchar **perror_buf) { xmlDocPtr doc; AmitkRoi * new_roi; xmlNodePtr nodes; AmitkRoiType i_roi_type; gchar * temp_string; gchar * isocontour_xml_filename; AmitkSpace * space; /* parse the xml file */ if ((doc = xmlParseFile(roi_xml_filename)) == NULL) { amitk_append_str_with_newline(perror_buf,"Couldn't Parse AMIDE ROI xml file %s",roi_xml_filename); return NULL; } /* get the root of our document */ if ((nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf,"AMIDE ROI xml file doesn't appear to have a root: %s", roi_xml_filename); return NULL; } new_roi = amitk_roi_new(0); /* get the roi name */ temp_string = xml_get_string(nodes->children, "text"); if (temp_string != NULL) { amitk_object_set_name(AMITK_OBJECT(new_roi),temp_string); g_free(temp_string); } /* get the document tree */ nodes = nodes->children; /* figure out the type */ temp_string = xml_get_string(nodes, "type"); if (temp_string != NULL) for (i_roi_type=0; i_roi_type < NUM_ROI_TYPES; i_roi_type++) if (g_ascii_strcasecmp(temp_string, roi_type_names[i_roi_type]) == 0) new_roi->type = i_roi_type; g_free(temp_string); /* and figure out the rest of the parameters */ space = amitk_space_read_xml(nodes, "coord_frame", perror_buf); amitk_space_copy_in_place(AMITK_SPACE(new_roi), space); g_object_unref(space); amitk_volume_set_corner(AMITK_VOLUME(new_roi), amitk_point_read_xml(nodes, "corner", perror_buf)); /* isocontour specific stuff */ if (AMITK_ROI_TYPE_ISOCONTOUR(new_roi)) { new_roi->voxel_size = amitk_point_read_xml(nodes, "voxel_size", perror_buf); new_roi->isocontour_min_value = xml_get_real(nodes, "isocontour_value", perror_buf); isocontour_xml_filename = xml_get_string(nodes, "isocontour_file"); if (isocontour_xml_filename != NULL) new_roi->map_data = data_set_load_xml(isocontour_xml_filename, perror_buf); } /* children were never used */ /* make sure to mark the roi as undrawn if needed */ if (AMITK_ROI_TYPE_ISOCONTOUR(new_roi)) { if (new_roi->map_data == NULL) AMITK_VOLUME(new_roi)->valid = FALSE; } else { if (POINT_EQUAL(AMITK_VOLUME_CORNER(new_roi), zero_point)) { AMITK_VOLUME(new_roi)->valid = FALSE; } } /* and we're done */ xmlFreeDoc(doc); return new_roi; } /* function to load in a list of ROI xml nodes */ static GList * rois_load_xml(xmlNodePtr node_list, gchar **perror_buf) { gchar * roi_xml_filename; GList * new_rois; AmitkRoi * new_roi; if (node_list != NULL) { /* first, recurse on through the list */ new_rois = rois_load_xml(node_list->next, perror_buf); /* load in this node */ roi_xml_filename = xml_get_string(node_list->children, "text"); new_roi = roi_load_xml(roi_xml_filename, perror_buf); new_rois = g_list_prepend(new_rois, new_roi); g_free(roi_xml_filename); } else new_rois = NULL; return new_rois; } AmitkStudy * legacy_load_xml(gchar ** perror_buf) { AmitkStudy * study = NULL; AmitkSpace * space; AmitkPoint view_center; AmitkInterpolation interpolation; xmlDocPtr doc; xmlNodePtr nodes; xmlNodePtr object_nodes; gchar * temp_string; gchar * file_version; gchar * creation_date; GList * objects; /* warn that this is an old file version */ amitk_append_str_with_newline(perror_buf,"A .xif file previous to file version 2.0 found.\n" "Invoking legacy loader, please resave file as soon as possible"); /* parse the xml file */ if ((doc = xmlParseFile("Study.xml")) == NULL) { amitk_append_str_with_newline(perror_buf,"Couldn't Parse AMIDE xml file:\n\tStudy.xml"); return NULL; } /* get the root of our document */ if ((nodes = xmlDocGetRootElement(doc)) == NULL) { amitk_append_str_with_newline(perror_buf,"AMIDE xml file doesn't appear to have a root:\n\tStudy.xml"); return NULL; } study = amitk_study_new(NULL); /* get the study name */ temp_string = xml_get_string(nodes->children, "text"); if (temp_string != NULL) { amitk_object_set_name(AMITK_OBJECT(study),temp_string); g_free(temp_string); } /* get the document tree */ nodes = nodes->children; /* get the version of the data file */ file_version = xml_get_string(nodes, "AMIDE_Data_File_Version"); /* get the creation date of the study */ creation_date = xml_get_string(nodes, "creation_date"); amitk_study_set_creation_date(study, creation_date); g_free(creation_date); /* get our study parameters */ space = amitk_space_read_xml(nodes, "coord_frame", perror_buf); amitk_space_copy_in_place(AMITK_SPACE(study), space); g_object_unref(space); /* figure out the interpolation */ temp_string = xml_get_string(nodes, "interpolation"); interpolation = AMITK_INTERPOLATION_NEAREST_NEIGHBOR; if (temp_string != NULL) if (g_ascii_strcasecmp(temp_string, "Trilinear") == 0) interpolation = AMITK_INTERPOLATION_TRILINEAR; g_free(temp_string); /* load in the volumes */ object_nodes = xml_get_node(nodes, "Volumes"); object_nodes = object_nodes->children; objects = volumes_load_xml(object_nodes, interpolation, perror_buf); amitk_object_add_children(AMITK_OBJECT(study), objects); amitk_objects_unref(objects); /* load in the rois */ object_nodes = xml_get_node(nodes, "ROIs"); object_nodes = object_nodes->children; objects = rois_load_xml(object_nodes, perror_buf); amitk_object_add_children(AMITK_OBJECT(study), objects); amitk_objects_unref(objects); /* get our view parameters */ view_center = amitk_point_read_xml(nodes, "view_center", perror_buf); amitk_study_set_view_center(study, amitk_space_s2b(AMITK_SPACE(study), view_center)); amitk_study_set_view_thickness(study, xml_get_real(nodes, "view_thickness", perror_buf)); amitk_study_set_view_start_time(study, xml_get_time(nodes, "view_time", perror_buf)); amitk_study_set_view_duration(study, xml_get_time(nodes, "view_duration", perror_buf)); amitk_study_set_zoom(study, xml_get_real(nodes, "zoom", perror_buf)); /* sanity check */ if (AMITK_STUDY_ZOOM(study) < EPSILON) { amitk_append_str_with_newline(perror_buf,"inappropriate zoom (%5.3f) for study, reseting to 1.0", AMITK_STUDY_ZOOM(study)); amitk_study_set_zoom(study, 1.0); } /* and we're done */ xmlFreeDoc(doc); /* legacy cruft, rip out at some point in the future */ /* compensate for errors in old versions of amide */ if (g_ascii_strcasecmp(file_version, "1.3") < 0) { GList * objects; AmitkObject * object; AmitkPoint new_axes[AMITK_AXIS_NUM]; AmitkPoint new_offset; AmitkAxis i_axis; amitk_append_str_with_newline(perror_buf,"detected file version previous to 1.3, compensating for coordinate errors"); view_center = AMITK_STUDY_VIEW_CENTER(study); view_center.y = -view_center.y; amitk_study_set_view_center(study,view_center); objects = AMITK_OBJECT_CHILDREN(study); while (objects != NULL) { object = objects->data; for (i_axis=0;i_axisnext; } } /* freeing up anything we haven't freed yet */ g_free(file_version); return study; } amide-1.0.6/amide-current/src/legacy.h000066400000000000000000000020571423227705100175470ustar00rootroot00000000000000/* legacy.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __LEGACY_H__ #define __LEGACY_H__ /* header files that are always needed with this file */ #include "amitk_study.h" AmitkStudy * legacy_load_xml(gchar ** perror_buf); #endif /* __LEGACY_H__ */ amide-1.0.6/amide-current/src/libecat_interface.c000066400000000000000000000373561423227705100217330ustar00rootroot00000000000000/* libecat_interface.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBECAT_SUPPORT #include #include #include #include "libecat_interface.h" static char * libecat_data_types[] = { N_("Unknown Data Type"), /* UnknownMatDataType */ N_("Byte"), /* ByteData */ N_("Short (16 bit), Little Endian"), /* VAX_Ix2 */ N_("Integer (32 bit), Little Endian"), /* VAX_Ix4 */ N_("VAX Float (32 bit)"), /* VAX_Rx4 */ N_("IEEE Float (32 bit)"), /* IeeeFloat */ N_("Short (16 bit), Big Endian"), /* SunShort */ N_("Integer (32 bit), Big Endian") /* SunLong */ }; /* NumMatrixDataTypes */ AmitkDataSet * libecat_import(const gchar * libecat_filename, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { MatrixFile * libecat_file=NULL; MatrixData * matrix_data=NULL; MatrixData * matrix_slice=NULL; AmitkVoxel i, j; gint matnum; AmitkDataSet * ds=NULL; guint slice, num_slices; gchar * name; gchar ** frags=NULL; time_t scan_time; AmitkPoint temp_point; AmitkPoint offset_rp; AmitkFormat format; AmitkVoxel dim; AmitkScalingType scaling_type; div_t x; gint divider; gint total_planes, i_plane; gboolean continue_work=TRUE; gchar * temp_string; const gchar * bad_char; Image_subheader * ish; Scan_subheader * ssh; Attn_subheader * ash; gchar * saved_time_locale; gchar * saved_numeric_locale; time_t dob; gint num_corrupted_planes = 0; gdouble calibration_factor = 1.0; saved_time_locale = g_strdup(setlocale(LC_TIME,NULL)); saved_numeric_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_TIME,"POSIX"); setlocale(LC_NUMERIC,"POSIX"); if (!(libecat_file = matrix_open(libecat_filename, MAT_READ_ONLY, MAT_UNKNOWN_FTYPE))) { g_warning(_("Can't open file %s using libecat"), libecat_filename); goto error; } /* check if we can handle the file type */ switch(libecat_file->mhptr->file_type) { case PetImage: /* i.e. CTI 6.4 */ case PetVolume: /* i.e. CTI 7.0 */ case AttenCor: case Sinogram: case Normalization: case InterfileImage: break; case NoData: case PolarMap: case ByteProjection: case PetProjection: case Short3dSinogram: case Byte3dSinogram: case Norm3d: case Float3dSinogram: case ByteImage: case ByteVolume: default: g_warning(_("Don't know how to handle this CTI file type: %d"), libecat_file->mhptr->file_type); goto error; break; } /* we always start at the first iamge */ // matnum = mat_numcod(1,1,1,0,0); /* frame, plane, gate, data, bed */ matnum = libecat_file->dirlist->first->matnum; if (!(matrix_data = matrix_read(libecat_file, matnum, MAT_SUB_HEADER))) { g_warning(_("Libecat can't get header info at matrix %x in file %s"), matnum, libecat_filename); goto error; } /* make sure we know how to process the data type */ /* note that the libecat library handles endian issues */ switch (matrix_data->data_type) { case VAX_Ix2: /* little endian short */ case SunShort: /* big endian short */ format = AMITK_FORMAT_SSHORT; break; case IeeeFloat: /* big endian float */ case VAX_Rx4: /* PDP float */ format = AMITK_FORMAT_FLOAT; break; /* handled data types */ case UnknownMatDataType: case ByteData: case VAX_Ix4: /* little endian int */ case SunLong: /* big endian int? */ case ColorData: case BitData: default: g_warning(_("No support for importing CTI files with data type of: %d (%s)"), matrix_data->data_type, libecat_data_types[((matrix_data->data_type) < NumMatrixDataTypes) ? matrix_data->data_type : 0]); goto error; break; } /* start acquiring some useful information */ dim.x = matrix_data->xdim; dim.y = matrix_data->ydim; dim.z = (matrix_data->zdim == 1) ? libecat_file->mhptr->num_planes : matrix_data->zdim; dim.g = libecat_file->mhptr->num_gates; dim.t = libecat_file->mhptr->num_frames; num_slices = libecat_file->mhptr->num_planes/matrix_data->zdim; /* should we include the calibration factor in the conversion? */ if (libecat_file->mhptr->calibration_units == Calibrated) calibration_factor = libecat_file->mhptr->calibration_factor; /* figure out the size of our factor array */ if (matrix_data->zdim == 1) { /* slice image, non-float data, so we'll need a per/plane (2D) array of scaling factors */ scaling_type = AMITK_SCALING_TYPE_2D; } else { /* volume image, so we'll need a per/frame (1D) array of scaling factors */ scaling_type = AMITK_SCALING_TYPE_1D; } /* init our data structures, it's a CTI File, we'll guess it's PET data */ ds = amitk_data_set_new_with_data(preferences, AMITK_MODALITY_PET, format, dim, scaling_type); if (ds == NULL) { g_warning(_("Couldn't allocate memory space for the data set structure to hold CTI data")); goto error; } /* try figuring out the name */ if (libecat_file->mhptr->study_name[0] != '\0') name = g_strndup(libecat_file->mhptr->study_name, 12); else if (libecat_file->mhptr->original_file_name[0] != '\0') name = g_strndup(libecat_file->mhptr->original_file_name, 32); else {/* no original filename? */ temp_string = g_path_get_basename(libecat_filename); /* remove the extension of the file */ g_strreverse(temp_string); frags = g_strsplit(temp_string, ".", 2); g_free(temp_string); g_strreverse(frags[1]); name = g_strdup(frags[1]); g_strfreev(frags); /* free up now unused strings */ } /* validate the name to utf8 */ if (!g_utf8_validate(name, -1, &bad_char)) { gsize invalid_point = bad_char-name; name[invalid_point] = '\0'; } /* try adding on the reconstruction method */ switch(libecat_file->mhptr->file_type) { case PetImage: case PetVolume: case InterfileImage: ish = (Image_subheader *) matrix_data->shptr; temp_string = name; if (ish->annotation[0] != '\0') name = g_strdup_printf("%s - %s", temp_string, ish->annotation); else name = g_strdup_printf("%s, %d", temp_string, ish->recon_type); g_free(temp_string); break; case AttenCor: ash = (Attn_subheader *) matrix_data->shptr; temp_string = name; name = g_strdup_printf("%s,%d", temp_string, ash->attenuation_type); g_free(temp_string); break; case Sinogram: default: break; } amitk_object_set_name(AMITK_OBJECT(ds),name); #ifdef AMIDE_DEBUG g_print("data set name %s\n",AMITK_OBJECT_NAME(ds)); g_print("\tx size %d\ty size %d\tz size %d\tframes %d\n", dim.x, dim.y, dim.z, dim.t); g_print("\tslices/volume %d\n",num_slices); #endif /* try to enter in a scan date and addition data */ scan_time = libecat_file->mhptr->scan_start_time; amitk_data_set_set_scan_date(ds, ctime(&scan_time)); amitk_data_set_set_subject_name(ds, libecat_file->mhptr->patient_name); amitk_data_set_set_subject_id(ds, libecat_file->mhptr->patient_id); dob = libecat_file->mhptr->patient_birth_date; amitk_data_set_set_subject_dob(ds, ctime(&(dob))); switch(libecat_file->mhptr->patient_orientation) { case FeetFirstProne: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST); break; case HeadFirstProne: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST); break; case FeetFirstSupine: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST); break; case HeadFirstSupine: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST); break; case FeetFirstRight: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST); break; case HeadFirstRight: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST); break; case FeetFirstLeft: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST); break; case HeadFirstLeft: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST); break; case UnknownOrientation: default: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_UNKNOWN); break; } /* get the voxel size */ temp_point.x = 10*matrix_data->pixel_size; temp_point.y = 10*matrix_data->y_size; temp_point.z = 10*matrix_data->z_size; if (isnan(temp_point.x) || isnan(temp_point.y) || isnan(temp_point.z)) {/*handle corrupted cti files */ g_warning(_("Detected corrupted CTI file, will try to continue by guessing voxel_size")); ds->voxel_size = one_point; } else if (EQUAL_ZERO(temp_point.x) || EQUAL_ZERO(temp_point.y) || EQUAL_ZERO(temp_point.z)) { g_warning(_("Detected zero voxel size in CTI file, will try to continue by guessing voxel_size")); ds->voxel_size = one_point; } else ds->voxel_size = temp_point; offset_rp.x = 10*matrix_data->x_origin; offset_rp.y = 10*matrix_data->y_origin; offset_rp.z = 10*matrix_data->z_origin; if (isnan(offset_rp.x) || isnan(offset_rp.y) || isnan(offset_rp.z)) { /*handle corrupted cti files */ g_warning(_("Detected corrupted CTI file, will try to continue by guessing offset")); offset_rp = zero_point; } /* guess the start of the scan is the same as the start of the first frame of data */ /* note, CTI files specify time as integers in msecs */ /* check if we can handle the file type */ switch(libecat_file->mhptr->file_type) { case PetImage: case PetVolume: case InterfileImage: ish = (Image_subheader *) matrix_data->shptr; ds->scan_start = ish->frame_start_time/1000.0; break; case AttenCor: ds->scan_start = 0.0; /* doesn't mean anything */ break; case Sinogram: ssh = (Scan_subheader *) matrix_data->shptr; ds->scan_start = ssh->frame_start_time/1000.0; break; default: break; /* should never get here */ } #ifdef AMIDE_DEBUG g_print("\tscan start time %5.3f\n",ds->scan_start); #endif if (update_func != NULL) { temp_string = g_strdup_printf(_("Importing CTI File:\n %s"), libecat_filename); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = dim.z*dim.g*dim.t; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); /* and load in the data */ for (i.t = 0, i_plane=0; (i.t < AMITK_DATA_SET_NUM_FRAMES(ds)) && (continue_work); i.t++) { #ifdef AMIDE_DEBUG g_print("\tloading frame:\t%d",i.t); #endif for (i.g = 0; (i.g < AMITK_DATA_SET_NUM_GATES(ds)) && (continue_work); i.g++) { for (slice=0; (slice < num_slices) && (continue_work) ; slice++) { matnum=mat_numcod(i.t+1,slice+1,i.g+1,0,0);/* frame, plane, gate, data, bed */ /* read in the corresponding cti slice */ if ((matrix_slice = matrix_read(libecat_file, matnum, 0)) == NULL) { num_corrupted_planes+=dim.z/num_slices; /* g_warning(_("Libecat can't get image matrix %x in file %s"), matnum, libecat_filename); */ /* goto error; */ } else { /* set the frame duration, note, CTI files specify time as integers in msecs */ switch(libecat_file->mhptr->file_type) { case PetImage: case PetVolume: case InterfileImage: ish = (Image_subheader *) matrix_slice->shptr; ds->frame_duration[i.t] = ish->frame_duration/1000.0; break; case Normalization: case AttenCor: ds->frame_duration[i.t] = 1.0; /* doesn't mean anything */ break; case Sinogram: ssh = (Scan_subheader *) matrix_slice->shptr; ds->frame_duration[i.t] = ssh->frame_duration/1000.0; break; default: break; /* should never get here */ } for (i.z = slice*(dim.z/num_slices); i.z < dim.z/num_slices + slice*(dim.z/num_slices); i.z++, i_plane++) { if (update_func != NULL) { x = div(i_plane,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) i_plane)/((gdouble)total_planes)); } /* save the scale factor */ j.x = j.y = 0; j.z = slice; j.g = i.g; j.t = i.t; if (scaling_type == AMITK_SCALING_TYPE_2D) *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, j) = calibration_factor*matrix_slice->scale_factor; else if (i.z == 0) /* AMITK_SCALING_TYPE_1D */ *AMITK_RAW_DATA_DOUBLE_1D_SCALING_POINTER(ds->internal_scaling_factor, j) = calibration_factor*matrix_slice->scale_factor; switch (format) { case AMITK_FORMAT_SSHORT: /* copy the data into the volume */ /* note, we compensate here for the fact that we define our origin as the bottom left, not top left like the CTI file */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_SSHORT_SET_CONTENT(ds->raw_data,i) = *(((amitk_format_SSHORT_t *) matrix_slice->data_ptr) + (dim.y*dim.x*(i.z-slice*(dim.z/num_slices)) +dim.x*(dim.y-i.y-1) +i.x)); break; case AMITK_FORMAT_FLOAT: /* copy the data into the volume */ /* note, we compensate here for the fact that we define our origin as the bottom left, not top left like the CTI file */ for (i.y = 0; i.y < dim.y; i.y++) for (i.x = 0; i.x < dim.x; i.x++) AMITK_RAW_DATA_FLOAT_SET_CONTENT(ds->raw_data,i) = *(((amitk_format_FLOAT_t *) matrix_slice->data_ptr) + (dim.y*dim.x*(i.z-slice*(dim.z/num_slices)) +dim.x*(dim.y-i.y-1) +i.x)); break; default: g_error("unexpected case in %s at %d\n", __FILE__, __LINE__); goto error; break; } /* format */ } /* i.z */ free_matrix_data(matrix_slice); } /* matrix_slice != NULL */ } /* slice */ } /* i.g */ #ifdef AMIDE_DEBUG g_print("\tduration:\t%5.3f\n",ds->frame_duration[i.t]); #endif } /* i.t */ if (num_corrupted_planes > 0) g_warning(_("Libecat returned %d blank planes... corrupted data file? Use data with caution."), num_corrupted_planes); if (!continue_work) goto error; /* setup remaining volume parameters */ amitk_data_set_set_injected_dose(ds, amitk_dose_unit_convert_from(libecat_file->mhptr->dosage, AMITK_DOSE_UNIT_MILLICURIE)); amitk_data_set_set_subject_weight(ds, libecat_file->mhptr->patient_weight); amitk_data_set_set_scale_factor(ds, 1.0); /* set the external scaling factor */ amitk_data_set_calc_far_corner(ds); /* set the far corner of the volume */ amitk_data_set_calc_min_max(ds, update_func, update_data); amitk_volume_set_center(AMITK_VOLUME(ds), offset_rp); goto function_end; error: if (ds != NULL) ds = amitk_object_unref(ds); function_end: if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); if (libecat_file != NULL) matrix_close(libecat_file); if (matrix_data != NULL) free_matrix_data(matrix_data); setlocale(LC_NUMERIC, saved_time_locale); setlocale(LC_NUMERIC, saved_numeric_locale); g_free(saved_time_locale); g_free(saved_numeric_locale); return ds; } #endif amide-1.0.6/amide-current/src/libecat_interface.h000066400000000000000000000024351423227705100217260ustar00rootroot00000000000000/* libecat_interface.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBECAT_SUPPORT #ifndef __LIBECAT_INTERFACE_H__ #define __LIBECAT_INTERFACE_H__ /* headers always needed with this guy */ #include "amitk_data_set.h" /* external functions */ AmitkDataSet * libecat_import(const gchar * filename, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data); #endif /* __LIBECAT_INTERFACE_H__ */ #endif /* AMIDE_LIBECAT_SUPPORT */ amide-1.0.6/amide-current/src/libmdc_interface.c000066400000000000000000001155301423227705100215510ustar00rootroot00000000000000/* libmdc_interface.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "amide_config.h" #ifdef AMIDE_LIBMDC_SUPPORT #include "amitk_data_set.h" #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include "libmdc_interface.h" #include #include #include static char * libmdc_unknown = "Unknown"; libmdc_format_t libmdc_import_to_format[LIBMDC_NUM_IMPORT_METHODS] = { LIBMDC_NONE, LIBMDC_GIF, LIBMDC_ACR, LIBMDC_CONC, LIBMDC_ECAT6, LIBMDC_ECAT7, LIBMDC_INTF, LIBMDC_ANLZ, LIBMDC_DICM, LIBMDC_NIFTI }; gchar * libmdc_import_menu_names[LIBMDC_NUM_IMPORT_METHODS] = { N_("(_X)MedCon Guess"), N_("_GIF 87a/89a"), N_("Acr/_Nema 2.0"), N_("_Siemens/Concorde"), N_("ECAT _6 via (X)MedCon"), N_("ECAT _7 via (X)MedCon"), N_("_InterFile 3.3"), N_("_Analyze (SPM)"), N_("_DICOM 3.0 via (X)MedCon"), N_("_NIFTI via (X)MedCon") }; gchar * libmdc_import_menu_explanations[LIBMDC_NUM_IMPORT_METHODS] = { N_("let (X)MedCon/libmdc guess file type"), N_("Import a file stored as GIF"), N_("Import a Acr/Nema 2.0 file"), N_("Import a Siemens/Concorde file"), N_("Import a CTI/ECAT 6 file through (X)MedCon"), N_("Import a CTI/ECAT 7 file through (X)MedCon"), N_("Import a InterFile 3.3 file"), N_("Import an Analyze file"), N_("Import a DICOM 3.0 file through (X)MedCon"), N_("Import a NIFTI file through (X)MedCon") }; libmdc_format_t libmdc_export_to_format[LIBMDC_NUM_EXPORT_METHODS] = { LIBMDC_ACR, LIBMDC_CONC, LIBMDC_ECAT6, LIBMDC_INTF, LIBMDC_ANLZ, LIBMDC_DICM, LIBMDC_NIFTI }; gchar * libmdc_export_menu_names[LIBMDC_NUM_EXPORT_METHODS] = { N_("Acr/Nema 2.0"), N_("Siemens/Concorde"), N_("ECAT 6 via (X)MedCon"), N_("InterFile 3.3"), N_("Analyze (SPM)"), N_("DICOM 3.0 via (X)MedCon"), N_("NIFTI") }; gchar * libmdc_export_menu_explanations[LIBMDC_NUM_EXPORT_METHODS] = { N_("Export a Acr/Nema 2.0 file"), N_("Export a Siemens/Concorde file"), N_("Export a CTI/ECAT 6 file"), N_("Export a InterFile 3.3 file"), N_("Export an Analyze file"), N_("Export a DICOM 3.0 file"), N_("Export a NIFTI file") }; static gint libmdc_format_number(libmdc_format_t format) { switch(format) { case LIBMDC_RAW: return MDC_FRMT_RAW; break; case LIBMDC_ASCII: return MDC_FRMT_ASCII; break; case LIBMDC_GIF: return MDC_FRMT_GIF; break; case LIBMDC_ACR: return MDC_FRMT_ACR; break; case LIBMDC_CONC: return MDC_FRMT_CONC; break; case LIBMDC_ECAT6: return MDC_FRMT_ECAT6; break; case LIBMDC_ECAT7: return MDC_FRMT_ECAT7; break; case LIBMDC_INTF: return MDC_FRMT_INTF; break; case LIBMDC_ANLZ: return MDC_FRMT_ANLZ; break; case LIBMDC_DICM: return MDC_FRMT_DICM; break; case LIBMDC_NIFTI: return MDC_FRMT_NIFTI; break; case LIBMDC_NONE: /* let libmdc guess */ default: return MDC_FRMT_NONE; break; } } gboolean libmdc_supports(const libmdc_format_t format) { return FrmtSupported[libmdc_format_number(format)]; } static gint libmdc_type_number(const AmitkFormat format) { switch(format) { case AMITK_FORMAT_UBYTE: return BIT8_U; break; case AMITK_FORMAT_SBYTE: return BIT8_S; break; case AMITK_FORMAT_USHORT: return BIT16_U; break; case AMITK_FORMAT_SSHORT: return BIT16_S; break; case AMITK_FORMAT_UINT: return BIT32_U; break; case AMITK_FORMAT_SINT: return BIT32_S; break; case AMITK_FORMAT_FLOAT: return FLT32; break; case AMITK_FORMAT_DOUBLE: return FLT64; break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); return 0; break; } } AmitkDataSet * libmdc_import(const gchar * filename, const libmdc_format_t libmdc_format, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { FILEINFO libmdc_fi; gboolean libmdc_fi_init=FALSE; gint error; struct tm time_structure; AmitkVoxel i; gint j; guint64 k; AmitkDataSet * ds=NULL; gchar * name; gchar * import_filename=NULL; gchar ** frags=NULL; AmitkVoxel dim; AmitkFormat format; AmitkModality modality; div_t x; gint divider; gint total_planes; gboolean continue_work=TRUE; gboolean invalid_date; gchar * temp_string; gint image_num; gboolean salvage = FALSE; gchar * msg; gint num_corrupted_planes = 0; const gchar * bad_char; gsize invalid_point; gchar * saved_time_locale; gchar * saved_numeric_locale; gboolean use_pixdim_duration = FALSE; AmitkPoint new_offset; AmitkPoint shift; AmitkAxes new_axes; void * ds_pointer; Uint8 * conv_pointer; gint format_size; gint bytes_per_plane; gint bytes_per_row; gboolean center_data_set = FALSE; saved_time_locale = g_strdup(setlocale(LC_TIME,NULL)); saved_numeric_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_TIME,"POSIX"); setlocale(LC_NUMERIC,"POSIX"); /* setup some defaults */ MDC_INFO=MDC_NO; /* don't print stuff */ MDC_VERBOSE=MDC_NO; /* and don't print stuff */ MDC_ANLZ_SPM=MDC_YES; /* if analyze format, assume SPM */ libmdc_fi.map = MDC_MAP_GRAY; /*default color map*/ MDC_MAKE_GRAY=MDC_YES; /* these are probably no longer important, as I now don't use MdcReadFile, and MdcPixelFiddle doesn't get invoked */ MDC_QUANTIFY=MDC_YES; /* want quantified data */ MDC_NEGATIVE=MDC_YES; /* allow negative values */ MDC_NORM_OVER_FRAMES = MDC_NO; /* figure out the fallback format */ if (libmdc_supports(libmdc_format)) MDC_FALLBACK_FRMT = libmdc_format_number(libmdc_format); else MDC_FALLBACK_FRMT = MDC_FRMT_NONE; /* mdc needs to be initialised to set the system endiannes */ MdcInit(); /* open the file */ import_filename = g_strdup(filename); /* this gets around the facts that filename is type const */ if ((error = MdcOpenFile(&libmdc_fi, import_filename)) != MDC_OK) { g_warning(_("Can't open file %s with libmdc/(X)MedCon"),filename); goto error; } libmdc_fi_init=TRUE; /* read the file */ if ((error = MdcLoadFile(&libmdc_fi)) != MDC_OK) { g_warning(_("Can't read file %s with libmdc/(X)MedCon"),filename); goto error; } /* end mdc */ MdcFinish(); /* validate various strings to utf8 */ if (!g_utf8_validate(libmdc_fi.patient_name, -1, &bad_char)) { invalid_point = bad_char-libmdc_fi.patient_name; libmdc_fi.patient_name[invalid_point] = '\0'; } if (!g_utf8_validate(libmdc_fi.patient_id, -1, &bad_char)) { invalid_point = bad_char-libmdc_fi.patient_id; libmdc_fi.patient_id[invalid_point] = '\0'; } if (!g_utf8_validate(libmdc_fi.patient_dob, -1, &bad_char)) { invalid_point = bad_char-libmdc_fi.patient_dob; libmdc_fi.patient_dob[invalid_point] = '\0'; } if (!g_utf8_validate(libmdc_fi.study_id, -1, &bad_char)) { invalid_point = bad_char-libmdc_fi.study_id; libmdc_fi.study_id[invalid_point] = '\0'; } if (!g_utf8_validate(libmdc_fi.patient_sex, -1, &bad_char)) { invalid_point = bad_char-libmdc_fi.patient_sex; libmdc_fi.patient_sex[invalid_point] = '\0'; } if (!g_utf8_validate(libmdc_fi.recon_method, -1, &bad_char)) { invalid_point = bad_char-libmdc_fi.recon_method; libmdc_fi.recon_method[invalid_point] = '\0'; } /* make sure libmdc returned all dim's as >0 */ for (j=0; jvoxel_size.x = libmdc_fi.pixdim[1]; ds->voxel_size.y = libmdc_fi.pixdim[2]; ds->voxel_size.z = libmdc_fi.pixdim[3]; /* double check voxel size z */ if (libmdc_fi.image[0].slice_spacing > 0.0) if (libmdc_fi.image[0].slice_spacing != libmdc_fi.pixdim[3]) { g_warning(_("Pixel z dimension (%5.3f mm) not equal to slice spacing (%5.3f mm) - will use slice spacing for thickness"), libmdc_fi.pixdim[3], libmdc_fi.image[0].slice_spacing); ds->voxel_size.z = libmdc_fi.image[0].slice_spacing; } if (EQUAL_ZERO(ds->voxel_size.x)) { g_warning(_("Voxel size X was read as 0, setting to 1 mm. This may be an internationalization error.")); ds->voxel_size.x = 1.0; } if (EQUAL_ZERO(ds->voxel_size.y)) { g_warning(_("Voxel size Y was read as 0, setting to 1 mm. This may be an internationalization error.")); ds->voxel_size.y = 1.0; } if (EQUAL_ZERO(ds->voxel_size.z)) { g_warning(_("Voxel size Z was read as 0, setting to 1 mm. This may be an internationalization error.")); ds->voxel_size.z = 1.0; } /* try figuring out the name, start with the study name */ name = NULL; if (strlen(libmdc_fi.study_id) > 0) if (g_ascii_strcasecmp(libmdc_fi.study_id, libmdc_unknown) != 0) name = g_strdup(libmdc_fi.study_id); if (name == NULL) if (strlen(libmdc_fi.patient_name) > 0) if (g_ascii_strcasecmp(libmdc_fi.patient_name, libmdc_unknown) != 0) name = g_strdup(libmdc_fi.patient_name); if (name == NULL) {/* no original filename? */ temp_string = g_path_get_basename(filename); /* remove the extension of the file */ g_strreverse(temp_string); frags = g_strsplit(temp_string, ".", 2); g_free(temp_string); g_strreverse(frags[1]); name = g_strdup(frags[1]); g_strfreev(frags); /* free up now unused strings */ } /* append the reconstruction method */ if (strlen(libmdc_fi.recon_method) > 0) if (g_ascii_strcasecmp(libmdc_fi.recon_method, libmdc_unknown) != 0) { temp_string = name; name = g_strdup_printf("%s - %s", temp_string, libmdc_fi.recon_method); g_free(temp_string); } amitk_object_set_name(AMITK_OBJECT(ds),name); g_free(name); /* enter in the date the scan was performed */ invalid_date = FALSE; time_structure.tm_sec = libmdc_fi.study_time_second; time_structure.tm_min = libmdc_fi.study_time_minute; time_structure.tm_hour = libmdc_fi.study_time_hour; time_structure.tm_mday = libmdc_fi.study_date_day; if (libmdc_fi.study_date_month == 0) { invalid_date = TRUE; time_structure.tm_mon=0; } else time_structure.tm_mon = libmdc_fi.study_date_month-1; if (libmdc_fi.study_date_year == 0) { invalid_date = TRUE; time_structure.tm_year = 0; } else time_structure.tm_year = libmdc_fi.study_date_year-1900; time_structure.tm_isdst = -1; /* "-1" is suppose to let the system figure it out, was "daylight"; */ if ((mktime(&time_structure) == -1) && invalid_date) { /* do any corrections needed on the time */ amitk_data_set_set_scan_date(ds, "Unknown"); /* give up */ } else { amitk_data_set_set_scan_date(ds, asctime(&time_structure)); } /* get the patient orientation */ switch (libmdc_fi.pat_slice_orient) { case MDC_SUPINE_HEADFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST); break; case MDC_SUPINE_FEETFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST); break; case MDC_PRONE_HEADFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST); break; case MDC_PRONE_FEETFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST); break; case MDC_DECUBITUS_RIGHT_HEADFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST); break; case MDC_DECUBITUS_RIGHT_FEETFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST); break; case MDC_DECUBITUS_LEFT_HEADFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST); break; case MDC_DECUBITUS_LEFT_FEETFIRST_TRANSAXIAL: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST); break; default: amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_UNKNOWN); break; } amitk_data_set_set_subject_name(ds, libmdc_fi.patient_name); amitk_data_set_set_subject_id(ds, libmdc_fi.patient_id); amitk_data_set_set_subject_dob(ds, libmdc_fi.patient_dob); /* default sex is unknown */ if ((libmdc_fi.patient_sex[0] == 'M') || (libmdc_fi.patient_sex[0] == 'm')) amitk_data_set_set_subject_sex(ds, AMITK_SUBJECT_SEX_MALE); else if ((libmdc_fi.patient_sex[0] == 'F') || (libmdc_fi.patient_sex[0] == 'f')) amitk_data_set_set_subject_sex(ds, AMITK_SUBJECT_SEX_FEMALE); /* guess the start of the scan is the same as the start of the first frame of data */ /* note, libmdc specifies time as integers in msecs */ /* note, libmdc only uses dyndata if there's more than one frame of data, if there's only 1 frame, dyndata is NULL! */ if (libmdc_fi.dyndata != NULL) ds->scan_start = libmdc_fi.dyndata[0].time_frame_start/1000.0; else if (libmdc_fi.image[0].sdata != NULL) ds->scan_start = 0.0; else if ((libmdc_fi.iformat == MDC_FRMT_ANLZ) && (!EQUAL_ZERO(libmdc_fi.pixdim[4]/1000.0))) { /* analyze files sometimes have duration in pixdim[4] */ use_pixdim_duration = TRUE; ds->scan_start = 0.0; } else { g_warning(_("(X)MedCon returned no duration information. Frame durations will be incorrect")); ds->scan_start = 0.0; } new_axes[AMITK_AXIS_X] = base_axes[AMITK_AXIS_X]; new_axes[AMITK_AXIS_Y] = base_axes[AMITK_AXIS_Y]; new_axes[AMITK_AXIS_Z] = base_axes[AMITK_AXIS_Z]; new_offset = zero_point; /* figure out the image orientation, below code added in version 1.0.3 */ /* Note, XMedCon is suppose to be like DICOM, it uses a right-handed space, that is LPH+: meaning x increases towards patient left, y increases toward patient posterior, and z increases toward patient head. In terms of how it stores data in memory though, it's actually LPF+. AMIDE uses a right-handed space that is LAF+ in both space and memory */ /* in practice, xmedcon seems to be inconsistent between different file types.... hence the logic below. */ switch (libmdc_fi.iformat) { case MDC_FRMT_DICM: if (((fabs(libmdc_fi.image[0].image_orient_pat[0]) + fabs(libmdc_fi.image[0].image_orient_pat[1]) + fabs(libmdc_fi.image[0].image_orient_pat[2])) > 0.9) && ((fabs(libmdc_fi.image[0].image_orient_pat[3]) + fabs(libmdc_fi.image[0].image_orient_pat[4]) + fabs(libmdc_fi.image[0].image_orient_pat[5])) > 0.9)) { new_axes[AMITK_AXIS_X].x = libmdc_fi.image[0].image_orient_pat[0]; new_axes[AMITK_AXIS_X].y = libmdc_fi.image[0].image_orient_pat[1]; new_axes[AMITK_AXIS_X].z = libmdc_fi.image[0].image_orient_pat[2]; new_axes[AMITK_AXIS_Y].x = libmdc_fi.image[0].image_orient_pat[3]; new_axes[AMITK_AXIS_Y].y = libmdc_fi.image[0].image_orient_pat[4]; new_axes[AMITK_AXIS_Y].z = libmdc_fi.image[0].image_orient_pat[5]; } /* Can skip these two lines, as we flip data manually when loading */ new_axes[AMITK_AXIS_X].y *= -1.0; new_axes[AMITK_AXIS_X].z *= -1.0; new_axes[AMITK_AXIS_Y].y *= 1.0; new_axes[AMITK_AXIS_Y].z *= 1.0; POINT_CROSS_PRODUCT(new_axes[AMITK_AXIS_X], new_axes[AMITK_AXIS_Y], new_axes[AMITK_AXIS_Z]); new_offset.x = libmdc_fi.image[0].image_pos_pat[0]; new_offset.y = -1.0 * libmdc_fi.image[0].image_pos_pat[1]; new_offset.z = -1.0 * libmdc_fi.image[0].image_pos_pat[2]; /* figure out the shift, as we're switching the y-axis */ { AmitkSpace * temp_space; temp_space = amitk_space_new(); amitk_space_set_axes(temp_space, new_axes, zero_point); shift.x= 0; shift.y = dim.y * ds->voxel_size.y; shift.z = dim.z * ds->voxel_size.z; shift = amitk_space_s2b(temp_space, shift); POINT_SUB(new_offset, shift, new_offset); temp_space = amitk_object_unref(temp_space); } break; case MDC_FRMT_ECAT6: case MDC_FRMT_ECAT7: if (((fabs(libmdc_fi.image[0].image_orient_dev[0]) + fabs(libmdc_fi.image[0].image_orient_dev[1]) + fabs(libmdc_fi.image[0].image_orient_dev[2])) > 0.9) && ((fabs(libmdc_fi.image[0].image_orient_dev[3]) + fabs(libmdc_fi.image[0].image_orient_dev[4]) + fabs(libmdc_fi.image[0].image_orient_dev[5])) > 0.9)) { new_axes[AMITK_AXIS_X].x = libmdc_fi.image[0].image_orient_dev[0]; new_axes[AMITK_AXIS_X].y = libmdc_fi.image[0].image_orient_dev[1]; new_axes[AMITK_AXIS_X].z = libmdc_fi.image[0].image_orient_dev[2]; new_axes[AMITK_AXIS_Y].x = libmdc_fi.image[0].image_orient_dev[3]; new_axes[AMITK_AXIS_Y].y = libmdc_fi.image[0].image_orient_dev[4]; new_axes[AMITK_AXIS_Y].z = libmdc_fi.image[0].image_orient_dev[5]; } POINT_CROSS_PRODUCT(new_axes[AMITK_AXIS_X], new_axes[AMITK_AXIS_Y], new_axes[AMITK_AXIS_Z]); /* the offset data seems to be garbage, at least on the test data sets I have, just center the data set */ center_data_set = TRUE; /* new_offset.x = libmdc_fi.image[0].image_pos_dev[0]; new_offset.y = libmdc_fi.image[0].image_pos_dev[1]; new_offset.z = libmdc_fi.image[0].image_pos_dev[2]; */ break; case MDC_FRMT_NIFTI: /* no idea whether this is right, but keeps compatibile with what was done prior to 1.0.3 */ new_axes[AMITK_AXIS_X].x *= -1.0; new_axes[AMITK_AXIS_X].y *= -1.0; new_axes[AMITK_AXIS_X].z *= -1.0; new_axes[AMITK_AXIS_Y].x *= -1.0; new_axes[AMITK_AXIS_Y].y *= -1.0; new_axes[AMITK_AXIS_Y].z *= -1.0; new_axes[AMITK_AXIS_Z].x *= -1.0; new_axes[AMITK_AXIS_Z].y *= -1.0; new_axes[AMITK_AXIS_Z].z *= -1.0; center_data_set = TRUE; break; case MDC_FRMT_CONC: /* libmdc concorde support doesn't currently import offset/rotation info */ default: /* all other formats, consistent with what was done prior to 1.0.3 */ /* don't try to read in offset/rotation info */ center_data_set = TRUE; break; } amitk_space_set_axes(AMITK_SPACE(ds), new_axes, zero_point); amitk_space_set_offset(AMITK_SPACE(ds), new_offset); #ifdef AMIDE_DEBUG g_print("\tscan start time %5.3f\n",ds->scan_start); #endif if (update_func != NULL) { temp_string = g_strdup_printf(_("Importing File Through (X)MedCon:\n %s"), filename); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = dim.z*dim.g*dim.t; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); /* and load in the data */ i = zero_voxel; for (i.t = 0; (i.t < dim.t) && (continue_work); i.t++) { #ifdef AMIDE_DEBUG g_print("\tloading frame %d",i.t); #endif /* set the frame duration, note, medcon/libMDC specifies time as float in msecs */ if (libmdc_fi.dyndata != NULL) amitk_data_set_set_frame_duration(ds, i.t, libmdc_fi.dyndata[i.t].time_frame_duration/1000.0); else if (libmdc_fi.image[0].sdata != NULL) amitk_data_set_set_frame_duration(ds, i.t, libmdc_fi.image[0].sdata->image_duration/1000.0); else if (use_pixdim_duration) amitk_data_set_set_frame_duration(ds, i.t, libmdc_fi.pixdim[4]/1000.0); else amitk_data_set_set_frame_duration(ds, i.t, 1.0); /* make sure it's not zero */ if (amitk_data_set_get_frame_duration(ds,i.t) < EPSILON) amitk_data_set_set_frame_duration(ds,i.t, EPSILON); for (i.g = 0; (i.g < ds->raw_data->dim.g) && (continue_work); i.g++) { /* copy the data into the data set */ for (i.z = 0 ; (i.z < ds->raw_data->dim.z) && (continue_work); i.z++) { /* note, libmdc is gates->frames->planes, we're frames->gates->planes */ image_num = i.z+i.t*dim.z+i.g*dim.z*dim.t; if (update_func != NULL) { x = div(image_num,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } /* read in the raw plane data if needed */ if (libmdc_fi.image[image_num].buf == NULL) { if ((error = MdcLoadPlane(&libmdc_fi, image_num)) != MDC_OK) { g_warning(_("Couldn't read plane %d in %s with libmdc/(X)MedCon"),image_num, filename); goto error; } } /* store the scaling factor... I think this is the right scaling factor... */ /* also needs to adjust, most formats libmdc reads are are y = m*x+b. amide, however, is y = m * (x+b); */ if (salvage) *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, i) = 1.0; else { *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_factor, i) = libmdc_fi.image[image_num].quant_scale* libmdc_fi.image[image_num].calibr_fctr; *AMITK_RAW_DATA_DOUBLE_2D_SCALING_POINTER(ds->internal_scaling_intercept,i) = libmdc_fi.image[image_num].intercept/ (libmdc_fi.image[image_num].quant_scale* libmdc_fi.image[image_num].calibr_fctr); } /* sanity check */ if (libmdc_fi.image[image_num].buf == NULL) { num_corrupted_planes++; } else { /* handle endian issues */ switch(ds->raw_data->format) { case AMITK_FORMAT_SBYTE: case AMITK_FORMAT_UBYTE: break; case AMITK_FORMAT_SSHORT: case AMITK_FORMAT_USHORT: if (MdcDoSwap()) for (k=0; k < bytes_per_plane; k+=2) MdcSwapBytes(libmdc_fi.image[image_num].buf+k, 2); break; case AMITK_FORMAT_SINT: case AMITK_FORMAT_UINT: case AMITK_FORMAT_FLOAT: if (MdcDoSwap()) for (k=0; k < bytes_per_plane; k+=4) MdcSwapBytes(libmdc_fi.image[image_num].buf+k, 4); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); goto error; break; } if (salvage) { /* convert the image to a 32 bit float to begin with */ if ((conv_pointer = MdcGetImgFLT32(&libmdc_fi, image_num)) == NULL){ g_warning(_("(X)MedCon couldn't convert to a float... out of memory?")); goto error; } } else { conv_pointer = libmdc_fi.image[image_num].buf; } /* flip as (X)MedCon stores data from anterior to posterior (top to bottom) */ for (i.y=0; i.y < dim.y; i.y++) { ds_pointer = amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), i); memcpy(ds_pointer, conv_pointer+bytes_per_row*(dim.y-i.y-1), format_size*ds->raw_data->dim.x); } /* free up the buffer data */ if (salvage) g_free(conv_pointer); MdcFree(libmdc_fi.image[image_num].buf); } /* .buf != NULL */ } /* i.z */ } #ifdef AMIDE_DEBUG g_print("\tduration %5.3f\n", amitk_data_set_get_frame_duration(ds, i.t)); #endif } /* i.t */ if (num_corrupted_planes > 0) g_warning(_("(X)MedCon returned %d blank planes... corrupted data file? Use data with caution."), num_corrupted_planes); /* setup remaining parameters */ amitk_data_set_set_injected_dose(ds, libmdc_fi.injected_dose); /* should be in MBq */ amitk_data_set_set_displayed_dose_unit(ds, AMITK_DOSE_UNIT_MEGABECQUEREL); amitk_data_set_set_subject_weight(ds, libmdc_fi.patient_weight); /* should be in Kg */ amitk_data_set_set_displayed_weight_unit(ds, AMITK_WEIGHT_UNIT_KILOGRAM); amitk_data_set_set_scale_factor(ds, 1.0); /* set the external scaling factor */ amitk_data_set_calc_far_corner(ds); /* set the far corner of the volume */ amitk_data_set_calc_min_max(ds, update_func, update_data); if (center_data_set) amitk_volume_set_center(AMITK_VOLUME(ds), zero_point); goto function_end; error: if (ds != NULL) ds = amitk_object_unref(ds); function_end: if (libmdc_fi_init) MdcCleanUpFI(&libmdc_fi); if (import_filename != NULL) g_free(import_filename); if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); setlocale(LC_NUMERIC, saved_time_locale); setlocale(LC_NUMERIC, saved_numeric_locale); g_free(saved_time_locale); g_free(saved_numeric_locale); return ds; } gboolean libmdc_export(AmitkDataSet * ds, const gchar * filename, const libmdc_format_t libmdc_format, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data) { FILEINFO fi; gboolean fi_init=FALSE; IMG_DATA * plane; AmitkVoxel i, j; AmitkVoxel dim; div_t x; gint divider; gint total_planes; gboolean continue_work=TRUE; gint image_num; gint libmdc_format_num; gint bytes_per_row; gint bytes_per_plane; gchar * err_str; /* note, err_str (if used) will point to a const string in libmdc */ gint err_num; void * data_ptr; gchar * temp_string; amide_time_t frame_start, frame_duration; AmitkCanvasPoint pixel_size; AmitkPoint corner; AmitkVolume * output_volume=NULL; AmitkPoint output_start_pt; AmitkDataSet * slice = NULL; AmitkPoint new_offset; gfloat * row_data; gchar * saved_time_locale; gchar * saved_numeric_locale; amide_data_t value; gboolean successful = FALSE; saved_time_locale = g_strdup(setlocale(LC_TIME,NULL)); saved_numeric_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_TIME,"POSIX"); setlocale(LC_NUMERIC,"POSIX"); /* setup some defaults */ MDC_INFO=MDC_NO; /* don't print stuff */ MDC_VERBOSE=MDC_NO; /* and don't print stuff */ MDC_ANLZ_SPM=MDC_YES; /* if analyze format, try using SPM style */ fi.map = MDC_MAP_GRAY; /*default color map*/ MDC_MAKE_GRAY=MDC_YES; MDC_QUANTIFY=MDC_YES; /* want quantified data */ MDC_NEGATIVE=MDC_YES; /* allow negative values */ MDC_PREFIX_DISABLED=MDC_YES; /* don't add on the m000- stuff */ MDC_NORM_OVER_FRAMES=MDC_NO; MDC_FILE_ENDIAN=MDC_HOST_ENDIAN; MDC_FILE_OVERWRITE=MDC_YES; /* figure out the fallback format */ if (libmdc_supports(libmdc_format)) { libmdc_format_num = libmdc_format_number(libmdc_format); } else { g_warning(_("Unsupported export file format: %d\n"), libmdc_format); goto cleanup; } /* mdc needs to be initialised to set the system endiannes */ MdcInit(); /* initialize the fi info structure */ MdcInitFI(&fi, ""); fi_init=TRUE; /* set what we can */ if (AMITK_DATA_SET_SUBJECT_NAME(ds) != NULL) strncpy(fi.patient_name,AMITK_DATA_SET_SUBJECT_NAME(ds), MDC_MAXSTR); if (AMITK_DATA_SET_SUBJECT_ID(ds) != NULL) strncpy(fi.patient_id,AMITK_DATA_SET_SUBJECT_ID(ds), MDC_MAXSTR); if (AMITK_DATA_SET_SUBJECT_DOB(ds) != NULL) strncpy(fi.patient_dob,AMITK_DATA_SET_SUBJECT_DOB(ds), MDC_MAXSTR); strncpy(fi.patient_sex, amitk_subject_sex_get_name(AMITK_DATA_SET_SUBJECT_SEX(ds)), MDC_MAXSTR); fi.injected_dose = AMITK_DATA_SET_INJECTED_DOSE(ds); fi.patient_weight= AMITK_DATA_SET_SUBJECT_WEIGHT(ds); switch(AMITK_DATA_SET_SUBJECT_ORIENTATION(ds)) { case AMITK_SUBJECT_ORIENTATION_SUPINE_HEADFIRST: fi.pat_slice_orient = MDC_SUPINE_HEADFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_SUPINE_FEETFIRST: fi.pat_slice_orient = MDC_SUPINE_FEETFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_PRONE_HEADFIRST: fi.pat_slice_orient = MDC_PRONE_HEADFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_PRONE_FEETFIRST: fi.pat_slice_orient = MDC_PRONE_FEETFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_HEADFIRST: fi.pat_slice_orient = MDC_DECUBITUS_RIGHT_HEADFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_RIGHT_DECUBITUS_FEETFIRST: fi.pat_slice_orient = MDC_DECUBITUS_RIGHT_FEETFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_HEADFIRST: fi.pat_slice_orient = MDC_DECUBITUS_LEFT_HEADFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_LEFT_DECUBITUS_FEETFIRST: fi.pat_slice_orient = MDC_DECUBITUS_LEFT_FEETFIRST_TRANSAXIAL; break; case AMITK_SUBJECT_ORIENTATION_UNKNOWN: default: break; } fi.ifname = g_strdup(filename); fi.iformat = MDC_FRMT_RAW; if (resliced) { fi.type = libmdc_type_number(AMITK_FORMAT_FLOAT); } else { fi.type = libmdc_type_number(AMITK_DATA_SET_FORMAT(ds)); } fi.bits = MdcType2Bits(fi.type); fi.endian = MDC_HOST_ENDIAN; dim = AMITK_DATA_SET_DIM(ds); if (resliced) { if (bounding_box != NULL) output_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(bounding_box))); else output_volume = amitk_volume_new(); if (output_volume == NULL) goto cleanup; if (bounding_box != NULL) { corner = AMITK_VOLUME_CORNER(output_volume); } else { AmitkCorners corners; amitk_volume_get_enclosing_corners(AMITK_VOLUME(ds), AMITK_SPACE(output_volume), corners); corner = point_diff(corners[0], corners[1]); amitk_space_set_offset(AMITK_SPACE(output_volume), amitk_space_s2b(AMITK_SPACE(output_volume), corners[0])); } dim.x = ceil(corner.x/voxel_size.x); dim.y = ceil(corner.y/voxel_size.y); dim.z = ceil(corner.z/voxel_size.z); corner.z = voxel_size.z; amitk_volume_set_corner(output_volume, corner); output_start_pt = AMITK_SPACE_OFFSET(output_volume); #ifdef AMIDE_DEBUG g_print("output dimensions %d %d %d, voxel size %f %f %f\n", dim.x, dim.y, dim.z, voxel_size.x, voxel_size.y, voxel_size.z); #else g_warning(_("dimensions of output data set will be %dx%dx%d, voxel size of %fx%fx%f"), dim.x, dim.y, dim.z, voxel_size.x, voxel_size.y, voxel_size.z); #endif } fi.dim[0]=6; fi.dim[1]=dim.x; fi.dim[2]=dim.y; fi.dim[3]=dim.z; fi.dim[4]=dim.t; fi.dim[5]=dim.g; fi.dim[6]=1; /* no beds */ fi.number = fi.dim[6]*fi.dim[5]*fi.dim[4]*fi.dim[3]; /* total # planes */ fi.pixdim[0]=3; if (resliced) { pixel_size.x = voxel_size.x; pixel_size.y = voxel_size.y; fi.pixdim[1] = voxel_size.x; fi.pixdim[2] = voxel_size.y; fi.pixdim[3] = voxel_size.z; } else { fi.pixdim[1]=AMITK_DATA_SET_VOXEL_SIZE_X(ds); fi.pixdim[2]=AMITK_DATA_SET_VOXEL_SIZE_Y(ds); fi.pixdim[3]=AMITK_DATA_SET_VOXEL_SIZE_Z(ds); } switch (AMITK_DATA_SET_MODALITY(ds)) { case AMITK_MODALITY_PET: fi.modality = M_PT; break; case AMITK_MODALITY_SPECT: fi.modality = M_ST; break; case AMITK_MODALITY_CT: fi.modality = M_CT; break; case AMITK_MODALITY_MRI: fi.modality = M_MR; break; case AMITK_MODALITY_OTHER: default: fi.modality = M_OT; break; } if (dim.t > 1) fi.acquisition_type = MDC_ACQUISITION_DYNAMIC; else fi.acquisition_type = MDC_ACQUISITION_TOMO; if (resliced) { bytes_per_row = dim.x*amitk_raw_format_sizes[AMITK_FORMAT_FLOAT]; } else { bytes_per_row = dim.x*amitk_raw_format_sizes[AMITK_DATA_SET_FORMAT(ds)]; } bytes_per_plane = dim.y*bytes_per_row; /* fill in dynamic data struct */ if (!MdcGetStructDD(&fi,dim.t)) { g_warning(_("couldn't malloc DYNAMIC_DATA structs")); goto cleanup; } if (!MdcGetStructID(&fi,fi.number)) { g_warning(_("couldn't malloc img_data structs")); goto cleanup; } if (update_func != NULL) { temp_string = g_strdup_printf(_("Exporting File Through (X)MedCon:\n %s"), filename); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } total_planes = dim.z*dim.g*dim.t; divider = ((total_planes/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (total_planes/AMITK_UPDATE_DIVIDER); image_num=0; data_ptr = ds->raw_data->data; j = zero_voxel; i = zero_voxel; for (i.t = 0; (i.t < dim.t) && (continue_work); i.t++) { frame_start = amitk_data_set_get_start_time(ds, i.t); frame_duration = amitk_data_set_get_frame_duration(ds, i.t); fi.dyndata[i.t].nr_of_slices = fi.dim[3]; /* medcon's in ms */ fi.dyndata[i.t].time_frame_start = 1000.0*frame_start; fi.dyndata[i.t].time_frame_duration = 1000.0*frame_duration; for (i.g = 0 ; (i.g < dim.g) && (continue_work); i.g++) { if (resliced) /* reset the output slice */ amitk_space_set_offset(AMITK_SPACE(output_volume), output_start_pt); for (i.z = 0 ; (i.z < dim.z) && (continue_work); i.z++) { /* note, libmdc is gates->frames->planes, we're frames->gates->planes */ image_num = i.z+i.t*dim.z+i.g*dim.z*dim.t; if (update_func != NULL) { x = div(image_num,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, ((gdouble) image_num)/((gdouble) total_planes)); } plane = &(fi.image[image_num]); plane->width = fi.dim[1]; plane->height = fi.dim[2]; plane->bits = fi.bits; plane->type = fi.type; plane->pixel_xsize = fi.pixdim[1]; plane->pixel_ysize = fi.pixdim[2]; plane->slice_width = fi.pixdim[3]; plane->slice_spacing = fi.pixdim[3]; if (resliced) { plane->quant_scale = 1.0; plane->intercept = 0.0; } else { plane->quant_scale = AMITK_DATA_SET_SCALE_FACTOR(ds)* amitk_data_set_get_internal_scaling_factor(ds, i); plane->intercept = plane->quant_scale * amitk_data_set_get_scaling_intercept(ds,i); } plane->calibr_fctr = 1.0; if ((plane->buf = MdcGetImgBuffer(bytes_per_plane)) == NULL) { g_warning(_("couldn't alloc %d bytes for plane"), bytes_per_plane); goto cleanup; } if (resliced) { slice = amitk_data_set_get_slice(ds, frame_start, frame_duration, i.g, pixel_size, output_volume); if ((AMITK_DATA_SET_DIM_X(slice) != dim.x) || (AMITK_DATA_SET_DIM_Y(slice) != dim.y)) { g_warning(_("Error in generating resliced data, %dx%d != %dx%d"), AMITK_DATA_SET_DIM_X(slice), AMITK_DATA_SET_DIM_Y(slice), dim.x, dim.y); goto cleanup; } /* advance for next iteration */ new_offset = AMITK_SPACE_OFFSET(output_volume); new_offset.z += voxel_size.z; amitk_space_set_offset(AMITK_SPACE(output_volume), new_offset); } /* ideally, I'd put in the orientation and offset into the exported files... For simplicity sake I'm not doing that at the moment, and just flipping the data on the y-axis manually as below. I'm not sure how consistent (X)Medcon's treatment of the image.image_orient_pat and image_pos_pat parameters is.... and setting these parameters is likely more confusing then it's worth... */ /* flip for (X)MedCon's axis */ for (i.y=0, j.y=0; i.y < dim.y; i.y++, j.y++) { if (resliced) { row_data = (gfloat *) (plane->buf+bytes_per_row*(dim.y-i.y-1)); for (j.x = 0; j.x < dim.x; j.x++) { /* clean - libmdc handles infinities, etc. badly */ value = AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice, j); if (finite(value)) row_data[j.x] = value; else row_data[j.x] = 0.0; } } else { memcpy(plane->buf+bytes_per_row*(dim.y-i.y-1), data_ptr, bytes_per_row); data_ptr += bytes_per_row; } } if (slice != NULL) slice = amitk_object_unref(slice); } /* i.z */ } } /* make sure everything's kosher */ err_str = MdcImagesPixelFiddle(&fi); if (err_str != NULL) { g_warning(_("couldn't pixel fiddle, error: %s"), err_str); goto cleanup; } /* and writeout the file */ err_num = MdcWriteFile(&fi, libmdc_format_num, 0, NULL); if (err_num != MDC_OK) { g_warning(_("couldn't write out file %s, error %d"), fi.ofname, err_num); goto cleanup; } successful = TRUE; /* made it through! */ cleanup: if (fi_init) MdcCleanUpFI(&fi); /* clean up FILEINFO struct */ /* end mdc */ MdcFinish(); if (output_volume != NULL) output_volume = amitk_object_unref(output_volume); if (slice != NULL) slice = amitk_object_unref(slice); if (update_func != NULL) /* remove progress bar */ (*update_func)(update_data, NULL, (gdouble) 2.0); setlocale(LC_NUMERIC, saved_time_locale); setlocale(LC_NUMERIC, saved_numeric_locale); g_free(saved_time_locale); g_free(saved_numeric_locale); return successful; } #endif /* AMIDE_LIBMDC_SUPPORT */ amide-1.0.6/amide-current/src/libmdc_interface.h000066400000000000000000000054721423227705100215610ustar00rootroot00000000000000/* libmdc_interface.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBMDC_SUPPORT #ifndef __LIBMDC_INTERFACE_H__ #define __LIBMDC_INTERFACE_H__ /* includes always needed with this file */ #include "amitk_data_set.h" typedef enum { LIBMDC_NONE, LIBMDC_RAW, LIBMDC_ASCII, LIBMDC_GIF, LIBMDC_ACR, LIBMDC_CONC, LIBMDC_ECAT6, LIBMDC_ECAT7, LIBMDC_INTF, LIBMDC_ANLZ, LIBMDC_DICM, LIBMDC_NIFTI, LIBMDC_NUM_FORMATS } libmdc_format_t; typedef enum { LIBMDC_IMPORT_GUESS, LIBMDC_IMPORT_GIF, LIBMDC_IMPORT_ACR, LIBMDC_IMPORT_CONC, LIBMDC_IMPORT_ECAT6, LIBMDC_IMPORT_ECAT7, LIBMDC_IMPORT_INTF, LIBMDC_IMPORT_ANLZ, LIBMDC_IMPORT_DICM, LIBMDC_IMPORT_NIFTI, LIBMDC_NUM_IMPORT_METHODS } libmdc_import_t; typedef enum { LIBMDC_EXPORT_ACR, LIBMDC_EXPORT_CONC, LIBMDC_EXPORT_ECAT6, LIBMDC_EXPORT_INTF, LIBMDC_EXPORT_ANLZ, LIBMDC_EXPORT_DICM, LIBMDC_EXPORT_NIFTI, LIBMDC_NUM_EXPORT_METHODS } libmdc_export_t; /* external functions */ gboolean libmdc_supports(libmdc_format_t format); AmitkDataSet * libmdc_import(const gchar * filename, const libmdc_format_t libmdc_format, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data); /* voxel_size only used if resliced=TRUE */ /* if bounding_box == NULL, will create its own using the minimal necessary */ gboolean libmdc_export(AmitkDataSet * ds, const gchar * filename, const libmdc_format_t libmdc_format, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data); extern libmdc_format_t libmdc_import_to_format[]; extern gchar * libmdc_import_menu_names[]; extern gchar * libmdc_import_menu_explanations[]; extern libmdc_format_t libmdc_export_to_format[]; extern gchar * libmdc_export_menu_names[]; extern gchar * libmdc_export_menu_explanations[]; #endif /* __LIBMDC_INTERFACE_H__ */ #endif /* AMIDE_LIBMDC_SUPPORT */ amide-1.0.6/amide-current/src/mpeg_encode.c000066400000000000000000000416361423227705100205510ustar00rootroot00000000000000/* mpeg_encode.c - interface to the mpeg encoding library * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" /* shared code */ #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) #include #include #include #include "amide_intl.h" #include "mpeg_encode.h" /* note, this is identifical to fame_yuv_t */ typedef struct __yuv_t_ { unsigned int w, h, p; unsigned char *y; unsigned char *u; unsigned char *v; } yuv_t; #define RGB_TO_Y(pixels, loc) (0.29900 * pixels[loc] + 0.58700 * pixels[loc+1] + 0.11400 * pixels[loc+2]) #define RGB_TO_U(pixels, loc)(-0.16874 * pixels[loc] - 0.33126 * pixels[loc+1] + 0.50000 * pixels[loc+2]+128.0) #define RGB_TO_V(pixels, loc) (0.50000 * pixels[loc] - 0.41869 * pixels[loc+1] - 0.08131 * pixels[loc+2]+128.0) static void convert_rgb_pixbuf_to_yuv(yuv_t * yuv, GdkPixbuf * pixbuf) { gint x, y, location, location2; gint inner_x, inner_y, half_location; gfloat cr, cb; gint pixbuf_xsize, pixbuf_ysize; guchar * pixels; gint row_stride; gboolean x_odd, y_odd; pixbuf_xsize = gdk_pixbuf_get_width(pixbuf); pixbuf_ysize = gdk_pixbuf_get_height(pixbuf); pixels = gdk_pixbuf_get_pixels(pixbuf); row_stride = gdk_pixbuf_get_rowstride(pixbuf); y_odd = (pixbuf_ysize & 0x1); x_odd = (pixbuf_xsize & 0x1); /* note, the Cr and Cb info is subsampled by 2x2 */ for (y=0; yy[inner_x+inner_y*yuv->w] = RGB_TO_Y(pixels, location); cb += RGB_TO_U(pixels, location); cr += RGB_TO_V(pixels, location); } half_location = x/2 + y*yuv->w/4; yuv->u[half_location] = cb/4.0; yuv->v[half_location] = cr/4.0; } if (x_odd) { location = y*row_stride+3*x; location2 = (y+1)*row_stride+3*x; yuv->y[x+y*yuv->w] = RGB_TO_Y(pixels, location); yuv->y[x+1+y*yuv->w] = 0; yuv->y[x+(y+1)*yuv->w] = RGB_TO_Y(pixels, location2); yuv->y[x+1+(y+1)*yuv->w] = 0; half_location = x/2 + y*yuv->w/4; yuv->u[half_location] = (RGB_TO_U(pixels, location)+RGB_TO_U(pixels, location2)+256)/4.0; yuv->v[half_location] = (RGB_TO_V(pixels, location)+RGB_TO_V(pixels, location2)+256)/4.0; } } if (y_odd) { for (x=0; xy[x+y*yuv->w] = RGB_TO_Y(pixels, location); yuv->y[x+1+y*yuv->w] = RGB_TO_Y(pixels, location2); yuv->y[x+(y+1)*yuv->w] = 0; yuv->y[x+1+(y+1)*yuv->w] = 0; half_location = x/2 + y*yuv->w/4; yuv->u[half_location] = (RGB_TO_U(pixels, location)+RGB_TO_U(pixels, location2)+256)/4.0; yuv->v[half_location] = (RGB_TO_V(pixels, location)+RGB_TO_V(pixels, location2)+256)/4.0; } if (x_odd) { location = y*row_stride+3*x; yuv->y[x+y*yuv->w] = RGB_TO_Y(pixels, location); yuv->y[x+1+y*yuv->w] = 0; yuv->y[x+(y+1)*yuv->w] = 0; yuv->y[x+1+(y+1)*yuv->w] = 0; half_location = x/2 + y*yuv->w/4; yuv->u[half_location] = (RGB_TO_U(pixels, location)+384)/4.0; yuv->v[half_location] = (RGB_TO_V(pixels, location)+384)/4.0; } } return; } #endif /* AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT */ /* -------------------------------------------------------- */ /* ---------------------- ffmpeg encoding ----------------- */ /* -------------------------------------------------------- */ #ifdef AMIDE_FFMPEG_SUPPORT #include typedef struct { AVCodec *codec; AVCodecContext *context; AVFrame *picture; yuv_t * yuv; guchar * output_buffer; gint output_buffer_size; gint size; /* output frame width * height */ FILE * output_file; } encode_t; /* free a mpeg_encode encode structure */ static encode_t * encode_free(encode_t * encode) { if (encode == NULL) return encode; if (encode->context != NULL) { avcodec_close(encode->context); av_free(encode->context); encode->context = NULL; } if (encode->picture != NULL) { av_frame_free(&(encode->picture)); encode->picture=NULL; } if (encode->yuv != NULL) { g_free(encode->yuv->y); g_free(encode->yuv); encode->yuv = NULL; } if (encode->output_buffer != NULL) { g_free(encode->output_buffer); encode->output_buffer = NULL; } // if (encode->fame_parameters != NULL) { // g_free(encode->fame_parameters); // encode->fame_parameters = NULL; // } // if (encode->yuv != NULL) { // g_free(encode->yuv->y); // g_free(encode->yuv); // encode->yuv = NULL; // } if (encode->output_file != NULL) { fclose(encode->output_file); encode->output_file = NULL; } g_free(encode); return NULL; } gboolean avcodec_initialized=FALSE; static void mpeg_encoding_init(void) { if (!avcodec_initialized) { /* must be called before using avcodec lib */ avcodec_register_all(); /* register all the codecs */ avcodec_register_all(); avcodec_initialized=TRUE; } } gpointer mpeg_encode_setup(gchar * output_filename, mpeg_encode_t type, gint xsize, gint ysize) { encode_t * encode; gint codec_type; gint i; mpeg_encoding_init(); switch(type) { case ENCODE_MPEG4: codec_type = AV_CODEC_ID_MPEG4; break; case ENCODE_MPEG1: default: codec_type=AV_CODEC_ID_MPEG1VIDEO; break; } /* alloc space for the mpeg_encoding structure */ if ((encode = g_try_new(encode_t,1)) == NULL) { g_warning("couldn't allocate memory space for encode_t"); return NULL; } encode->context=NULL; encode->picture=NULL; encode->yuv=NULL; encode->output_buffer=NULL; encode->output_file=NULL; /* find the mpeg1 video encoder */ encode->codec = avcodec_find_encoder(codec_type); if (!encode->codec) { g_warning("couldn't find codec %d",codec_type); encode_free(encode); return NULL; } encode->context = avcodec_alloc_context3(NULL); if (!encode->context) { g_warning("couldn't allocate memory for encode->context"); encode_free(encode); return NULL; } #if LIBAVCODEC_VERSION_MAJOR >= 55 encode->picture= av_frame_alloc(); #else encode->picture= avcode_alloc_frame(); #endif if (!encode->picture) { g_warning("couldn't allocate memory for encode->picture"); encode_free(encode); return NULL; } /* at a minimum, the width and height need to be even */ /* we'll make them divisible by 16 incase ffmpeg wants to use AltiVec or SSE acceleration */ xsize = 16*ceil(xsize/16.0); ysize = 16*ceil(ysize/16.0); /* put sample parameters */ /* used to use 400000.0*((float) (xsize*ysize)/(352.0*288.0)) but output mpeg was too blocky */ encode->context->bit_rate = 2000000.0*((float) (xsize*ysize)/(352.0*288.0)); encode->context->width = xsize; encode->context->height = ysize; encode->size = encode->context->width*encode->context->height; /* frames per second */ encode->context->time_base= (AVRational){1,FRAMES_PER_SECOND}; encode->context->gop_size = 10; /* emit one intra frame every ten frames */ encode->context->max_b_frames=10; encode->context->pix_fmt = AV_PIX_FMT_YUV420P; /* encoding parameters */ encode->context->sample_aspect_ratio= (AVRational){1,1}; /* our pixels are square */ /* deprecated option... encode->context->me_method=5; *//* 5 is epzs */ encode->context->trellis=2; /* turn trellis quantization on */ /* open it */ if (avcodec_open2(encode->context, encode->codec, NULL) < 0) { g_warning("could not open codec"); encode_free(encode); return NULL; } if ((encode->output_file = fopen(output_filename, "wb")) == NULL) { g_warning("unable to open output file for mpeg encoding"); encode_free(encode); return NULL; } /* alloc image and output buffer */ encode->output_buffer_size = 200000*(xsize*ysize)/(352*288); if (encode->output_buffer_size < 100000) encode->output_buffer_size=100000; if ((encode->output_buffer = g_try_new(guchar,encode->output_buffer_size)) == NULL) { g_warning("couldn't allocate memory space for output_buffer"); encode_free(encode); return NULL; } if ((encode->yuv = g_try_new(yuv_t, 1)) == NULL) { g_warning(_("Unable to allocate yuv struct")); encode_free(encode); return NULL; } encode->yuv->w = xsize; encode->yuv->h = ysize; encode->yuv->p = xsize; /* alloc mem for YUV 420 size (hence the 3/2) */ if ((encode->yuv->y = g_try_new0(guchar, xsize*ysize*3/2)) == NULL) { g_warning(_("Unable to allocate yuv buffer")); encode_free(encode); return NULL; } encode->yuv->u = encode->yuv->y + xsize*ysize; encode->yuv->v = encode->yuv->u + xsize*ysize/4; /* initialize the u and v portions of the yuv buffer, as 0 is not the right initial value, and the portion of the buffer that's larger then the pixbuf's we use will never be written to */ for (i=0; iyuv->u[i] = 128; encode->yuv->v[i] = 128; } encode->picture->data[0] = encode->yuv->y; encode->picture->data[1] = encode->yuv->u; encode->picture->data[2] = encode->yuv->v; encode->picture->linesize[0] = encode->context->width; encode->picture->linesize[1] = encode->context->width/2; encode->picture->linesize[2] = encode->context->width/2; encode->picture->width = encode->context->width; encode->picture->height = encode->context->height; encode->picture->format = AV_PIX_FMT_YUV420P; return (gpointer) encode; } gboolean mpeg_encode_frame(gpointer data, GdkPixbuf * pixbuf) { encode_t * encode = data; // gint out_size; AVPacket pkt = {0}; int ret, got_packet = 0; convert_rgb_pixbuf_to_yuv(encode->yuv, pixbuf); /* encode the image */ // out_size = avcodec_encode_video(encode->context, encode->output_buffer, encode->output_buffer_size, encode->picture); // fwrite(encode->output_buffer, 1, out_size, encode->output_file); // return TRUE; ret = avcodec_encode_video2(encode->context, &pkt, encode->picture, &got_packet); if (ret >= 0 && got_packet) { fwrite(pkt.data, 1, pkt.size, encode->output_file); av_packet_unref(&pkt); } return (ret >= 0) ? TRUE : FALSE; }; /* close everything up */ gpointer mpeg_encode_close(gpointer data) { encode_t * encode = data; /* add sequence end code to have a real mpeg file */ encode->output_buffer[0] = 0x00; encode->output_buffer[1] = 0x00; encode->output_buffer[2] = 0x01; encode->output_buffer[3] = 0xb7; fwrite(encode->output_buffer, 1, 4, encode->output_file); /* free encode struct/close out_file */ encode_free(encode); return NULL; } /* endif AMIDE_FFMPEG_SUPPORT */ /* --------------------------------------------------------------------------------------------------------*/ /* old code */ /* mpeg encoding used to be done using libfame */ /* --------------------------------------------------------------------------------------------------------*/ #elif AMIDE_LIBFAME_SUPPORT #include #define BUFFER_MULT 8 typedef struct { fame_context_t * fame_context; fame_parameters_t * fame_parameters; gint xsize; gint ysize; guchar *buffer; gint buffer_size; /*xsize*ysize*BUFFER_MULT */ yuv_t * yuv; FILE * output_file; } context_t; /* free a mpeg_encode context structure */ static context_t * context_free(context_t * context) { gint length; if (context == NULL) return context; if (context->fame_context != NULL) { length = fame_close(context->fame_context); /* flush anything left */ if ((context->buffer != NULL) && (context->output_file != NULL)) /* and finish writing the file */ fwrite(context->buffer, sizeof(guchar), length, context->output_file); context->fame_context = NULL; } if (context->output_file != NULL) { fclose(context->output_file); context->output_file = NULL; } if (context->fame_parameters != NULL) { g_free(context->fame_parameters); context->fame_parameters = NULL; } if (context->buffer != NULL) { g_free(context->buffer); context->buffer = NULL; } if (context->yuv != NULL) { g_free(context->yuv->y); g_free(context->yuv); context->yuv = NULL; } g_free(context); return NULL; } /* setup the mpeg encoding process */ gpointer mpeg_encode_setup(gchar * output_filename, mpeg_encode_t type, gint xsize, gint ysize) { fame_parameters_t default_fame_parameters = FAME_PARAMETERS_INITIALIZER; context_t * context; fame_object_t *object; int i; /* we need x and y to be divisible by 2 for conversion to YUV12 space */ /* and we need x and y to be divisible by 16 for fame */ xsize = 16*ceil(xsize/16.0); ysize = 16*ceil(ysize/16.0); /* alloc space for the mpeg_encoding structure */ if ((context = g_try_new(context_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for context_t")); return NULL; } context->fame_context = NULL; context->fame_parameters = NULL; context->buffer = NULL; context->output_file = NULL; context->xsize = xsize; context->ysize = ysize; context->buffer_size = xsize*ysize*BUFFER_MULT; /* needs to be able to hold a couple frames */ if ((context->fame_parameters = g_try_new(fame_parameters_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for fame parameters")); context_free(context); return NULL; } memcpy(context->fame_parameters, &default_fame_parameters, sizeof(fame_parameters_t)); if ((context->buffer = g_try_new(guchar, context->buffer_size)) == NULL) { g_warning(_("Unable to allocate memory space for mpeg encoding buffer")); context_free(context); return NULL; } if ((context->yuv = g_try_new(yuv_t, 1)) == NULL) { g_warning(_("Unable to allocate yuv struct")); context_free(context); return NULL; } context->yuv->w = xsize; context->yuv->h = ysize; context->yuv->p = xsize; if ((context->yuv->y = g_try_new(unsigned char, xsize*ysize*3/2)) == NULL) { g_warning(_("Unable to allocate yuv buffer")); context_free(context); return NULL; } context->yuv->u = context->yuv->y + xsize*ysize; context->yuv->v = context->yuv->u + xsize*ysize/4; /* initialize yuv buffer, as the portion of the buffer that's large then the pixbuf's we use is never used*/ for (i=0; iyuv->y[i] = 0; for (i=0; iyuv->u[i] = 128; context->yuv->v[i] = 128; } if ((context->output_file = fopen(output_filename, "wb")) == NULL) { g_warning(_("unable to open output file for mpeg encoding")); context_free(context); return NULL; } context->fame_context = fame_open(); /* initalize library */ /* specify any parameters we want to change from default */ context->fame_parameters->width = xsize; context->fame_parameters->height = ysize; context->fame_parameters->frame_rate_num = FRAMES_PER_SECOND; context->fame_parameters->frame_rate_den = 1; context->fame_parameters->verbose = 0; /* turn off verbose mode */ /* specify additional options */ switch(type) { case ENCODE_MPEG4: object = fame_get_object(context->fame_context, "profile/mpeg4"); break; case ENCODE_MPEG1: default: object = fame_get_object(context->fame_context, "profile/mpeg1"); break; } fame_register(context->fame_context, "profile", object); fame_init(context->fame_context, context->fame_parameters, context->buffer, context->buffer_size); return (gpointer) context; } /* encode a frame of data */ gboolean mpeg_encode_frame(gpointer data, GdkPixbuf * pixbuf) { context_t * context = data; gint length; g_return_val_if_fail(gdk_pixbuf_get_colorspace(pixbuf) == GDK_COLORSPACE_RGB, FALSE); convert_rgb_pixbuf_to_yuv(context->yuv, pixbuf); fame_start_frame(context->fame_context, context->yuv, NULL); while((length = fame_encode_slice(context->fame_context)) != 0) fwrite(context->buffer, sizeof(guchar), length, context->output_file); fame_end_frame(context->fame_context, NULL); return TRUE; } /* close everything up */ gpointer mpeg_encode_close(gpointer data) { context_t * context = data; context_free(context); /* free context */ return NULL; } #endif /* AMIDE_LIBFAME_SUPPORT */ amide-1.0.6/amide-current/src/mpeg_encode.h000066400000000000000000000030251423227705100205440ustar00rootroot00000000000000/* mpeg_encode.c - interface to the mpeg encoding library * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) #ifndef __MPEG_ENCODE_H__ #define __MPEG_ENCODE_H__ /* header files that are always associated with this header file */ #include #define FRAMES_PER_SECOND 30 typedef enum { ENCODE_MPEG1, ENCODE_MPEG4 } mpeg_encode_t; /* functions */ gpointer mpeg_encode_setup(gchar * output_filename, mpeg_encode_t type, gint xsize, gint ysize); gboolean mpeg_encode_frame(gpointer mpeg_encode_context, GdkPixbuf * pixbuf); gpointer mpeg_encode_close(gpointer mpeg_encode_context); #endif /* __MPEG_ENCODE_H__ */ #endif /* AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT */ amide-1.0.6/amide-current/src/pixmaps.c000066400000000000000000000147201423227705100177570ustar00rootroot00000000000000/* pixmaps.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amitk_data_set.h" #include "amitk_study.h" #include "../pixmaps/amide_logo.h" #include "../pixmaps/interpolation_nearest_neighbor.h" #include "../pixmaps/interpolation_trilinear.h" #include "../pixmaps/transfer_function.h" #include "../pixmaps/fuse_type_blend.h" #include "../pixmaps/fuse_type_overlay.h" #include "../pixmaps/target.h" #include "../pixmaps/view_transverse.h" #include "../pixmaps/view_coronal.h" #include "../pixmaps/view_sagittal.h" #include "../pixmaps/view_single.h" #include "../pixmaps/view_linked.h" #include "../pixmaps/view_linked3.h" #include "../pixmaps/thresholding.h" #include "../pixmaps/thresholding_per_slice.h" #include "../pixmaps/thresholding_per_frame.h" #include "../pixmaps/thresholding_interpolate_frames.h" #include "../pixmaps/thresholding_global.h" #include "../pixmaps/threshold_style_min_max.h" #include "../pixmaps/threshold_style_center_width.h" /* #include "../pixmaps/window_bone_icon.h" */ /* #include "../pixmaps/window_soft_tissue_icon.h" */ #include "../pixmaps/window_abdomen.h" #include "../pixmaps/window_brain.h" #include "../pixmaps/window_extremities.h" #include "../pixmaps/window_liver.h" #include "../pixmaps/window_lung.h" #include "../pixmaps/window_pelvis_soft_tissue.h" #include "../pixmaps/window_skull_base.h" #include "../pixmaps/window_spine_a.h" #include "../pixmaps/window_spine_b.h" #include "../pixmaps/window_thorax_soft_tissue.h" #include "../pixmaps/roi_box.h" #include "../pixmaps/roi_cylinder.h" #include "../pixmaps/roi_ellipsoid.h" #include "../pixmaps/roi_isocontour_2d.h" #include "../pixmaps/roi_isocontour_3d.h" #include "../pixmaps/roi_freehand_2d.h" #include "../pixmaps/roi_freehand_3d.h" #include "../pixmaps/align_pt.h" #include "../pixmaps/study.h" #include "../pixmaps/layout_linear.h" #include "../pixmaps/layout_orthogonal.h" #include "../pixmaps/panels_mixed.h" #include "../pixmaps/panels_linear_x.h" #include "../pixmaps/panels_linear_y.h" static gboolean icons_initialized=FALSE; static struct { const guint8 * pixbuf_inline; const gchar * icon_id; } amide_icons[] = { { amide_logo, "amide_icon_logo" }, { align_pt, "amide_icon_align_pt" }, { fuse_type_blend, "amide_icon_fuse_type_blend" }, { fuse_type_overlay, "amide_icon_fuse_type_overlay" }, { interpolation_nearest_neighbor, "amide_icon_interpolation_nearest_neighbor" }, { interpolation_trilinear, "amide_icon_interpolation_trilinear" }, { layout_linear, "amide_icon_layout_linear" }, { layout_orthogonal, "amide_icon_layout_orthogonal" }, { panels_mixed, "amide_icon_panels_mixed" }, { panels_linear_x, "amide_icon_panels_linear_x" }, { panels_linear_y, "amide_icon_panels_linear_y" }, { roi_box, "amide_icon_roi_box" }, { roi_cylinder, "amide_icon_roi_cylinder" }, { roi_ellipsoid, "amide_icon_roi_ellipsoid" }, { roi_isocontour_2d, "amide_icon_roi_isocontour_2d"}, { roi_isocontour_3d, "amide_icon_roi_isocontour_3d"}, { roi_freehand_2d, "amide_icon_roi_freehand_2d"}, { roi_freehand_3d, "amide_icon_roi_freehand_3d"}, { study, "amide_icon_study"}, { target, "amide_icon_canvas_target" }, { transfer_function, "amide_icon_transfer_function" }, { threshold_style_min_max, "amide_icon_threshold_style_min_max" }, { threshold_style_center_width, "amide_icon_threshold_style_center_width" }, { thresholding, "amide_icon_thresholding" }, { thresholding_per_slice, "amide_icon_thresholding_per_slice" }, { thresholding_per_frame, "amide_icon_thresholding_per_frame" }, { thresholding_interpolate_frames, "amide_icon_thresholding_interpolate_frames" }, { thresholding_global, "amide_icon_thresholding_global" }, { view_transverse, "amide_icon_view_transverse" }, { view_coronal, "amide_icon_view_coronal" }, { view_sagittal, "amide_icon_view_sagittal" }, { view_single, "amide_icon_view_mode_single" }, { view_linked, "amide_icon_view_mode_linked_2way" }, { view_linked3, "amide_icon_view_mode_linked_3way" }, { window_abdomen, "amide_icon_window_abdomen" }, { window_brain, "amide_icon_window_brain" }, { window_extremities,"amide_icon_window_extremities" }, { window_liver,"amide_icon_window_window_liver" }, { window_lung,"amide_icon_window_lung" }, { window_pelvis_soft_tissue,"amide_icon_window_pelvis_soft_tissue" }, { window_skull_base,"amide_icon_window_skull_base"}, { window_spine_a,"amide_icon_window_spine_a"}, { window_spine_b,"amide_icon_window_spine_b"}, { window_thorax_soft_tissue,"amide_icon_window_soft_tissue"}, }; const gchar * windowing_icons[AMITK_WINDOW_NUM] = { "amide_icon_window_abdomen", "amide_icon_window_brain", "amide_icon_window_extremities", "amide_icon_window_window_liver", "amide_icon_window_lung", "amide_icon_window_pelvis_soft_tissue", "amide_icon_window_skull_base", "amide_icon_window_spine_a", "amide_icon_window_spine_b", "amide_icon_window_soft_tissue", }; // amide_icon_window_bone, // amide_icon_window_soft_tissue_icon void pixmaps_initialize_icons() { GtkIconFactory *icon_factory; GtkIconSet *icon_set; GdkPixbuf * pixbuf; gint i; if (icons_initialized) return; /* create amide's group of icons */ icon_factory = gtk_icon_factory_new(); for (i=0; i < G_N_ELEMENTS(amide_icons); i++) { pixbuf = gdk_pixbuf_new_from_inline(-1, amide_icons[i].pixbuf_inline, FALSE, NULL); icon_set = gtk_icon_set_new_from_pixbuf(pixbuf); g_object_unref(pixbuf); gtk_icon_factory_add (icon_factory, amide_icons[i].icon_id, icon_set); gtk_icon_set_unref (icon_set); } /* add this group of icon's to the list of icon's GTK will search for AMIDE */ gtk_icon_factory_add_default (icon_factory); g_object_unref (icon_factory); icons_initialized=TRUE; return; } amide-1.0.6/amide-current/src/pixmaps.h000066400000000000000000000017461423227705100177700ustar00rootroot00000000000000/* pixmaps.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* header files that are always needed with this file */ extern const gchar * windowing_icons[]; void pixmaps_initialize_icons(); amide-1.0.6/amide-current/src/raw_data_import.c000066400000000000000000000563631423227705100214630ustar00rootroot00000000000000/* raw_data_import.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include "amide.h" #include "amide_gconf.h" #include "amitk_common.h" #include "raw_data_import.h" #include "amitk_progress_dialog.h" #define GCONF_AMIDE_RAWDATAIMPORT "RAWDATAIMPORT" /* raw_data information structure */ typedef struct raw_data_info_t { gchar * filename; gchar * name; gsize total_file_size; AmitkRawFormat raw_format; AmitkVoxel data_dim; AmitkPoint voxel_size; AmitkModality modality; amide_data_t scale_factor; guint offset; GtkWidget * num_bytes_label1; GtkWidget * num_bytes_label2; GtkWidget * read_offset_label; GtkWidget * ok_button; } raw_data_info_t; static void change_name_cb(GtkWidget * widget, gpointer data); static void change_scaling_cb(GtkWidget * widget, gpointer data); static void change_entry_cb(GtkWidget * widget, gpointer data); static void change_modality_cb(GtkWidget * widget, gpointer data); static void change_raw_format_cb(GtkWidget * widget, gpointer data); static guint update_num_bytes(raw_data_info_t * raw_data_info); static void read_last_values(AmitkModality * plast_modality, AmitkRawFormat * plast_raw_format, AmitkVoxel * plast_data_dim, AmitkPoint * plast_voxel_size, guint * plast_offset, amide_data_t *plast_scale_factor); static GtkWidget * import_dialog(raw_data_info_t * raw_data_info); static void update_offset_label(raw_data_info_t * raw_data_info); /* function called when the name of the data set has been changed */ static void change_name_cb(GtkWidget * widget, gpointer data) { raw_data_info_t * raw_data_info = data; gchar * new_name; /* get the contents of the name entry box and save it */ new_name = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); g_free(raw_data_info->name); raw_data_info->name = new_name; return; } /* function called to change the scaling factor */ static void change_scaling_cb(GtkWidget * widget, gpointer data) { gchar * str; gint error; gdouble temp_real; raw_data_info_t * raw_data_info = data; /* get the contents of the name entry box */ str = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); /* convert to the correct number */ error = sscanf(str, "%lf", &temp_real); if (error == EOF) return; /* make sure it's a valid number */ g_free(str); /* and save the value */ raw_data_info->scale_factor = temp_real; amide_gconf_set_float(GCONF_AMIDE_RAWDATAIMPORT,"LastScaleFactor", raw_data_info->scale_factor); return; } /* function called when a numerical entry of the data set has been changed, used for the dimensions and voxel_size */ static void change_entry_cb(GtkWidget * widget, gpointer data) { gchar * str; gint error; gdouble temp_real=0.0; gint temp_int=0; guint which_widget; raw_data_info_t * raw_data_info = data; /* figure out which widget this is */ which_widget = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "type")); /* get the contents of the name entry box */ str = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); /* convert to the correct number */ if ((which_widget < AMITK_DIM_NUM) || (which_widget == AMITK_DIM_NUM+AMITK_AXIS_NUM)) { error = sscanf(str, "%d", &temp_int); if (error == EOF) return; /* make sure it's a valid number */ if (temp_int < 0) return; } else { /* one of the voxel_size widgets */ error = sscanf(str, "%lf", &temp_real); if (error == EOF) /* make sure it's a valid number */ return; if (temp_real < 0.0) return; } g_free(str); /* and save the value in our temporary data set structure */ switch(which_widget) { case AMITK_DIM_X: raw_data_info->data_dim.x = temp_int; break; case AMITK_DIM_Y: raw_data_info->data_dim.y = temp_int; break; case AMITK_DIM_Z: raw_data_info->data_dim.z = temp_int; break; case AMITK_DIM_G: raw_data_info->data_dim.g = temp_int; break; case AMITK_DIM_T: raw_data_info->data_dim.t = temp_int; break; case (AMITK_DIM_NUM+AMITK_AXIS_X): raw_data_info->voxel_size.x = temp_real; break; case (AMITK_DIM_NUM+AMITK_AXIS_Y): raw_data_info->voxel_size.y = temp_real; break; case (AMITK_DIM_NUM+AMITK_AXIS_Z): raw_data_info->voxel_size.z = temp_real; break; case (AMITK_DIM_NUM+AMITK_AXIS_NUM): raw_data_info->offset = temp_int; break; default: break; /* do nothing */ } /* recalculate the total number of bytes to be read and have it displayed */ update_num_bytes(raw_data_info); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimG", raw_data_info->data_dim.g); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimT", raw_data_info->data_dim.t); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimZ", raw_data_info->data_dim.z); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimY", raw_data_info->data_dim.y); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimX", raw_data_info->data_dim.x); amide_gconf_set_float(GCONF_AMIDE_RAWDATAIMPORT,"LastVoxelSizeZ", raw_data_info->voxel_size.z); amide_gconf_set_float(GCONF_AMIDE_RAWDATAIMPORT,"LastVoxelSizeY", raw_data_info->voxel_size.y); amide_gconf_set_float(GCONF_AMIDE_RAWDATAIMPORT,"LastVoxelSizeX", raw_data_info->voxel_size.x); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastOffset", raw_data_info->offset); return; } /* function to change the modality */ static void change_modality_cb(GtkWidget * widget, gpointer data) { raw_data_info_t * raw_data_info = data; raw_data_info->modality = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastModality", raw_data_info->modality); return; } /* function to change the raw data file's data format */ static void change_raw_format_cb(GtkWidget * widget, gpointer data) { raw_data_info_t * raw_data_info = data; raw_data_info->raw_format = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); /* recalculate the total number of bytes to be read and have it displayed*/ update_num_bytes(raw_data_info); /* update the offset label so it makes sense */ update_offset_label(raw_data_info); amide_gconf_set_int(GCONF_AMIDE_RAWDATAIMPORT,"LastRawFormat", raw_data_info->raw_format); return; } /* reset the label for the offset entry */ static void update_offset_label(raw_data_info_t * raw_data_info) { if (raw_data_info->raw_format == AMITK_RAW_FORMAT_ASCII_8_NE) gtk_label_set_text(GTK_LABEL(raw_data_info->read_offset_label), _("read offset (entries):")); else gtk_label_set_text(GTK_LABEL(raw_data_info->read_offset_label), _("read offset (bytes):")); } /* calculate the total amount of the file that will be read through */ static guint update_num_bytes(raw_data_info_t * raw_data_info) { gsize num_bytes; guint num_entries; gchar * temp_string; /* how many bytes we're currently reading from the file */ if (raw_data_info->raw_format == AMITK_RAW_FORMAT_ASCII_8_NE) { num_entries = raw_data_info->offset + raw_data_info->data_dim.x*raw_data_info->data_dim.y*raw_data_info->data_dim.z*raw_data_info->data_dim.g*raw_data_info->data_dim.t; gtk_label_set_text(GTK_LABEL(raw_data_info->num_bytes_label1), _("total entries to read through:")); temp_string = g_strdup_printf("%d",num_entries); gtk_label_set_text(GTK_LABEL(raw_data_info->num_bytes_label2), temp_string); g_free(temp_string); /* and figure out a bare minimum for how many bytes might be in the file, this would correspond to all single digit numbers, seperated by spaces */ num_bytes = 2*num_entries; } else { num_bytes = raw_data_info->offset + amitk_raw_format_calc_num_bytes(raw_data_info->data_dim, raw_data_info->raw_format); gtk_label_set_text(GTK_LABEL(raw_data_info->num_bytes_label1), _("total bytes to read through:")); temp_string = g_strdup_printf("%lu",num_bytes); gtk_label_set_text(GTK_LABEL(raw_data_info->num_bytes_label2), temp_string); g_free(temp_string); } /* if we think we can load in the file, desensitise the "ok" button */ gtk_widget_set_sensitive(raw_data_info->ok_button, (num_bytes <= raw_data_info->total_file_size) && (num_bytes > 0)); return num_bytes; } static void read_last_values(AmitkModality * plast_modality, AmitkRawFormat * plast_raw_format, AmitkVoxel * plast_data_dim, AmitkPoint * plast_voxel_size, guint * plast_offset, amide_data_t *plast_scale_factor) { gint temp_int; gfloat temp_float; *plast_modality = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastModality"); *plast_raw_format = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastRawFormat"); temp_int = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimG"); (*plast_data_dim).g = (temp_int == 0) ? 1 : temp_int; temp_int = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimT"); (*plast_data_dim).t = (temp_int == 0) ? 1 : temp_int; temp_int = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimZ"); (*plast_data_dim).z = (temp_int == 0) ? 1 : temp_int; temp_int = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimY"); (*plast_data_dim).y = (temp_int == 0) ? 1 : temp_int; temp_int = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastDataDimX"); (*plast_data_dim).x = (temp_int == 0) ? 1 : temp_int; temp_float = amide_gconf_get_float(GCONF_AMIDE_RAWDATAIMPORT,"LastVoxelSizeZ"); (*plast_voxel_size).z = EQUAL_ZERO(temp_float) ? 1.0 : temp_float; temp_float = amide_gconf_get_float(GCONF_AMIDE_RAWDATAIMPORT,"LastVoxelSizeY"); (*plast_voxel_size).y = EQUAL_ZERO(temp_float) ? 1.0 : temp_float; temp_float = amide_gconf_get_float(GCONF_AMIDE_RAWDATAIMPORT,"LastVoxelSizeX"); (*plast_voxel_size).x = EQUAL_ZERO(temp_float) ? 1.0 : temp_float; *plast_offset = amide_gconf_get_int(GCONF_AMIDE_RAWDATAIMPORT,"LastOffset"); temp_float = amide_gconf_get_float(GCONF_AMIDE_RAWDATAIMPORT,"LastScaleFactor"); *plast_scale_factor = EQUAL_ZERO(temp_float) ? 1.0 : temp_float; return; } /* function to bring up the dialog widget to direct our importing of raw data */ static GtkWidget * import_dialog(raw_data_info_t * raw_data_info) { AmitkModality i_modality; AmitkDim i_dim; AmitkRawFormat i_raw_format; AmitkAxis i_axis; gchar * temp_string = NULL; gchar ** frags; GtkWidget * dialog; GtkWidget * packing_table; GtkWidget * label; GtkWidget * entry; GtkWidget * menu; guint table_row = 0; /* start making the import dialog */ dialog = gtk_dialog_new(); temp_string = g_strdup_printf(_("%s: Raw Data Import Dialog\n"), PACKAGE); gtk_window_set_title(GTK_WINDOW(dialog), temp_string); g_free(temp_string); raw_data_info->ok_button = gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_YES); gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE); /* make the packing table */ packing_table = gtk_table_new(10,6,FALSE); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),packing_table); /* widgets to change the roi's name */ label = gtk_label_new(_("name:")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 0,1, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); /* figure out an initial name for the data */ temp_string = g_path_get_basename(raw_data_info->filename); /* remove the extension of the file */ g_strreverse(temp_string); frags = g_strsplit(temp_string, ".", 2); g_free(temp_string); if (frags[1] != NULL) raw_data_info->name = strdup(frags[1]); else /* no extension on filename */ raw_data_info->name = strdup(frags[0]); g_strfreev(frags); g_strreverse(raw_data_info->name); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), raw_data_info->name); gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(change_name_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(entry),1,3, table_row, table_row+1, GTK_FILL | GTK_EXPAND, 0, X_PADDING, Y_PADDING); table_row++; /* widgets to change the object's modality */ label = gtk_label_new(_("modality:")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 0,1, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_modality=0; i_modalitymodality); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(change_modality_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(menu), 1,3, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* widgets to change the raw data file's data format */ label = gtk_label_new(_("data format:")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 0,1, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_raw_format=0; i_raw_formatraw_format); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(change_raw_format_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(menu), 1,3, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); /* how many bytes we can read from the file */ label = gtk_label_new(_("file size (bytes):")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 3,5, table_row, table_row+1, GTK_FILL | GTK_EXPAND, 0, X_PADDING, Y_PADDING); /* how many bytes we're currently reading from the file */ temp_string = g_strdup_printf("%lu", raw_data_info->total_file_size); label = gtk_label_new(temp_string); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); g_free(temp_string); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 5,6, table_row, table_row+1, GTK_FILL | GTK_EXPAND, 0, X_PADDING, Y_PADDING); table_row++; /* what offset in the raw_data file we should start reading at */ raw_data_info->read_offset_label = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(raw_data_info->read_offset_label), 1.0, 0.5); update_offset_label(raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(raw_data_info->read_offset_label), 0,1, table_row, table_row+1, GTK_FILL | GTK_EXPAND, 0, X_PADDING, Y_PADDING); entry = gtk_entry_new(); temp_string = g_strdup_printf("%d", raw_data_info->offset); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); g_object_set_data(G_OBJECT(entry), "type", GINT_TO_POINTER(AMITK_DIM_NUM+AMITK_AXIS_NUM)); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(change_entry_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(entry),1,3, table_row, table_row+1, GTK_FILL | GTK_EXPAND, 0, X_PADDING, Y_PADDING); /* how many bytes we're currently reading from the file */ raw_data_info->num_bytes_label1 = gtk_label_new(""); raw_data_info->num_bytes_label2 = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(raw_data_info->num_bytes_label1), 1.0, 0.5); gtk_misc_set_alignment(GTK_MISC(raw_data_info->num_bytes_label2), 0.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(raw_data_info->num_bytes_label1), 3,5, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(raw_data_info->num_bytes_label2), 5,6, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); update_num_bytes(raw_data_info); /* put something sensible into the label */ table_row++; /* labels for the x, y, and z components */ label = gtk_label_new(_("x")); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("y")); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("z")); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("gates")); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 4,5, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("frames")); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 5,6, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); table_row++; /* widgets to change the dimensions of the data set */ label = gtk_label_new(_("dimensions (# voxels)")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 0,1, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); for (i_dim=0; i_dimdata_dim, i_dim)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); g_object_set_data(G_OBJECT(entry), "type", GINT_TO_POINTER(i_dim)); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(change_entry_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(entry),i_dim+1,i_dim+2, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); } table_row++; /* widgets to change the voxel size of the data set */ label = gtk_label_new(_("voxel size (mm)")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 0,1, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); for (i_axis=0; i_axisvoxel_size, i_axis)); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); g_object_set_data(G_OBJECT(entry), "type", GINT_TO_POINTER(i_axis+AMITK_DIM_NUM)); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(change_entry_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(entry),i_axis+1,i_axis+2, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); } table_row++; /* scale factor to apply to the data */ label = gtk_label_new(_("scale factor")); gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(label), 0,1, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); entry = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(entry), 12); temp_string = g_strdup_printf("%5.3f", raw_data_info->scale_factor); gtk_entry_set_text(GTK_ENTRY(entry), temp_string); g_free(temp_string); gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(change_scaling_cb), raw_data_info); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(entry),1,2, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); table_row++; gtk_widget_show_all(dialog); return dialog; } /* function to bring up the dialog widget to direct our importing of raw data */ AmitkDataSet * raw_data_import(const gchar * raw_data_filename, AmitkPreferences * preferences) { struct stat file_info; raw_data_info_t * raw_data_info; AmitkDataSet * ds; gint dialog_reply; GtkWidget * dialog; GtkWidget * progress_dialog = NULL; gboolean return_val; /* get space for our raw_data_info structure */ if ((raw_data_info = g_try_new(raw_data_info_t,1)) == NULL) { g_warning(_("Couldn't allocate memory space for raw_data_info structure for raw data import")); return NULL; } /* initialize */ raw_data_info->filename = g_strdup(raw_data_filename); read_last_values(&(raw_data_info->modality), &(raw_data_info->raw_format), &(raw_data_info->data_dim), &(raw_data_info->voxel_size), &(raw_data_info->offset), &(raw_data_info->scale_factor)); /* figure out the file size in bytes (file_info.st_size) */ if (stat(raw_data_info->filename, &file_info) != 0) { g_warning(_("Couldn't get stat's on file %s for raw data import"), raw_data_info->filename); g_free(raw_data_info); return NULL; } raw_data_info->total_file_size = file_info.st_size; /* create the import_dialog */ dialog = import_dialog(raw_data_info); /* block till the user closes the dialog */ dialog_reply = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); /* and start loading in the file if we hit ok*/ if (dialog_reply == GTK_RESPONSE_YES) { /* the progress dialog */ progress_dialog = amitk_progress_dialog_new(NULL); ds = amitk_data_set_import_raw_file(raw_data_info->filename, raw_data_info->raw_format, raw_data_info->data_dim, raw_data_info->offset, preferences, raw_data_info->modality, raw_data_info->name, raw_data_info->voxel_size, raw_data_info->scale_factor, amitk_progress_dialog_update, progress_dialog); } else /* we hit the cancel button */ ds = NULL; if (progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(progress_dialog), "delete_event", NULL, &return_val); progress_dialog = NULL; } if (raw_data_info->filename != NULL) { g_free(raw_data_info->filename); raw_data_info->filename = NULL; } if (raw_data_info->name != NULL) { g_free(raw_data_info->name); raw_data_info->name = NULL; } if (raw_data_info != NULL) { g_free(raw_data_info); raw_data_info = NULL; } return ds; /* NULL if we hit cancel */ } amide-1.0.6/amide-current/src/raw_data_import.h000066400000000000000000000020711423227705100214530ustar00rootroot00000000000000/* raw_data_import.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* header files that are always needed with this file */ #include "amitk_data_set.h" /* external functions */ AmitkDataSet * raw_data_import(const gchar * filename, AmitkPreferences * preferences); amide-1.0.6/amide-current/src/render.c000066400000000000000000001344661423227705100175670ustar00rootroot00000000000000/* rendering.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBVOLPACK_SUPPORT #include #include #include "render.h" #include "amitk_roi.h" #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include #include #ifdef AMIDE_DEBUG #include #endif /* external variables */ gchar * rendering_quality_names[] = { N_("Highest Quality and Slowest"), N_("High Quality and Medium Speed"), N_("Medium Quality and Fast"), N_("Low Quality and Fastest") }; gchar * pixel_type_names[] = { N_("Opacity"), N_("Grayscale") }; rendering_voxel_t * dummy_voxel; rendering_t * rendering_unref(rendering_t * rendering) { classification_t i_class; if (rendering== NULL) return rendering; /* sanity checks */ g_return_val_if_fail(rendering->ref_count > 0, NULL); rendering->ref_count--; #ifdef AMIDE_DEBUG if (rendering->ref_count == 0) g_print("freeing rendering context of %s\n",rendering->name); #endif /* if we've removed all reference's, free the context */ if (rendering->ref_count == 0) { if (rendering->object != NULL) { amitk_object_unref(rendering->object); rendering->object = NULL; } if (rendering->rendering_data != NULL) { g_free(rendering->rendering_data); rendering->rendering_data = NULL; } if (rendering->name != NULL) { g_free(rendering->name); rendering->name = NULL; } if (rendering->vpc != NULL) { vpDestroyContext(rendering->vpc); rendering->vpc = NULL; } if (rendering->image != NULL) { g_free(rendering->image); rendering->image = NULL; } for (i_class = 0; i_class < NUM_CLASSIFICATIONS; i_class++) { g_free(rendering->ramp_x[i_class]); g_free(rendering->ramp_y[i_class]); } if (rendering->transformed_volume != NULL) { amitk_object_unref(rendering->transformed_volume); rendering->transformed_volume = NULL; } if (rendering->extraction_volume != NULL) { amitk_object_unref(rendering->extraction_volume); rendering->extraction_volume = NULL; } g_free(rendering); rendering = NULL; } return rendering; } /* either volume or object must be NULL */ rendering_t * rendering_init(const AmitkObject * object, AmitkVolume * rendering_volume, const amide_real_t voxel_size, const amide_time_t start, const amide_time_t duration, const gboolean zero_fill, const gboolean optimize_rendering, const gboolean no_gradient_opacity, AmitkUpdateFunc update_func, gpointer update_data) { rendering_t * new_rendering = NULL; gint i; gint init_density_ramp_x[] = RENDERING_DENSITY_RAMP_X; gfloat init_density_ramp_y[] = RENDERING_DENSITY_RAMP_Y; gint init_gradient_ramp_x[] = RENDERING_GRADIENT_RAMP_X; gfloat init_gradient_ramp_y[] = RENDERING_GRADIENT_RAMP_Y; gfloat init_gradient_ramp_y_flat[] = RENDERING_GRADIENT_RAMP_Y_FLAT; if (!(AMITK_IS_DATA_SET(object) || AMITK_IS_ROI(object))) return NULL; if ((new_rendering = g_try_new(rendering_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for rendering context")); return NULL; } new_rendering->ref_count = 1; new_rendering->need_rerender = TRUE; new_rendering->need_reclassify = TRUE; /* start initializing what we can */ new_rendering->vpc = vpCreateContext(); new_rendering->object = amitk_object_copy(object); new_rendering->name = g_strdup(AMITK_OBJECT_NAME(object)); if (AMITK_IS_DATA_SET(object)) new_rendering->color_table = AMITK_DATA_SET_COLOR_TABLE(object, AMITK_VIEW_MODE_SINGLE); else new_rendering->color_table = AMITK_COLOR_TABLE_BW_LINEAR; if (no_gradient_opacity) new_rendering->pixel_type = OPACITY; else new_rendering->pixel_type = RENDERING_DEFAULT_PIXEL_TYPE; new_rendering->image = NULL; new_rendering->rendering_data = NULL; new_rendering->curve_type[DENSITY_CLASSIFICATION] = CURVE_LINEAR; new_rendering->curve_type[GRADIENT_CLASSIFICATION] = CURVE_LINEAR; new_rendering->transformed_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(rendering_volume))); new_rendering->extraction_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(rendering_volume))); new_rendering->start = start; new_rendering->duration = duration; if (AMITK_IS_DATA_SET(object)) new_rendering->view_start_gate = AMITK_DATA_SET_VIEW_START_GATE(object); else new_rendering->view_start_gate = 0; if (AMITK_IS_DATA_SET(object)) new_rendering->view_end_gate = AMITK_DATA_SET_VIEW_END_GATE(object); else new_rendering->view_end_gate = 0; new_rendering->zero_fill = zero_fill; new_rendering->optimize_rendering = optimize_rendering; /* figure out the size of our context */ new_rendering->dim.x = ceil((AMITK_VOLUME_X_CORNER(rendering_volume))/voxel_size); new_rendering->dim.y = ceil((AMITK_VOLUME_Y_CORNER(rendering_volume))/voxel_size); new_rendering->dim.z = ceil((AMITK_VOLUME_Z_CORNER(rendering_volume))/voxel_size); new_rendering->dim.g = 1; new_rendering->dim.t = 1; new_rendering->voxel_size = voxel_size; /* adjust the thresholding if needed */ if (AMITK_IS_DATA_SET(new_rendering->object)) if (AMITK_DATA_SET_THRESHOLDING(new_rendering->object) == AMITK_THRESHOLDING_PER_SLICE) { amitk_data_set_set_thresholding(AMITK_DATA_SET(new_rendering->object), AMITK_THRESHOLDING_GLOBAL); g_warning(_("\"Per Slice\" thresholding illogical for conversion to volume rendering, using \"Global\" thresholding ")); } #if AMIDE_DEBUG g_print("\tSetting up a Rendering Context\n"); #endif /* setup the density and gradient ramps */ new_rendering->num_points[DENSITY_CLASSIFICATION] = RENDERING_DENSITY_RAMP_POINTS; if ((new_rendering->ramp_x[DENSITY_CLASSIFICATION] = g_try_new(gint, new_rendering->num_points[DENSITY_CLASSIFICATION])) == NULL) { g_warning(_("couldn't allocate memory space for density ramp x")); return NULL; } if ((new_rendering->ramp_y[DENSITY_CLASSIFICATION] = g_try_new(gfloat,new_rendering->num_points[DENSITY_CLASSIFICATION])) == NULL) { g_warning(_("couldn't allocate memory space for density ramp y")); return NULL; } for (i=0;inum_points[DENSITY_CLASSIFICATION];i++) { new_rendering->ramp_x[DENSITY_CLASSIFICATION][i] = init_density_ramp_x[i]; new_rendering->ramp_y[DENSITY_CLASSIFICATION][i] = init_density_ramp_y[i]; } new_rendering->num_points[GRADIENT_CLASSIFICATION] = RENDERING_GRADIENT_RAMP_POINTS; if ((new_rendering->ramp_x[GRADIENT_CLASSIFICATION] = g_try_new(gint,new_rendering->num_points[GRADIENT_CLASSIFICATION])) == NULL) { g_warning(_("couldn't allocate memory space for gradient ramp x")); return NULL; } if ((new_rendering->ramp_y[GRADIENT_CLASSIFICATION] = g_try_new(gfloat,new_rendering->num_points[GRADIENT_CLASSIFICATION])) == NULL) { g_warning(_("couldn't allocate memory space for gradient ramp y")); return NULL; } for (i=0;inum_points[GRADIENT_CLASSIFICATION];i++) { new_rendering->ramp_x[GRADIENT_CLASSIFICATION][i] = init_gradient_ramp_x[i]; if (no_gradient_opacity) new_rendering->ramp_y[GRADIENT_CLASSIFICATION][i] = init_gradient_ramp_y_flat[i]; else new_rendering->ramp_y[GRADIENT_CLASSIFICATION][i] = init_gradient_ramp_y[i]; } /* setup the context's classification function */ if (vpRamp(new_rendering->density_ramp, sizeof(gfloat), new_rendering->num_points[DENSITY_CLASSIFICATION], new_rendering->ramp_x[DENSITY_CLASSIFICATION], new_rendering->ramp_y[DENSITY_CLASSIFICATION]) != VP_OK){ g_warning(_("Error Setting the Rendering Density Ramp")); new_rendering = rendering_unref(new_rendering); return new_rendering; } /* setup the context's gradient classification */ if (vpRamp(new_rendering->gradient_ramp, sizeof(gfloat), new_rendering->num_points[GRADIENT_CLASSIFICATION], new_rendering->ramp_x[GRADIENT_CLASSIFICATION], new_rendering->ramp_y[GRADIENT_CLASSIFICATION]) != VP_OK) { g_warning(_("Error Setting the Rendering Gradient Ramp")); new_rendering = rendering_unref(new_rendering); return new_rendering; } /* tell the rendering context info on the voxel structure */ if (vpSetVoxelSize(new_rendering->vpc, RENDERING_BYTES_PER_VOXEL, RENDERING_VOXEL_FIELDS, RENDERING_SHADE_FIELDS, RENDERING_CLSFY_FIELDS) != VP_OK) { g_warning(_("Error Setting the Rendering Voxel Size (%s): %s"), new_rendering->name, vpGetErrorString(vpGetError(new_rendering->vpc))); new_rendering = rendering_unref(new_rendering); return new_rendering; } /* now tell the rendering context the location of each field in voxel, do this for each field in the context */ if (vpSetVoxelField (new_rendering->vpc,RENDERING_NORMAL_FIELD, RENDERING_NORMAL_SIZE, RENDERING_NORMAL_OFFSET, RENDERING_NORMAL_MAX) != VP_OK) { g_warning(_("Error Specifying the Rendering Voxel Fields (%s, NORMAL): %s"), new_rendering->name, vpGetErrorString(vpGetError(new_rendering->vpc))); new_rendering = rendering_unref(new_rendering); return new_rendering; } if (vpSetVoxelField (new_rendering->vpc,RENDERING_DENSITY_FIELD, RENDERING_DENSITY_SIZE, RENDERING_DENSITY_OFFSET, RENDERING_DENSITY_MAX) != VP_OK) { g_warning(_("Error Specifying the Rendering Voxel Fields (%s, DENSITY): %s"), new_rendering->name, vpGetErrorString(vpGetError(new_rendering->vpc))); new_rendering = rendering_unref(new_rendering); return new_rendering; } if (vpSetVoxelField (new_rendering->vpc,RENDERING_GRADIENT_FIELD, RENDERING_GRADIENT_SIZE, RENDERING_GRADIENT_OFFSET, RENDERING_GRADIENT_MAX) != VP_OK) { g_warning(_("Error Specifying the Rendering Voxel Fields (%s, GRADIENT): %s"), new_rendering->name, vpGetErrorString(vpGetError(new_rendering->vpc))); new_rendering = rendering_unref(new_rendering); return new_rendering; } /* apply density classification to the vpc */ if (vpSetClassifierTable(new_rendering->vpc, RENDERING_DENSITY_PARAM, RENDERING_DENSITY_FIELD, new_rendering->density_ramp, sizeof(new_rendering->density_ramp)) != VP_OK){ g_warning(_("Error Setting the Rendering Classifier Table (%s, DENSITY): %s"), new_rendering->name, vpGetErrorString(vpGetError(new_rendering->vpc))); new_rendering = rendering_unref(new_rendering); return new_rendering; } /* apply it to the different vpc's */ if (vpSetClassifierTable(new_rendering->vpc, RENDERING_GRADIENT_PARAM, RENDERING_GRADIENT_FIELD, new_rendering->gradient_ramp, sizeof(new_rendering->gradient_ramp)) != VP_OK){ g_warning(_("Error Setting the Classifier Table (%s, GRADIENT): %s"), new_rendering->name, vpGetErrorString(vpGetError(new_rendering->vpc))); new_rendering = rendering_unref(new_rendering); return new_rendering; } /* now copy the object data into the rendering context */ if (rendering_load_object(new_rendering, update_func, update_data) != TRUE) { new_rendering = rendering_unref(new_rendering); return new_rendering; } /* and finally, set up the structure into which the rendering will be returned */ rendering_set_image(new_rendering, new_rendering->pixel_type, RENDERING_DEFAULT_ZOOM); return new_rendering; } /* function to reload the rendering context's concept of an object when necessary */ gboolean rendering_reload_object(rendering_t * rendering, const amide_time_t new_start, const amide_time_t new_duration, AmitkUpdateFunc update_func, gpointer update_data) { amide_time_t old_start, old_duration; guint frame; old_start = rendering->start; old_duration = rendering->duration; rendering->start = new_start; rendering->duration = new_duration; /* only need to do stuff for dynamic data sets */ if (!AMITK_IS_DATA_SET(rendering->object)) return TRUE; if (!(AMITK_DATA_SET_DYNAMIC(rendering->object) || AMITK_DATA_SET_GATED(rendering->object))) return TRUE; // changed as of 0.8.12 -- delete when sure everything works // if (amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), new_start) == // amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), old_start)) // if (amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), new_start+new_duration) == // amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), old_start+old_duration)) frame = amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), new_start); /* if we're completely inside one frame, or we haven't changed time */ if (((frame == amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), old_start)) && (frame == amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), new_start+new_duration)) && (frame == amitk_data_set_get_frame(AMITK_DATA_SET(rendering->object), old_start+old_duration))) || (REAL_EQUAL(new_start, old_start) && REAL_EQUAL(new_duration, old_duration))) if (AMITK_DATA_SET_VIEW_START_GATE(rendering->object) == rendering->view_start_gate) if (AMITK_DATA_SET_VIEW_END_GATE(rendering->object) == rendering->view_end_gate) return TRUE; rendering->view_start_gate = AMITK_DATA_SET_VIEW_START_GATE(rendering->object); rendering->view_end_gate = AMITK_DATA_SET_VIEW_END_GATE(rendering->object); /* allright, reload the rendering context's data */ rendering->need_rerender = TRUE; rendering->need_reclassify = TRUE; return rendering_load_object(rendering, update_func, update_data); } /* function to update the rendering structure's concept of the object */ gboolean rendering_load_object(rendering_t * rendering, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel i_voxel, j_voxel; rendering_density_t * density; /* buffer for density data */ guint density_size;/* size of density data */ guint context_size;/* size of context */ div_t x; gint divider; gchar * temp_string; gboolean continue_work=TRUE; #ifdef AMIDE_DEBUG struct timeval tv1; struct timeval tv2; gdouble time1; gdouble time2; /* let's do some timing */ gettimeofday(&tv1, NULL); #endif /* tell the volpack context the dimensions of our rendering context */ if (vpSetVolumeSize(rendering->vpc, rendering->dim.x, rendering->dim.y, rendering->dim.z) != VP_OK) { g_warning(_("Error Setting the Context Size (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } /* allocate space for the raw data and the context */ density_size = rendering->dim.x * rendering->dim.y * rendering->dim.z * RENDERING_DENSITY_SIZE; context_size = rendering->dim.x * rendering->dim.y * rendering->dim.z * RENDERING_BYTES_PER_VOXEL; if ((density = (rendering_density_t * ) g_try_malloc0(density_size)) == NULL) { g_warning(_("Could not allocate memory space for density data for %s"), rendering->name); return FALSE; } if (rendering->rendering_data != NULL) { g_free(rendering->rendering_data); rendering->rendering_data = NULL; } if ((rendering->rendering_data = (rendering_voxel_t * ) g_try_malloc(context_size)) == NULL) { g_warning(_("Could not allocate memory space for rendering context volume for %s"), rendering->name); g_free(density); return FALSE; } vpSetRawVoxels(rendering->vpc, rendering->rendering_data, context_size, RENDERING_BYTES_PER_VOXEL, rendering->dim.x * RENDERING_BYTES_PER_VOXEL, rendering->dim.x* rendering->dim.y * RENDERING_BYTES_PER_VOXEL); /* setup the progress information */ if (update_func != NULL) { temp_string = g_strdup_printf(_("Converting for rendering: %s"), rendering->name); continue_work = (*update_func)(update_data, temp_string, (gdouble) 0.0); g_free(temp_string); } divider = ((rendering->dim.z/AMITK_UPDATE_DIVIDER) < 1) ? 1 : (rendering->dim.z/AMITK_UPDATE_DIVIDER); if (AMITK_IS_ROI(rendering->object)) { AmitkPoint center, radius; amide_real_t height; AmitkPoint temp_point; AmitkPoint box_corner; gint temp_int; AmitkVoxel start, end; AmitkCorners intersection_corners; AmitkPoint voxel_size; voxel_size.x = voxel_size.y = voxel_size.z = rendering->voxel_size; radius = point_cmult(0.5, AMITK_VOLUME_CORNER(rendering->object)); center = amitk_space_b2s(AMITK_SPACE(rendering->object), amitk_volume_get_center(AMITK_VOLUME(rendering->object))); height = AMITK_VOLUME_Z_CORNER(rendering->object); box_corner = AMITK_VOLUME_CORNER(rendering->object); j_voxel.t = j_voxel.g = j_voxel.z = i_voxel.t= i_voxel.g = 0; /* figure out the intersection between the rendering volume and the roi */ if (!amitk_volume_volume_intersection_corners(rendering->extraction_volume, AMITK_VOLUME(rendering->object), intersection_corners)) { start = end = zero_voxel; } else { // intersection_corners[1] = point_cmult(1.0-EPSILON, intersection_corners[1]); POINT_TO_VOXEL(intersection_corners[0], voxel_size, 0, 0, start); POINT_TO_VOXEL(intersection_corners[1], voxel_size, 1, 1, end); end = voxel_sub(end, one_voxel); } g_return_val_if_fail(end.x < rendering->dim.x, FALSE); g_return_val_if_fail(end.y < rendering->dim.y, FALSE); g_return_val_if_fail(end.z < rendering->dim.z, FALSE); for (i_voxel.z = start.z; (i_voxel.z <= end.z) && (continue_work); i_voxel.z++) { if (update_func != NULL) { x = div(i_voxel.z,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, (gdouble) i_voxel.z/(end.z-start.z)); } for (i_voxel.y = start.y; i_voxel.y <= end.y; i_voxel.y++) for (i_voxel.x = start.x; i_voxel.x <= end.x; i_voxel.x++) { VOXEL_TO_POINT(i_voxel, voxel_size, temp_point); temp_point = amitk_space_s2s(AMITK_SPACE(rendering->extraction_volume), AMITK_SPACE(rendering->object),temp_point); switch(AMITK_ROI_TYPE(rendering->object)) { case AMITK_ROI_TYPE_ISOCONTOUR_2D: case AMITK_ROI_TYPE_ISOCONTOUR_3D: case AMITK_ROI_TYPE_FREEHAND_2D: case AMITK_ROI_TYPE_FREEHAND_3D: POINT_TO_VOXEL(temp_point, AMITK_ROI(rendering->object)->voxel_size, 0, 0, j_voxel); if (amitk_raw_data_includes_voxel(AMITK_ROI(rendering->object)->map_data, j_voxel)) { temp_int = *AMITK_RAW_DATA_UBYTE_POINTER(AMITK_ROI(rendering->object)->map_data, j_voxel); if (temp_int == 2) temp_int = RENDERING_DENSITY_MAX; else if (temp_int == 1) temp_int = RENDERING_DENSITY_MAX/2.0; } else temp_int = 0; break; case AMITK_ROI_TYPE_ELLIPSOID: if (point_in_ellipsoid(temp_point, center, radius)) temp_int = RENDERING_DENSITY_MAX; else temp_int = 0; break; case AMITK_ROI_TYPE_BOX: if (point_in_box(temp_point, box_corner)) temp_int = RENDERING_DENSITY_MAX; else temp_int = 0; break; case AMITK_ROI_TYPE_CYLINDER: if (point_in_elliptic_cylinder(temp_point, center, height, radius)) temp_int = RENDERING_DENSITY_MAX; else temp_int = 0; break; default: temp_int=0; g_assert(TRUE); /* assert if we ever get here */ break; } /* note, volpack needs a mirror reversal on the z axis */ density[i_voxel.x + i_voxel.y*rendering->dim.x+ (rendering->dim.z-i_voxel.z-1)*rendering->dim.y*rendering->dim.x] = temp_int; } } } else { /* DATA SET */ AmitkVolume * slice_volume; AmitkDataSet * slice; AmitkPoint new_offset; AmitkPoint temp_corner; amide_data_t temp_val, scale; amide_data_t max, min; AmitkVoxel dim; gboolean unmatched_dimensions = FALSE; AmitkCanvasPoint pixel_size; slice_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(rendering->extraction_volume))); /* define the slice that we're trying to pull out of the data set */ temp_corner = AMITK_VOLUME_CORNER(slice_volume); temp_corner.z = rendering->voxel_size; amitk_volume_set_corner(slice_volume, temp_corner); new_offset = zero_point; /* in slice_volume space */ new_offset.z = rendering->voxel_size; /* copy the info from a data set structure into our rendering_volume structure */ j_voxel.t = j_voxel.g = j_voxel.z = i_voxel.t= i_voxel.g = 0; for (i_voxel.z = 0; ((i_voxel.z < rendering->dim.z) && continue_work); i_voxel.z++) { if (update_func != 0) { x = div(i_voxel.z,divider); if (x.rem == 0) continue_work = (*update_func)(update_data, NULL, (gdouble) i_voxel.z/rendering->dim.z); } pixel_size.x = pixel_size.y = rendering->voxel_size; slice = amitk_data_set_get_slice(AMITK_DATA_SET(rendering->object), rendering->start, rendering->duration, -1, pixel_size, slice_volume); if (!unmatched_dimensions && ((rendering->dim.x != AMITK_DATA_SET_DIM_X(slice)) || (rendering->dim.y != AMITK_DATA_SET_DIM_Y(slice)))) { g_warning("unmatched dimensions between rendering and slices (%dx%d != %dx%d) in %s\n", rendering->dim.x, rendering->dim.y, AMITK_DATA_SET_DIM_X(slice), AMITK_DATA_SET_DIM_Y(slice), __FILE__); unmatched_dimensions = TRUE; } dim.x = MIN(rendering->dim.x, AMITK_DATA_SET_DIM_X(slice)); dim.y = MIN(rendering->dim.y, AMITK_DATA_SET_DIM_Y(slice)); amitk_data_set_get_thresholding_min_max(AMITK_DATA_SET_SLICE_PARENT(slice), AMITK_DATA_SET(slice), rendering->start, rendering->duration, &min, &max); scale = ((amide_data_t) RENDERING_DENSITY_MAX) / (max-min); /* note, volpack needs a mirror reversal on the z axis */ if (rendering->zero_fill) { for (j_voxel.y = i_voxel.y = 0; i_voxel.y < dim.y; j_voxel.y++, i_voxel.y++) for (j_voxel.x = i_voxel.x = 0; i_voxel.x < dim.x; j_voxel.x++, i_voxel.x++) { temp_val = scale * (AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice,j_voxel)-min); if (temp_val > RENDERING_DENSITY_MAX) temp_val = 0.0; if (temp_val < 0.0) temp_val = 0.0; density[i_voxel.x+ i_voxel.y*rendering->dim.x+ (rendering->dim.z-i_voxel.z-1)* rendering->dim.y* rendering->dim.x] = temp_val; } } else { for (j_voxel.y = i_voxel.y = 0; i_voxel.y < dim.y; j_voxel.y++, i_voxel.y++) for (j_voxel.x = i_voxel.x = 0; i_voxel.x < dim.x; j_voxel.x++, i_voxel.x++) { temp_val = scale * (AMITK_DATA_SET_DOUBLE_0D_SCALING_CONTENT(slice,j_voxel)-min); if (temp_val > RENDERING_DENSITY_MAX) temp_val = RENDERING_DENSITY_MAX; if (temp_val < 0.0) temp_val = 0.0; density[i_voxel.x+ i_voxel.y*rendering->dim.x+ (rendering->dim.z-i_voxel.z-1)* rendering->dim.y* rendering->dim.x] = temp_val; } } amitk_object_unref(slice); /* advance the requested slice volume for next iteration */ amitk_space_set_offset(AMITK_SPACE(slice_volume), amitk_space_s2b(AMITK_SPACE(slice_volume), new_offset)); } amitk_object_unref(slice_volume); } /* if we quit, get out of here */ if (update_func != NULL) continue_work = (*update_func)(update_data, NULL, (gdouble) 2.0); /* remove progress bar */ if (!continue_work) { g_free(density); return FALSE; } /* compute surface normals (for shading) and gradient magnitudes (for classification) */ if (vpVolumeNormals(rendering->vpc, density, density_size, RENDERING_DENSITY_FIELD, RENDERING_GRADIENT_FIELD, RENDERING_NORMAL_FIELD) != VP_OK) { g_warning(_("Error Computing the Rendering Normals (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); g_free(density); return FALSE; } /* we're now done with the density volume, free it */ g_free(density); #ifdef AMIDE_DEBUG /* and wrapup our timing */ gettimeofday(&tv2, NULL); time1 = ((double) tv1.tv_sec) + ((double) tv1.tv_usec)/1000000.0; time2 = ((double) tv2.tv_sec) + ((double) tv2.tv_usec)/1000000.0; g_print("######## Loading object %s took %5.3f (s) #########\n", AMITK_OBJECT_NAME(rendering->object), time2-time1); #endif /* we'll be using min-max octree's as the classifying functions will probably be changed a lot */ /* octrees supposedly allow faster classification */ if (rendering->optimize_rendering) { #if AMIDE_DEBUG g_print("\tCreating the Min/Max Octree\n"); #endif /* set the thresholds on the min-max octree */ if (vpMinMaxOctreeThreshold(rendering->vpc, RENDERING_DENSITY_PARAM, RENDERING_OCTREE_DENSITY_THRESH) != VP_OK) { g_warning(_("Error Setting Rendering Octree Threshold (%s, DENSITY): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } if (vpMinMaxOctreeThreshold(rendering->vpc, RENDERING_GRADIENT_PARAM, RENDERING_OCTREE_GRADIENT_THRESH) != VP_OK) { g_warning(_("Error Setting Rendering Octree Threshold (%s, GRADIENT): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } /* create the min/max octree */ if (vpCreateMinMaxOctree(rendering->vpc, 0, RENDERING_OCTREE_BASE_NODE_SIZE) != VP_OK) { g_warning(_("Error Generating Octree (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } } /* set the initial ambient property, as I don't like the volpack default */ /* if (vpSetMaterial(vpc[which], VP_MATERIAL0, VP_AMBIENT, VP_BOTH_SIDES, 0.0, 0.0, 0.0) != VP_OK){ g_warning(_("Error Setting the Material (%s, AMBIENT): %s"),vol_name[which], vpGetErrorString(vpGetError(vpc[which]))); return FALSE; }*/ /* if (vpSetMaterial(vpc[PET_VOLUME], VP_MATERIAL0, VP_DIFFUSE, VP_BOTH_SIDES, 0.35, 0.35, 0.35) != VP_OK){ g_warning(_("Error Setting the Material (PET_VOLUME, DIFFUSE): %s"),vpGetErrorString(vpGetError(vpc[PET_VOLUME]))); return FALSE; }*/ /* if (vpSetMaterial(vpc[PET_VOLUME], VP_MATERIAL0, VP_SPECULAR, VP_BOTH_SIDES, 0.39, 0.39, 0.39) != VP_OK){ g_warning(_("Error Setting the Material (PET_VOLUME, SPECULAR): %s"),vpGetErrorString(vpGetError(vpc[PET_VOLUME]))); return FALSE; } */ /* set the initial shinyness, volpack's default is something shiny, I set shiny to zero */ if (vpSetMaterial(rendering->vpc, VP_MATERIAL0, VP_SHINYNESS, VP_BOTH_SIDES,0.0,0.0,0.0) != VP_OK){ g_warning(_("Error Setting the Rendering Material (%s, SHINYNESS): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } /* set the shading parameters */ if (vpSetLookupShader(rendering->vpc, 1, 1, RENDERING_NORMAL_FIELD, rendering->shade_table, sizeof(rendering->shade_table), 0, NULL, 0) != VP_OK){ g_warning(_("Error Setting the Rendering Shader (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } /* and do the shade table stuff (this fills in the shade table I believe) */ if (vpShadeTable(rendering->vpc) != VP_OK){ g_warning(_("Error Shading Table for Rendering (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return FALSE; } return TRUE; } static void set_space(rendering_t * rendering) { vpMatrix4 m; guint i,j; AmitkPoint axis; /* initalize */ for (i=0;i<4;i++) for (j=0;j<4;j++) if (i == j) m[i][j]=1; else m[i][j]=0; /* and setup the matrix we're feeding into volpack */ for (i=0;i<3;i++) { axis = amitk_space_get_axis(AMITK_SPACE(rendering->transformed_volume), i); m[i][0] = axis.x; m[i][1] = axis.y; m[i][2] = axis.z; } /* we want to rotate the data set */ if (vpCurrentMatrix(rendering->vpc, VP_MODEL) != VP_OK) g_warning(_("Error Setting The Item To Rotate (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); /* set the rotation */ if (vpSetMatrix(rendering->vpc, m) != VP_OK) g_warning(_("Error Rotating Rendering (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); } /* set the rotation space for a rendering context */ void rendering_set_space(rendering_t * rendering, AmitkSpace * space) { rendering->need_rerender = TRUE; amitk_space_copy_in_place(AMITK_SPACE(rendering->transformed_volume), space); set_space(rendering); return; } /* sets the rotation transform for a rendering context */ void rendering_set_rotation(rendering_t * rendering, AmitkAxis dir, gdouble rotation) { rendering->need_rerender = TRUE; /* rotate the axis */ amitk_space_rotate_on_vector(AMITK_SPACE(rendering->transformed_volume), amitk_space_get_axis(AMITK_SPACE(rendering->transformed_volume), dir), rotation, zero_point); set_space(rendering); return; } /* reset the rotation transform for a rendering context */ void rendering_reset_rotation(rendering_t * rendering) { AmitkSpace * new_space; rendering->need_rerender = TRUE; /* reset the coord frame */ new_space = amitk_space_new(); /* base space */ amitk_space_copy_in_place(AMITK_SPACE(rendering->transformed_volume), new_space); g_object_unref(new_space); /* reset the rotation */ rendering_set_rotation(rendering, AMITK_AXIS_X, 0.0); return; } /* set the speed versus quality parameters of a rendering context */ void rendering_set_quality(rendering_t * rendering, rendering_quality_t quality) { gdouble max_ray_opacity, min_voxel_opacity; rendering->need_rerender = TRUE; /* set the rendering speed parameters MAX_RAY_OPACITY and MIN_VOXEL_OPACITY*/ switch (quality) { case HIGH: max_ray_opacity = 0.99; min_voxel_opacity = 0.01; break; break; case FAST: max_ray_opacity = 0.95; min_voxel_opacity = 0.05; break; case FASTEST: max_ray_opacity = 0.9; min_voxel_opacity = 0.1; break; case HIGHEST: default: max_ray_opacity = 1.0; min_voxel_opacity = 0.0; break; } /* set the maximum ray opacity (the renderer quits follow a ray if this value is reached */ if (vpSetd(rendering->vpc, VP_MAX_RAY_OPACITY, max_ray_opacity) != VP_OK){ g_warning(_("Error Setting Rendering Max Ray Opacity (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); } /* set the minimum voxel opacity (the render ignores voxels with values below this*/ if (vpSetd(rendering->vpc, VP_MIN_VOXEL_OPACITY, min_voxel_opacity) != VP_OK) { g_warning(_("Error Setting the Min Voxel Opacity (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); } rendering->need_reclassify = TRUE; return; } /* function to set up the image that we'll be getting back from the rendering */ void rendering_set_image(rendering_t * rendering, pixel_type_t pixel_type, gdouble zoom) { guint volpack_pixel_type; amide_intpoint_t size_dim; /* size in one dimension, note that height == width */ rendering->need_rerender = TRUE; switch (pixel_type) { case GRAYSCALE: volpack_pixel_type = VP_LUMINANCE; break; case OPACITY: default: volpack_pixel_type = VP_ALPHA; break; } size_dim = ceil(zoom*POINT_MAX(rendering->dim)); g_free(rendering->image); if ((rendering->image = g_try_new(guchar,size_dim*size_dim)) == NULL) { g_warning(_("Could not allocate memory space for Rendering Image for %s"), rendering->name); return; } rendering->pixel_type = pixel_type; if (vpSetImage(rendering->vpc, (guchar *) rendering->image, size_dim, size_dim, size_dim* RENDERING_DENSITY_SIZE, volpack_pixel_type)) { g_warning(_("Error Switching the Rendering Image Pixel Return Type (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); } return; } /* switch the state of depth cueing (TRUE is on) */ void rendering_set_depth_cueing(rendering_t * rendering, gboolean state) { rendering->need_rerender = TRUE; if (vpEnable(rendering->vpc, VP_DEPTH_CUE, state) != VP_OK) { g_warning(_("Error Setting the Rendering Depth Cue (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); } return; } /* set the depth cueing parameters*/ void rendering_set_depth_cueing_parameters(rendering_t * rendering, gdouble front_factor, gdouble density) { rendering->need_rerender = TRUE; /* the defaults should be 1.0 and 1.0 */ if (vpSetDepthCueing(rendering->vpc, front_factor, density) != VP_OK){ g_warning(_("Error Enabling Rendering Depth Cueing (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); } return; } /* to render a rendering context... */ void rendering_render(rendering_t * rendering) { #ifdef AMIDE_COMMENT_OUT struct timeval tv1; struct timeval tv2; gdouble time1; gdouble time2; /* let's do some timing */ gettimeofday(&tv1, NULL); #endif if (rendering->need_rerender) { if (rendering->vpc != NULL) { if (rendering->optimize_rendering) { if (rendering->need_reclassify) { #if AMIDE_DEBUG g_print("\tClassifying\n"); #endif if (vpClassifyVolume(rendering->vpc) != VP_OK) { g_warning(_("Error Classifying the Volume (%s): %s"), rendering->name,vpGetErrorString(vpGetError(rendering->vpc))); return; } } if (vpRenderClassifiedVolume(rendering->vpc) != VP_OK) { g_warning(_("Error Rendering the Classified Volume (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return; } } else { if (vpRenderRawVolume(rendering->vpc) != VP_OK) { g_warning(_("Error Rendering the Volume (%s): %s"), rendering->name, vpGetErrorString(vpGetError(rendering->vpc))); return; } } } } #ifdef AMIDE_COMMENT_OUT /* and wrapup our timing */ gettimeofday(&tv2, NULL); time1 = ((double) tv1.tv_sec) + ((double) tv1.tv_usec)/1000000.0; time2 = ((double) tv2.tv_sec) + ((double) tv2.tv_usec)/1000000.0; g_print("######## Rendering object %s took %5.3f (s) #########\n", AMITK_OBJECT_NAME(rendering->object), time2-time1); #endif rendering->need_rerender = FALSE; rendering->need_reclassify = FALSE; return; } /* free up a list of rendering contexts */ renderings_t * renderings_unref(renderings_t * renderings) { if (renderings == NULL) return renderings; /* sanity check */ g_return_val_if_fail(renderings->ref_count > 0, NULL); renderings->ref_count--; /* things to do if our ref count is zero */ if (renderings->ref_count == 0) { /* recursively delete rest of list */ renderings->next = renderings_unref(renderings->next); renderings->rendering = rendering_unref(renderings->rendering); g_free(renderings); renderings = NULL; } return renderings; } /* the recursive part of renderings_init */ static renderings_t * renderings_init_recurse(GList * objects, AmitkVolume * render_volume, const amide_real_t voxel_size, const amide_time_t start, const amide_time_t duration, const gboolean zero_fill, const gboolean optimize_rendering, const gboolean no_gradient_opacity, AmitkUpdateFunc update_func, gpointer update_data) { renderings_t * temp_renderings; rendering_t * new_rendering; renderings_t * rest_of_list; if (objects == NULL) return NULL; /* recurse first */ rest_of_list = renderings_init_recurse(objects->next, render_volume, voxel_size, start, duration, zero_fill, optimize_rendering, no_gradient_opacity, update_func, update_data); new_rendering = rendering_init(objects->data, render_volume,voxel_size, start, duration, zero_fill, optimize_rendering, no_gradient_opacity, update_func, update_data); if (new_rendering != NULL) { if ((temp_renderings = g_try_new(renderings_t, 1)) == NULL) { return temp_renderings; } temp_renderings->ref_count = 1; temp_renderings->rendering = new_rendering; temp_renderings->next = rest_of_list; return temp_renderings; } else { return rest_of_list; } } /* returns an initialized rendering list */ renderings_t * renderings_init(GList * objects,const amide_time_t start, const amide_time_t duration, const gboolean zero_fill, const gboolean optimize_rendering, const gboolean no_gradient_opacity, const amide_real_t fov, const AmitkPoint view_center, AmitkUpdateFunc update_func, gpointer update_data) { AmitkCorners render_corner; amide_real_t voxel_size; AmitkVolume * render_volume; renderings_t * return_list; AmitkPoint width; amide_real_t max_width; if (objects == NULL) return NULL; /* figure out all encompasing corners for the slices based on our viewing axis */ render_volume = amitk_volume_new(); /* base coordinate frame */ amitk_volumes_get_enclosing_corners(objects, AMITK_SPACE(render_volume), render_corner); /* compensate for field of view */ width = point_sub(render_corner[1], render_corner[0]); max_width = (fov/100.0)*POINT_MAX(width); if (width.x > max_width) { if ((view_center.x-max_width/2.0) < render_corner[0].x) render_corner[1].x = render_corner[0].x+max_width; else if ((view_center.x+max_width/2.0) > render_corner[1].x) render_corner[0].x = render_corner[1].x-max_width; else { render_corner[0].x = view_center.x - max_width/2.0; render_corner[1].x = view_center.x + max_width/2.0; } } if (width.y > max_width) { if ((view_center.y-max_width/2.0) < render_corner[0].y) render_corner[1].y = render_corner[0].y+max_width; else if ((view_center.y+max_width/2.0) > render_corner[1].y) render_corner[0].y = render_corner[1].y-max_width; else { render_corner[0].y = view_center.y - max_width/2.0; render_corner[1].y = view_center.y + max_width/2.0; } } if (width.z > max_width) { if ((view_center.z-max_width/2.0) < render_corner[0].z) render_corner[1].z = render_corner[0].z+max_width; else if ((view_center.z+max_width/2.0) > render_corner[1].z) render_corner[0].z = render_corner[1].z-max_width; else { render_corner[0].z = view_center.z - max_width/2.0; render_corner[1].z = view_center.z + max_width/2.0; } } amitk_space_set_offset(AMITK_SPACE(render_volume), render_corner[0]); amitk_volume_set_corner(render_volume, amitk_space_b2s(AMITK_SPACE(render_volume), render_corner[1])); /* figure out what size our rendering voxels will be */ voxel_size = amitk_data_sets_get_min_voxel_size(objects); if (voxel_size < 0.0) voxel_size = amitk_rois_get_max_min_voxel_size(objects); if (voxel_size < 0.0) voxel_size = 1.0; /* and generate our rendering list */ return_list = renderings_init_recurse(objects, render_volume,voxel_size, start, duration, zero_fill, optimize_rendering, no_gradient_opacity, update_func, update_data); amitk_object_unref(render_volume); return return_list; } /* reloads the rendering list when needed, returns FALSE if not everything was done correctly */ gboolean renderings_reload_objects(renderings_t * renderings, const amide_time_t start, const amide_time_t duration, AmitkUpdateFunc update_func, gpointer update_data) { gboolean correct=TRUE; if (renderings != NULL) { /* reload this rendering context */ correct = rendering_reload_object(renderings->rendering, start, duration, update_func, update_data); /* and do the next */ correct = correct && renderings_reload_objects(renderings->next, start, duration, update_func, update_data); } return correct; } /* sets the space for a list of rendering context */ void renderings_set_space(renderings_t * renderings, AmitkSpace * space) { while (renderings != NULL) { rendering_set_space(renderings->rendering, space); renderings = renderings->next; } return; } /* sets the rotation transform for a list of rendering context */ void renderings_set_rotation(renderings_t * renderings, AmitkAxis dir, gdouble rotation) { while (renderings != NULL) { rendering_set_rotation(renderings->rendering, dir, rotation); renderings = renderings->next; } return; } /* resets the rotation transform for a list of rendering context */ void renderings_reset_rotation(renderings_t * renderings) { while (renderings != NULL) { rendering_reset_rotation(renderings->rendering); renderings = renderings->next; } return; } /* to set the quality on a list of rendering contexts */ void renderings_set_quality(renderings_t * renderings, rendering_quality_t quality) { while (renderings != NULL) { rendering_set_quality(renderings->rendering, quality); renderings = renderings->next; } return; } /* set the return image parameters for a list of rendering contexts */ void renderings_set_zoom(renderings_t * renderings, gdouble zoom) { while (renderings != NULL) { rendering_set_image(renderings->rendering, renderings->rendering->pixel_type, zoom); renderings = renderings->next; } return; } /* turn depth cueing on/off for a list of rendering contexts */ void renderings_set_depth_cueing(renderings_t * renderings, gboolean state) { while (renderings != NULL) { rendering_set_depth_cueing(renderings->rendering, state); renderings = renderings->next; } return; } /* sets the depth cueing parameters for a list of rendering contexts */ void renderings_set_depth_cueing_parameters(renderings_t * renderings, gdouble front_factor, gdouble density) { while (renderings != NULL) { rendering_set_depth_cueing_parameters(renderings->rendering, front_factor, density); renderings = renderings->next; } return; } /* to render a list of rendering contexts... */ void renderings_render(renderings_t * renderings) { while (renderings != NULL) { rendering_render(renderings->rendering); renderings = renderings->next; } return; } /* count the rendering lists */ guint renderings_count(renderings_t * renderings) { if (renderings != NULL) return (1+renderings_count(renderings->next)); else return 0; } /* function to set a material parameter */ /* gboolean render_set_material_shinyness(gint material_num, gdouble shinyness) */ /* { */ /* gint i; */ /* for (i=0; i */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBVOLPACK_SUPPORT #ifndef __RENDER_H__ #define __RENDER_H__ /* header files that are always needed with this file */ #include #include "amitk_object.h" #include "amitk_data_set.h" /* -------------- structures and such ------------- */ typedef gshort rendering_normal_t; typedef guchar rendering_density_t; typedef guchar rendering_gradient_t; typedef enum {DENSITY_CLASSIFICATION, GRADIENT_CLASSIFICATION, NUM_CLASSIFICATIONS} classification_t; typedef enum {HIGHEST, HIGH, FAST, FASTEST, NUM_QUALITIES} rendering_quality_t; typedef enum {OPACITY, GRAYSCALE, NUM_PIXEL_TYPES} pixel_type_t; typedef enum {CURVE_LINEAR, CURVE_SPLINE, NUM_CURVE_TYPES} curve_type_t; typedef struct { /* contents of a voxel */ rendering_normal_t normal; /* encoded surface normal vector */ rendering_density_t density; /* original density */ rendering_gradient_t gradient; /* original gradient */ } rendering_voxel_t; /* dummy variable used in some macros below */ extern rendering_voxel_t * dummy_voxel; /* ----------- defines ------------- */ #define RENDERING_BYTES_PER_VOXEL sizeof(rendering_voxel_t)/* voxel size in bytes */ #define RENDERING_VOXEL_FIELDS 3 /* number of fields in voxel */ #define RENDERING_SHADE_FIELDS 2 /* number of fields used for shading (normal and density); must be the 1st fields of RawVoxel */ #define RENDERING_CLSFY_FIELDS 2 /* number of fields used for classifying (density and gradient); can be any fields in the RawVoxel */ #define RENDERING_NORMAL_FIELD 0 #define RENDERING_NORMAL_OFFSET vpFieldOffset(dummy_voxel, normal) #define RENDERING_NORMAL_SIZE sizeof(rendering_normal_t) #define RENDERING_NORMAL_MAX VP_NORM_MAX /*7923 last time I checked */ #define RENDERING_DENSITY_FIELD 1 #define RENDERING_DENSITY_OFFSET vpFieldOffset(dummy_voxel, density) #define RENDERING_DENSITY_SIZE sizeof(rendering_density_t) #define RENDERING_DENSITY_MAX VP_SCALAR_MAX /*255 last time I checked */ #define RENDERING_GRADIENT_FIELD 2 #define RENDERING_GRADIENT_OFFSET vpFieldOffset(dummy_voxel, gradient) #define RENDERING_GRADIENT_SIZE sizeof(rendering_gradient_t) #define RENDERING_GRADIENT_MAX VP_GRAD_MAX /* 221 last time I checked */ #define RENDERING_DENSITY_PARAM 0 /* classification parameter */ #define RENDERING_GRADIENT_PARAM 1 /* classification parameter */ /* initial density and gradient ramps */ //#define RENDERING_DENSITY_RAMP_X {0.0, 20, RENDERING_DENSITY_MAX} //#define RENDERING_DENSITY_RAMP_Y {0.0, 1.0, 1.0} //#define RENDERING_DENSITY_RAMP_POINTS 3 #define RENDERING_DENSITY_RAMP_X {0.0, RENDERING_DENSITY_MAX} #define RENDERING_DENSITY_RAMP_Y {0.0, 1.0} #define RENDERING_DENSITY_RAMP_POINTS 2 #define RENDERING_GRADIENT_RAMP_X {0.0, RENDERING_GRADIENT_MAX} #define RENDERING_GRADIENT_RAMP_Y {0.0, 1.0} #define RENDERING_GRADIENT_RAMP_Y_FLAT {0.2, 0.2} #define RENDERING_GRADIENT_RAMP_POINTS 2 #define RENDERING_OCTREE_DENSITY_THRESH 4 #define RENDERING_OCTREE_GRADIENT_THRESH 4 #define RENDERING_OCTREE_BASE_NODE_SIZE 4 #define RENDERING_DEFAULT_ZOOM 1.0 #define RENDERING_DEFAULT_QUALITY HIGHEST #define RENDERING_DEFAULT_PIXEL_TYPE GRAYSCALE #define RENDERING_DEFAULT_DEPTH_CUEING FALSE #define RENDERING_DEFAULT_FRONT_FACTOR 1.0 #define RENDERING_DEFAULT_DENSITY 1.0 /* ------------ some more structures ------------ */ /* our rendering context structure */ typedef struct _rendering_t { vpContext * vpc; /* VolPack rendering Context */ AmitkObject * object; gchar * name; AmitkColorTable color_table; pixel_type_t pixel_type; amide_time_t start; amide_time_t duration; gint view_start_gate; gint view_end_gate; AmitkVolume * transformed_volume; /* volume in rendering space in which the data resides */ AmitkVolume * extraction_volume; /* set on init, used for extracting data into the context */ rendering_voxel_t * rendering_data; amide_real_t voxel_size; /* volpack needs isotropic voxels */ AmitkVoxel dim; /* dimensions of our rendering_data and image */ guchar * image; gfloat shade_table[RENDERING_NORMAL_MAX+1]; /* shading lookup table */ gfloat density_ramp[RENDERING_DENSITY_MAX+1]; /* opacity as a function */ gfloat gradient_ramp[RENDERING_GRADIENT_MAX+1]; /* opacity as a function */ gint * ramp_x[NUM_CLASSIFICATIONS]; gfloat * ramp_y[NUM_CLASSIFICATIONS]; guint num_points[NUM_CLASSIFICATIONS]; curve_type_t curve_type[NUM_CLASSIFICATIONS]; gboolean zero_fill; gboolean optimize_rendering; gboolean need_rerender; gboolean need_reclassify; guint ref_count; } rendering_t; /* a list of rendering contexts */ typedef struct _renderings_t renderings_t; struct _renderings_t { rendering_t * rendering; guint ref_count; renderings_t * next; }; /* notes: the update function needs to have the folowing syntax: gboolean update_func(gchar * message, gfloat fraction, gpointer data); */ /* external functions */ rendering_t * rendering_unref(rendering_t * rendering); rendering_t * rendering_init(const AmitkObject * object, AmitkVolume * rendering_volume, const amide_real_t min_voxel_size, const amide_time_t start, const amide_time_t duration, const gboolean zero_fill, const gboolean optimize_rendering, const gboolean no_gradient_opacity, AmitkUpdateFunc update_func, gpointer update_data); gboolean rendering_reload_object(rendering_t * rendering, const amide_time_t new_start, const amide_time_t new_duration, AmitkUpdateFunc update_func, gpointer update_data); gboolean rendering_load_object(rendering_t * rendering, AmitkUpdateFunc update_func, gpointer update_data); void rendering_set_space(rendering_t * rendering, AmitkSpace * space); void rendering_set_rotation(rendering_t * rendering, AmitkAxis dir, gdouble rotation); void rendering_reset_rotation(rendering_t * rendering); void rendering_set_quality(rendering_t * rendering, rendering_quality_t quality); void rendering_set_image(rendering_t * rendering, pixel_type_t pixel_type, gdouble zoom); void rendering_set_depth_cueing(rendering_t * rendering, gboolean state); void rendering_set_depth_cueing_parameters(rendering_t * rendering, gdouble front_factor, gdouble density); void rendering_render(rendering_t * rendering); renderings_t * renderings_unref(renderings_t * renderings); renderings_t * renderings_init(GList * objects, const amide_time_t start, const amide_time_t duration, const gboolean zero_fill, const gboolean optimize_rendering, const gboolean no_gradient_opacity, const amide_real_t fov, const AmitkPoint view_center, AmitkUpdateFunc update_func, gpointer update_data); gboolean renderings_reload_objects(renderings_t * renderings, const amide_time_t start, const amide_time_t duration, AmitkUpdateFunc update_func, gpointer update_data); void renderings_set_space(renderings_t * renderings, AmitkSpace * space); void renderings_set_rotation(renderings_t * renderings, AmitkAxis dir, gdouble rotation); void renderings_reset_rotation(renderings_t * renderings); void renderings_set_quality(renderings_t * renderlings, rendering_quality_t quality); void renderings_set_zoom(renderings_t * renderings, gdouble zoom); void renderings_set_depth_cueing(renderings_t * renderings, gboolean state); void renderings_set_depth_cueing_parameters(renderings_t * renderings, gdouble front_factor, gdouble density); void renderings_render(renderings_t * renderings); guint renderings_count(renderings_t * renderings); /* external variables */ extern gchar * rendering_quality_names[]; extern gchar * pixel_type_names[]; /* external funnctions from render.c */ //gboolean render_set_material_shinyness(gint material_num, gdouble shinyness); #endif /* __RENDERING_H__ */ #endif /* AMIDE_LIBVOLPACK_SUPPORT */ amide-1.0.6/amide-current/src/tb_alignment.c000066400000000000000000000664301423227705100207460ustar00rootroot00000000000000/* tb_alignment.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * except mutual information addition Copyright (C) 2011-2012 Ian Miller * */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_progress_dialog.h" #include "alignment_mutual_information.h" #include "alignment_procrustes.h" #include "tb_alignment.h" #include "ui_common.h" #define LABEL_WIDTH 375 static gchar * data_set_error_page_text = N_("There is only one data set in this study. There needs " "to be at least two data sets to perform an alignment"); static gchar * fiducial_marks_error_page_text = N_("In order to perform an alignment, each data set must " "have at least three objects with the same name as " "the corresponding three objects in the other data set." "\n\n" "Please see the help documentation for a longer " "explanation as to how alignments can be done."); static gchar * start_page_text = N_("Welcome to the data set alignment wizard, used for " "aligning one medical image data set with another. " "\n\n" #ifdef AMIDE_LIBGSL_SUPPORT "Currently, only rigid body registration using either " "fiducial marks, or maximization of mutual information " "has been implemented inside of AMIDE. " #else "This program was built without libgsl support, as such " "registration utilizing fiducial marks is not supported." #endif "\n\n" "The mutual information algorithm is run on the " "currently displayed slices, not the whole data " "sets."); typedef enum { COLUMN_DATA_SET_NAME, COLUMN_DATA_SET_POINTER, NUM_DATA_SET_COLUMNS } data_set_column_t; typedef enum { COLUMN_POINT_SELECTED, COLUMN_POINT_NAME, COLUMN_POINT_POINTER, NUM_POINT_COLUMNS } point_column_t; typedef enum { INTRO_PAGE, ALIGNMENT_TYPE_PAGE, DATA_SETS_PAGE, FIDUCIAL_MARKS_PAGE, NO_FIDUCIAL_MARKS_PAGE, CONCLUSION_PAGE, NUM_PAGES } which_page_t; typedef enum { #ifdef AMIDE_LIBGSL_SUPPORT PROCRUSTES, #endif MUTUAL_INFORMATION, NUM_ALIGNMENT_TYPES } which_alignment_t; static gchar * alignment_names[] = { #ifdef AMIDE_LIBGSL_SUPPORT N_("Fiducial Markers"), #endif N_("Mutual Information") }; /* data structures */ typedef struct tb_alignment_t { GtkWidget * dialog; GtkWidget * page[NUM_PAGES]; GtkWidget * list_moving_ds; GtkWidget * list_fixed_ds; GtkWidget * list_points; GtkWidget * progress_dialog; GList * data_sets; AmitkDataSet * moving_ds; AmitkDataSet * fixed_ds; which_alignment_t alignment_type; GList * selected_marks; AmitkSpace * transform_space; /* the new coordinate space for the moving volume */ amide_time_t view_start_time; amide_time_t view_duration; AmitkPoint view_center; amide_real_t view_thickness; guint reference_count; } tb_alignment_t; static tb_alignment_t * tb_alignment_free(tb_alignment_t * alignment); static tb_alignment_t * tb_alignment_init(void); static void apply_cb(GtkAssistant * assistant, gpointer data); static void close_cb(GtkAssistant * assistant, gpointer data); static void data_sets_update_model(tb_alignment_t * alignment); static void points_update_model(tb_alignment_t * alignment); static void alignment_type_changed_cb(GtkRadioButton * clicked_button, gpointer data ); static void data_set_selection_changed_cb(GtkTreeSelection * selection, gpointer data); static gboolean points_button_press_event(GtkWidget * list, GdkEventButton * event, gpointer data); static GtkWidget * create_alignment_type_page(tb_alignment_t * tb_alignment); static GtkWidget * create_data_sets_page(tb_alignment_t * tb_alignment); static GtkWidget * create_fiducial_marks_page(tb_alignment_t * tb_alignment); static gint forward_page_function (gint current_page, gpointer data); static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data); /* destroy a alignment data structure */ static tb_alignment_t * tb_alignment_free(tb_alignment_t * tb_alignment) { gboolean return_val; g_return_val_if_fail(tb_alignment != NULL, NULL); /* sanity checks */ g_return_val_if_fail(tb_alignment->reference_count > 0, NULL); /* remove a reference count */ tb_alignment->reference_count--; /* things to do if we've removed all reference's */ if (tb_alignment->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_alignment\n"); #endif if (tb_alignment->data_sets != NULL) tb_alignment->data_sets = amitk_objects_unref(tb_alignment->data_sets); if (tb_alignment->moving_ds != NULL) { amitk_object_unref(tb_alignment->moving_ds); tb_alignment->moving_ds = NULL; } if (tb_alignment->fixed_ds != NULL) { amitk_object_unref(tb_alignment->fixed_ds); tb_alignment->fixed_ds = NULL; } if (tb_alignment->selected_marks != NULL) tb_alignment->selected_marks = amitk_objects_unref(tb_alignment->selected_marks); if (tb_alignment->transform_space != NULL) { g_object_unref(tb_alignment->transform_space); tb_alignment->transform_space = NULL; } if (tb_alignment->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_alignment->progress_dialog), "delete_event", NULL, &return_val); tb_alignment->progress_dialog = NULL; } g_free(tb_alignment); tb_alignment = NULL; } return tb_alignment; } /* allocate and initialize an alignment data structure */ static tb_alignment_t * tb_alignment_init(void) { tb_alignment_t * tb_alignment; /* alloc space for the data structure for passing ui info */ if ((tb_alignment = g_try_new(tb_alignment_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_alignment_t")); return NULL; } tb_alignment->reference_count = 1; tb_alignment->dialog = NULL; tb_alignment->progress_dialog = NULL; tb_alignment->moving_ds = NULL; tb_alignment->fixed_ds = NULL; tb_alignment->alignment_type = 0; /* PROCRUSTES if with GSL support */ tb_alignment->selected_marks = NULL; tb_alignment->transform_space = NULL; return tb_alignment; } /* function called when the finish button is hit */ static void apply_cb(GtkAssistant * assistant, gpointer data) { tb_alignment_t * tb_alignment = data; /* sanity check */ g_return_if_fail(tb_alignment->transform_space != NULL); /* apply the alignment transform */ amitk_space_transform(AMITK_SPACE(tb_alignment->moving_ds), tb_alignment->transform_space); return; } /* function called to cancel the dialog */ static void close_cb(GtkAssistant * assistant, gpointer data) { tb_alignment_t * tb_alignment = data; GtkWidget * dialog = tb_alignment->dialog; tb_alignment = tb_alignment_free(tb_alignment); /* trash collection */ gtk_widget_destroy(dialog); return; } static void data_sets_update_model(tb_alignment_t * tb_alignment) { GtkTreeIter iter; GtkTreeModel * model; GtkTreeSelection *selection; GList * data_sets; gint count; /* update the moving data set */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_alignment->list_moving_ds)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_alignment->list_moving_ds)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ data_sets = tb_alignment->data_sets; count = 0; while (data_sets != NULL) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set (GTK_LIST_STORE(model), &iter, COLUMN_DATA_SET_NAME, AMITK_OBJECT_NAME(data_sets->data), COLUMN_DATA_SET_POINTER, data_sets->data, -1); if ( ((tb_alignment->moving_ds == NULL) && (count == 0)) || (tb_alignment->moving_ds == data_sets->data)) gtk_tree_selection_select_iter (selection, &iter); count++; data_sets = data_sets->next; } /* update the fixed data set */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_alignment->list_fixed_ds)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_alignment->list_fixed_ds)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ data_sets = tb_alignment->data_sets; count = 0; while (data_sets != NULL) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set (GTK_LIST_STORE(model), &iter, COLUMN_DATA_SET_NAME, AMITK_OBJECT_NAME(data_sets->data), COLUMN_DATA_SET_POINTER, data_sets->data, -1); if (((tb_alignment->fixed_ds == NULL) && (tb_alignment->moving_ds != data_sets->data)) || (tb_alignment->fixed_ds == data_sets->data)) if (count == 1) gtk_tree_selection_select_iter (selection, &iter); count++; data_sets = data_sets->next; } return; } static void points_update_model(tb_alignment_t * tb_alignment) { GtkTreeIter iter; GList * fiducial_marks; GList * selected_marks; GtkTreeModel * model; gboolean selected; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_alignment->list_points)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ /* put in new pairs of points */ fiducial_marks = AMITK_OBJECT_CHILDREN(tb_alignment->fixed_ds); selected_marks = tb_alignment->selected_marks; tb_alignment->selected_marks = NULL; while (fiducial_marks != NULL) { if (AMITK_IS_FIDUCIAL_MARK(fiducial_marks->data) || (AMITK_IS_VOLUME(fiducial_marks->data))) { if (amitk_objects_find_object_by_name(AMITK_OBJECT_CHILDREN(tb_alignment->moving_ds), AMITK_OBJECT_NAME(fiducial_marks->data))) { if ((amitk_objects_find_object_by_name(selected_marks, AMITK_OBJECT_NAME(fiducial_marks->data))) || (selected_marks == NULL)) selected = TRUE; else selected = FALSE; gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_POINT_SELECTED, selected, COLUMN_POINT_NAME, AMITK_OBJECT_NAME(fiducial_marks->data), COLUMN_POINT_POINTER, fiducial_marks->data, -1); if (selected) tb_alignment->selected_marks = g_list_append(tb_alignment->selected_marks, amitk_object_ref(fiducial_marks->data)); } } fiducial_marks = fiducial_marks->next; } selected_marks = amitk_objects_unref(selected_marks); return; } static void alignment_type_changed_cb(GtkRadioButton * rb, gpointer data ) { tb_alignment_t * tb_alignment = data; g_return_if_fail(tb_alignment != NULL); tb_alignment->alignment_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(rb), "alignment_type")); return; } static void data_set_selection_changed_cb(GtkTreeSelection * selection, gpointer data) { tb_alignment_t * tb_alignment = data; AmitkDataSet * ds; gboolean fixed_ds; gboolean can_continue; GtkTreeIter iter; GtkTreeModel * model; fixed_ds = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(selection), "fixed")); if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get(model, &iter, COLUMN_DATA_SET_POINTER, &ds, -1); g_return_if_fail(AMITK_IS_DATA_SET(ds)); if (fixed_ds) { if (tb_alignment->fixed_ds != NULL) amitk_object_unref(tb_alignment->fixed_ds); tb_alignment->fixed_ds = amitk_object_ref(ds); } else { if (tb_alignment->moving_ds != NULL) amitk_object_unref(tb_alignment->moving_ds); tb_alignment->moving_ds = amitk_object_ref(ds); } } else { if (fixed_ds) { if (tb_alignment->fixed_ds != NULL) amitk_object_unref(tb_alignment->fixed_ds); tb_alignment->fixed_ds = NULL; } else { if (tb_alignment->moving_ds != NULL) amitk_object_unref(tb_alignment->moving_ds); tb_alignment->moving_ds = NULL; } } can_continue = ((tb_alignment->fixed_ds != NULL) && (tb_alignment->moving_ds != NULL) && (tb_alignment->fixed_ds != tb_alignment->moving_ds)); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[DATA_SETS_PAGE], can_continue); return; } static gboolean points_button_press_event(GtkWidget * list, GdkEventButton * event, gpointer data) { tb_alignment_t * tb_alignment = data; GtkTreePath * path=NULL; AmitkObject * point; gboolean can_continue; GtkTreeIter iter; GtkTreeModel * model; gboolean toggled; gint cell_x, cell_y; switch(event->button) { case 1: /* left button */ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(list), event->x, event->y, &path, NULL, &cell_x, &cell_y)) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(model, &iter, COLUMN_POINT_SELECTED, &toggled, COLUMN_POINT_POINTER, &point, -1); g_return_val_if_fail(AMITK_IS_FIDUCIAL_MARK(point) || AMITK_IS_VOLUME(point), FALSE); toggled = !toggled; gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_POINT_SELECTED, toggled, -1); if (toggled) { tb_alignment->selected_marks = g_list_append(tb_alignment->selected_marks, amitk_object_ref(point)); } else { tb_alignment->selected_marks = g_list_remove(tb_alignment->selected_marks, point); amitk_object_unref(point); } } break; default: /* do nothing */ break; } can_continue = (amitk_objects_count(tb_alignment->selected_marks) >= 3); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[FIDUCIAL_MARKS_PAGE], can_continue); return FALSE; } /* Ian Miller addition */ /* this sets up the user interface for the "Alignment type" page/section of the wizard */ static GtkWidget * create_alignment_type_page(tb_alignment_t * tb_alignment) { GtkWidget * vbox; GtkWidget * rb[NUM_ALIGNMENT_TYPES]; which_alignment_t i_alignment; vbox = gtk_vbox_new (TRUE, 2); for (i_alignment = 0; i_alignment < NUM_ALIGNMENT_TYPES; i_alignment ++) { if (i_alignment == 0) rb[i_alignment] = gtk_radio_button_new_with_label(NULL, alignment_names[i_alignment]); else rb[i_alignment] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rb[0]), alignment_names[i_alignment]); gtk_box_pack_start (GTK_BOX (vbox), rb[i_alignment], TRUE, TRUE, 2); g_object_set_data(G_OBJECT(rb[i_alignment]), "alignment_type", GINT_TO_POINTER(i_alignment)); } /* set which toggle button is pressed in before connecting signals */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb[tb_alignment->alignment_type]), TRUE); for (i_alignment = 0; i_alignment < NUM_ALIGNMENT_TYPES; i_alignment ++) { g_signal_connect(G_OBJECT(rb[i_alignment]), "clicked", G_CALLBACK(alignment_type_changed_cb), tb_alignment); } return vbox; } static GtkWidget * create_data_sets_page(tb_alignment_t * tb_alignment) { GtkWidget * table; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkWidget * vseparator; table = gtk_table_new(3,3,FALSE); /* the moving data set */ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); tb_alignment->list_moving_ds = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Align Data Set: (moving)"), renderer, "text", COLUMN_DATA_SET_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_alignment->list_moving_ds), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_alignment->list_moving_ds)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_object_set_data(G_OBJECT(selection), "fixed", GINT_TO_POINTER(FALSE)); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(data_set_selection_changed_cb), tb_alignment); gtk_table_attach(GTK_TABLE(table),tb_alignment->list_moving_ds, 0,1,0,1, GTK_FILL|GTK_EXPAND, GTK_FILL | GTK_EXPAND,X_PADDING, Y_PADDING); vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(table), vseparator, 1,2,0,2, 0, GTK_FILL, X_PADDING, Y_PADDING); /* the fixed data set */ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); tb_alignment->list_fixed_ds = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Align Data Set: (fixed)"), renderer, "text", COLUMN_DATA_SET_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_alignment->list_fixed_ds), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_alignment->list_fixed_ds)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_object_set_data(G_OBJECT(selection), "fixed", GINT_TO_POINTER(TRUE)); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(data_set_selection_changed_cb), tb_alignment); gtk_table_attach(GTK_TABLE(table),tb_alignment->list_fixed_ds, 2,3,0,1, GTK_FILL|GTK_EXPAND, GTK_FILL | GTK_EXPAND,X_PADDING, Y_PADDING); return table; } static GtkWidget * create_fiducial_marks_page(tb_alignment_t * tb_alignment) { GtkWidget * table; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; table = gtk_table_new(2,2,FALSE); store = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER); tb_alignment->list_points = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); g_signal_connect(G_OBJECT(tb_alignment->list_points), "button_press_event", G_CALLBACK(points_button_press_event), tb_alignment); renderer = gtk_cell_renderer_toggle_new (); column = gtk_tree_view_column_new_with_attributes("Select", renderer, "active", COLUMN_POINT_SELECTED, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_alignment->list_points), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Points for Alignment"), renderer, "text", COLUMN_POINT_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_alignment->list_points), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_alignment->list_points)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); gtk_table_attach(GTK_TABLE(table),tb_alignment->list_points, 0,1,0,1, GTK_FILL|GTK_EXPAND, GTK_FILL | GTK_EXPAND,X_PADDING, Y_PADDING); return table; } static gint forward_page_function (gint current_page, gpointer data) { tb_alignment_t * tb_alignment=data; gint num_pairs=0; switch (current_page) { case ALIGNMENT_TYPE_PAGE: return DATA_SETS_PAGE; break; case DATA_SETS_PAGE: if (tb_alignment->alignment_type == MUTUAL_INFORMATION) return CONCLUSION_PAGE; if ((tb_alignment->fixed_ds != NULL) && (tb_alignment->moving_ds != NULL)) num_pairs = amitk_objects_count_pairs_by_name(AMITK_OBJECT_CHILDREN(tb_alignment->fixed_ds), AMITK_OBJECT_CHILDREN(tb_alignment->moving_ds)); if (num_pairs < 3) return NO_FIDUCIAL_MARKS_PAGE; else return FIDUCIAL_MARKS_PAGE; break; case FIDUCIAL_MARKS_PAGE: return CONCLUSION_PAGE; break; default: return current_page+1; break; } } static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data) { tb_alignment_t * tb_alignment = data; which_page_t which_page; which_alignment_t which_alignment; gdouble performance_metric; gchar * temp_string; which_page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(page), "which_page")); which_alignment = tb_alignment->alignment_type; switch(which_page) { case DATA_SETS_PAGE: data_sets_update_model(tb_alignment); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), page, (tb_alignment->fixed_ds != NULL) && (tb_alignment->moving_ds != NULL) && (tb_alignment->fixed_ds != tb_alignment->moving_ds)); break; case FIDUCIAL_MARKS_PAGE: points_update_model(tb_alignment); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[FIDUCIAL_MARKS_PAGE], amitk_objects_count(tb_alignment->selected_marks) >= 3); break; case CONCLUSION_PAGE: /* calculate the alignment */ switch(which_alignment) { #ifdef AMIDE_LIBGSL_SUPPORT case PROCRUSTES: tb_alignment->transform_space = alignment_procrustes(tb_alignment->moving_ds, tb_alignment->fixed_ds, tb_alignment->selected_marks, &performance_metric); temp_string = g_strdup_printf(_("The alignment has been calculated, press Apply, or Cancel to quit.\n\nThe calculated fiducial reference error is:\n\t %5.2f mm/point"), performance_metric); break; #endif case MUTUAL_INFORMATION: tb_alignment->transform_space = alignment_mutual_information(tb_alignment->moving_ds, tb_alignment->fixed_ds, tb_alignment->view_center, tb_alignment->view_thickness, tb_alignment->view_start_time, tb_alignment->view_duration, &performance_metric, amitk_progress_dialog_update, tb_alignment->progress_dialog); temp_string = g_strdup_printf(_("The alignment has been calculated, press Apply, or Cancel to quit.\n\nThe calculated mutual information metric is:\n\t %5.2f"), performance_metric); break; default: g_return_if_reached(); break; } gtk_label_set_text(GTK_LABEL(page), temp_string); g_free(temp_string); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), page, TRUE); break; case NO_FIDUCIAL_MARKS_PAGE: default: break; } return; } /* function that sets up an align point dialog */ void tb_alignment(AmitkStudy * study, GtkWindow * parent) { tb_alignment_t * tb_alignment; GdkPixbuf * logo; guint count; gint i; g_return_if_fail(AMITK_IS_STUDY(study)); tb_alignment = tb_alignment_init(); tb_alignment->data_sets = amitk_object_get_children_of_type(AMITK_OBJECT(study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); tb_alignment->view_start_time = AMITK_STUDY_VIEW_START_TIME(study); tb_alignment->view_duration = AMITK_STUDY_VIEW_DURATION(study); tb_alignment->view_center = AMITK_STUDY_VIEW_CENTER(study); tb_alignment->view_thickness = AMITK_STUDY_VIEW_THICKNESS(study); tb_alignment->dialog = gtk_assistant_new(); gtk_window_set_transient_for(GTK_WINDOW(tb_alignment->dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW(tb_alignment->dialog), TRUE); g_signal_connect(G_OBJECT(tb_alignment->dialog), "cancel", G_CALLBACK(close_cb), tb_alignment); g_signal_connect(G_OBJECT(tb_alignment->dialog), "close", G_CALLBACK(close_cb), tb_alignment); g_signal_connect(G_OBJECT(tb_alignment->dialog), "apply", G_CALLBACK(apply_cb), tb_alignment); g_signal_connect(G_OBJECT(tb_alignment->dialog), "prepare", G_CALLBACK(prepare_page_cb), tb_alignment); gtk_assistant_set_forward_page_func(GTK_ASSISTANT(tb_alignment->dialog), forward_page_function, tb_alignment, NULL); tb_alignment->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_alignment->dialog)); /* --------------- initial page ------------------ */ count = amitk_data_sets_count(tb_alignment->data_sets, TRUE); tb_alignment->page[INTRO_PAGE] = gtk_label_new((count >= 2) ? _(start_page_text) : _(data_set_error_page_text)); gtk_widget_set_size_request(tb_alignment->page[INTRO_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_alignment->page[INTRO_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[INTRO_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[INTRO_PAGE], _("Data Set Alignment Wizard")); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[INTRO_PAGE], GTK_ASSISTANT_PAGE_INTRO); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[INTRO_PAGE], count >= 2); /*------------------ pick your alignment type page ------------------ */ tb_alignment->page[ALIGNMENT_TYPE_PAGE] = create_alignment_type_page(tb_alignment); gtk_assistant_append_page(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[ALIGNMENT_TYPE_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[ALIGNMENT_TYPE_PAGE], _("Alignment Type Selection")); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[ALIGNMENT_TYPE_PAGE], TRUE); /*------------------ pick your data set page ------------------ */ tb_alignment->page[DATA_SETS_PAGE] = create_data_sets_page(tb_alignment); gtk_assistant_append_page(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[DATA_SETS_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[DATA_SETS_PAGE], _("Data Set Selection")); /*------------------ pick your fiducial marks page ------------------ */ tb_alignment->page[FIDUCIAL_MARKS_PAGE] = create_fiducial_marks_page(tb_alignment); gtk_assistant_append_page(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[FIDUCIAL_MARKS_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[FIDUCIAL_MARKS_PAGE], _("Fiducial Marks Selection")); /* --------------- page shown if no fiducial marks ------------------ */ tb_alignment->page[NO_FIDUCIAL_MARKS_PAGE] = gtk_label_new(_(fiducial_marks_error_page_text)); gtk_widget_set_size_request(tb_alignment->page[NO_FIDUCIAL_MARKS_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_alignment->page[NO_FIDUCIAL_MARKS_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[NO_FIDUCIAL_MARKS_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[NO_FIDUCIAL_MARKS_PAGE], _("Alignment Error")); /* ---------------- conclusion page ---------------------------------- */ tb_alignment->page[CONCLUSION_PAGE] = gtk_label_new(""); gtk_widget_set_size_request(tb_alignment->page[CONCLUSION_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_alignment->page[CONCLUSION_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[CONCLUSION_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[CONCLUSION_PAGE], _("Conclusion")); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_alignment->dialog), tb_alignment->page[CONCLUSION_PAGE], GTK_ASSISTANT_PAGE_CONFIRM); /* things for all page */ logo = gtk_widget_render_icon(GTK_WIDGET(tb_alignment->dialog), "amide_icon_logo", GTK_ICON_SIZE_DIALOG, 0); for (i=0; idialog), tb_alignment->page[i], logo); g_object_set_data(G_OBJECT(tb_alignment->page[i]),"which_page", GINT_TO_POINTER(i)); } g_object_unref(logo); gtk_widget_show_all(tb_alignment->dialog); return; } amide-1.0.6/amide-current/src/tb_alignment.h000066400000000000000000000017751423227705100207540ustar00rootroot00000000000000/* tb_alignment.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_study.h" /* external functions */ void tb_alignment(AmitkStudy * study, GtkWindow * parent); amide-1.0.6/amide-current/src/tb_crop.c000066400000000000000000001113541423227705100177270ustar00rootroot00000000000000/* tb_crop.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "image.h" #include "tb_crop.h" #include "amitk_threshold.h" #include "amitk_progress_dialog.h" #include "ui_common.h" #define AXIS_WIDTH 120 #define AXIS_HEIGHT 120 #define CURSOR_SIZE 1 #define NUM_ROWS 4 static const char * finish_page_text = N_("When the apply button is hit, a new data set will be created\n" "and placed into the study's tree, consisting of the appropriately\n" "cropped data\n"); typedef enum { TRANSVERSE_PAGE, CORONAL_PAGE, SAGITTAL_PAGE, CONVERSION_PAGE, FINISH_PAGE, NUM_PAGES } which_page_t; typedef enum { RANGE_MIN, RANGE_MAX, NUM_RANGES } range_t; /* data structures */ typedef struct tb_crop_t { GtkWidget * dialog; AmitkVoxel range[NUM_RANGES]; AmitkFormat format; AmitkScalingType scaling_type; guint frame; guint gate; gdouble zoom; amide_data_t threshold_max; amide_data_t threshold_min; AmitkColorTable color_table; gboolean threshold_info_set; AmitkStudy * study; AmitkDataSet * data_set; AmitkDataSet * projections[AMITK_VIEW_NUM]; GtkWidget * canvas[AMITK_VIEW_NUM]; GnomeCanvasItem * image[AMITK_VIEW_NUM]; gint canvas_width[AMITK_VIEW_NUM]; gint canvas_height[AMITK_VIEW_NUM]; GnomeCanvasItem * line[AMITK_VIEW_NUM][2][NUM_RANGES]; GtkWidget * threshold[AMITK_VIEW_NUM]; GList * update_view; gint idle_handler_id; GtkWidget * zoom_spinner[AMITK_VIEW_NUM]; GtkWidget * frame_spinner[AMITK_VIEW_NUM]; GtkWidget * gate_spinner[AMITK_VIEW_NUM]; GtkWidget * spinner[AMITK_VIEW_NUM][AMITK_DIM_NUM][NUM_RANGES]; GtkWidget * mm_label[AMITK_VIEW_NUM][AMITK_AXIS_NUM][NUM_RANGES]; GtkWidget * page[NUM_PAGES]; GtkWidget * progress_dialog; guint reference_count; } tb_crop_t; static void apply_cb(GtkAssistant * assistant, gpointer data); static void close_cb(GtkAssistant * assistant, gpointer data); static tb_crop_t * tb_crop_free(tb_crop_t * tb_crop); static tb_crop_t * tb_crop_init(void); static GtkWidget * create_projection_page(tb_crop_t * tb_crop, AmitkView view); static GtkWidget * create_conversion_page(tb_crop_t * tb_crop); static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data); static void zoom_spinner_cb(GtkSpinButton * button, gpointer data); static void frame_spinner_cb(GtkSpinButton * button, gpointer data); static void gate_spinner_cb(GtkSpinButton * button, gpointer data); static void spinner_cb(GtkSpinButton * button, gpointer data); static void projection_thresholds_changed_cb(AmitkDataSet * projection, gpointer data); static void projection_color_table_changed_cb(AmitkDataSet * projection, AmitkViewMode view_mode, gpointer data); static void change_format_cb(GtkWidget * widget, gpointer data); static void change_scaling_type_cb(GtkWidget * widget, gpointer data); static void update_mm_labels(tb_crop_t * tb_crop, AmitkView view); static void update_crop_lines(tb_crop_t * tb_crop, AmitkView view); static void add_canvas_update(tb_crop_t * tb_crop, AmitkView view); static gboolean update_canvas_while_idle(gpointer tb_crop); /* function called when the finish button is hit */ static void apply_cb(GtkAssistant * assistant, gpointer data) { tb_crop_t * tb_crop = data; AmitkDataSet * cropped; /* disable the buttons */ gtk_widget_set_sensitive(GTK_WIDGET(assistant), FALSE); /* generate the new data set */ cropped = amitk_data_set_get_cropped(tb_crop->data_set, tb_crop->range[RANGE_MIN], tb_crop->range[RANGE_MAX], tb_crop->format, tb_crop->scaling_type, amitk_progress_dialog_update, tb_crop->progress_dialog); /* if successful, add the new data set to the study and quit*/ if (cropped != NULL) { amitk_object_add_child(AMITK_OBJECT(tb_crop->study), AMITK_OBJECT(cropped)); /* this adds a reference to the data set*/ amitk_object_unref(cropped); /* so remove a reference */ } else g_warning("Failed to generate cropped data set"); /* close_cb gets run automatically on close */ return; } /* function called to cancel the dialog */ static void close_cb(GtkAssistant * assistant, gpointer data) { tb_crop_t * tb_crop = data; GtkWidget * dialog = tb_crop->dialog; tb_crop = tb_crop_free(tb_crop); gtk_widget_destroy(dialog); return; } static GtkWidget * create_projection_page(tb_crop_t * tb_crop, AmitkView view) { GtkWidget * table; GtkWidget * label; GtkWidget * spin_button; gint table_row, m_table_row; gint table_column; AmitkDim i_dim; range_t i_range; gchar * temp_string; GtkWidget * axis_canvas; GtkWidget * vseparator; GtkWidget * middle_table; table = gtk_table_new(NUM_ROWS,5,FALSE); table_row=0; table_column=0; /* the zoom selection */ label = gtk_label_new(_("zoom")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, 0); spin_button = gtk_spin_button_new_with_range(0.2,5.0,0.2); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button),2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), tb_crop->zoom); g_object_set_data(G_OBJECT(spin_button), "which_view", GINT_TO_POINTER(view)); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(zoom_spinner_cb), tb_crop); gtk_table_attach(GTK_TABLE(table), spin_button, table_column+1,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, 0); tb_crop->zoom_spinner[view] = spin_button; table_row++; /* the gate selection */ if (AMITK_DATA_SET_NUM_GATES(tb_crop->data_set) > 1) { label = gtk_label_new(_("gate")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, 0); spin_button = gtk_spin_button_new_with_range(0,AMITK_DATA_SET_NUM_GATES(tb_crop->data_set)-1,1); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button),0); g_object_set_data(G_OBJECT(spin_button), "which_view", GINT_TO_POINTER(view)); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(gate_spinner_cb), tb_crop); gtk_table_attach(GTK_TABLE(table), spin_button, table_column+1,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, 0); tb_crop->gate_spinner[view] = spin_button; table_row++; } /* the frame selection */ if (AMITK_DATA_SET_NUM_FRAMES(tb_crop->data_set) > 1) { label = gtk_label_new(_("frame")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(0,AMITK_DATA_SET_NUM_FRAMES(tb_crop->data_set)-1,1); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button),0); g_object_set_data(G_OBJECT(spin_button), "which_view", GINT_TO_POINTER(view)); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(frame_spinner_cb), tb_crop); gtk_table_attach(GTK_TABLE(table), spin_button, table_column+1,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_crop->frame_spinner[view] = spin_button; table_row++; } /* the projection */ #ifdef AMIDE_LIBGNOMECANVAS_AA tb_crop->canvas[view] = gnome_canvas_new_aa(); #else tb_crop->canvas[view] = gnome_canvas_new(); #endif gtk_table_attach(GTK_TABLE(table), tb_crop->canvas[view], table_column,table_column+2,table_row,NUM_ROWS, FALSE,FALSE, X_PADDING, Y_PADDING); add_canvas_update(tb_crop, view); /* wait for canvas to update, this allows the projection to get made */ while (tb_crop->idle_handler_id != 0) gtk_main_iteration(); table_row=0; table_column += 2; /* a separator for clarity */ vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(table), vseparator, table_column, table_column+1, table_row, NUM_ROWS, 0, GTK_FILL, X_PADDING, Y_PADDING); table_row=0; table_column += 1; /* the middle table */ middle_table = gtk_table_new(9, 3, FALSE); gtk_table_attach(GTK_TABLE(table), middle_table, table_column, table_column+1, table_row, NUM_ROWS, 0, GTK_FILL, X_PADDING, Y_PADDING); m_table_row=0; /* the range selectors */ for (i_dim=0; i_dimdata_set), i_dim) > 1) { temp_string = g_strdup_printf(_("%s range:"), amitk_dim_get_name(i_dim)); label = gtk_label_new(temp_string); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); g_free(temp_string); gtk_table_attach(GTK_TABLE(middle_table), label, 0,1, m_table_row,m_table_row+1, GTK_FILL|GTK_EXPAND,FALSE, X_PADDING, 0); for (i_range=0; i_rangedata_set), i_dim)-1,1); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button),0); // gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), // voxel_get_dim(tb_crop->range[i_range], i_dim)); g_object_set_data(G_OBJECT(spin_button), "which_view", GINT_TO_POINTER(view)); g_object_set_data(G_OBJECT(spin_button), "which_dim", GINT_TO_POINTER(i_dim)); g_object_set_data(G_OBJECT(spin_button), "which_range", GINT_TO_POINTER(i_range)); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(spinner_cb), tb_crop); gtk_table_attach(GTK_TABLE(middle_table), spin_button, 1+i_range,2+i_range, m_table_row,m_table_row+1, FALSE,FALSE, X_PADDING, 0); tb_crop->spinner[view][i_dim][i_range] = spin_button; } m_table_row++; if (i_dim <= AMITK_DIM_Z) { label = gtk_label_new(_("(mm)")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(middle_table), label, 0,1, m_table_row,m_table_row+1, GTK_FILL|GTK_EXPAND,FALSE, X_PADDING, 0); for (i_range=0; i_rangemm_label[view][i_dim][i_range] = gtk_label_new(""); gtk_table_attach(GTK_TABLE(middle_table), tb_crop->mm_label[view][i_dim][i_range], 1+i_range,2+i_range, m_table_row,m_table_row+1, FALSE,FALSE, X_PADDING, 0); } m_table_row++; } } } /* the axis display */ #ifdef AMIDE_LIBGNOMECANVAS_AA axis_canvas = gnome_canvas_new_aa(); #else axis_canvas = gnome_canvas_new(); #endif ui_common_draw_view_axis(GNOME_CANVAS(axis_canvas), 0, 0, view, AMITK_LAYOUT_LINEAR, AXIS_WIDTH, AXIS_HEIGHT); gtk_widget_set_size_request(axis_canvas, AXIS_WIDTH, AXIS_HEIGHT); gnome_canvas_set_scroll_region(GNOME_CANVAS(axis_canvas), 0.0, 0.0, 3.0*AXIS_WIDTH, AXIS_HEIGHT); gtk_table_attach(GTK_TABLE(middle_table), axis_canvas, 0,3,m_table_row,m_table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row=0; table_column+=1; /* a separator for clarity */ vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(table), vseparator, table_column, table_column+1, table_row, NUM_ROWS, 0, GTK_FILL, X_PADDING, Y_PADDING); table_row=0; table_column += 1; /* the threshold */ tb_crop->threshold[view] = amitk_threshold_new(tb_crop->projections[view], AMITK_THRESHOLD_LINEAR_LAYOUT, GTK_WINDOW(tb_crop->dialog), TRUE); gtk_table_attach(GTK_TABLE(table), tb_crop->threshold[view], table_column,table_column+1,table_row,NUM_ROWS, FALSE,FALSE, X_PADDING, Y_PADDING); gtk_widget_show_all(table); return table; } static GtkWidget * create_conversion_page(tb_crop_t * tb_crop) { GtkWidget * table; GtkWidget * label; gint table_row; AmitkFormat i_format; AmitkScalingType i_scaling_type; GtkWidget * entry; GtkWidget * menu; GtkWidget * hseparator; table = gtk_table_new(3,3,FALSE); table_row = 0; /* widget to tell you the internal data format */ label = gtk_label_new(_("Current Data Format:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), amitk_format_names[AMITK_DATA_SET_FORMAT(tb_crop->data_set)]); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(table), entry, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); /* widget to tell you the scaling format */ label = gtk_label_new(_("Current Scale Format:")); gtk_table_attach(GTK_TABLE(table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), amitk_scaling_menu_names[AMITK_DATA_SET_SCALING_TYPE(tb_crop->data_set)]); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_table_attach(GTK_TABLE(table), entry, 4,5, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator,0,5, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* widget to tell you the internal data format */ label = gtk_label_new(_("Output Data Format:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_format=0; i_formatformat); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(change_format_cb), tb_crop); gtk_table_attach(GTK_TABLE(table), menu, 1,2, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); /* widget to tell you the scaling format */ label = gtk_label_new(_("Output Scale Format:")); gtk_table_attach(GTK_TABLE(table), label, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_scaling_type=0; i_scaling_typescaling_type); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(change_scaling_type_cb), tb_crop); gtk_table_attach(GTK_TABLE(table), menu, 4,5, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show_all(table); return table; } static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data) { tb_crop_t * tb_crop = data; which_page_t which_page; AmitkView view; AmitkDim i_dim; range_t i_range; which_page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(page), "which_page")); view = which_page-TRANSVERSE_PAGE; /* ---------------- set entries appropriately ---------------- */ switch(which_page) { case TRANSVERSE_PAGE: case CORONAL_PAGE: case SAGITTAL_PAGE: g_signal_handlers_block_by_func(G_OBJECT(tb_crop->zoom_spinner[view]), G_CALLBACK(zoom_spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->zoom_spinner[view]), tb_crop->zoom); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->zoom_spinner[view]), G_CALLBACK(zoom_spinner_cb), tb_crop); if (AMITK_DATA_SET_NUM_GATES(tb_crop->data_set) > 1) { g_signal_handlers_block_by_func(G_OBJECT(tb_crop->gate_spinner[view]), G_CALLBACK(gate_spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->gate_spinner[view]), tb_crop->gate); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->gate_spinner[view]), G_CALLBACK(gate_spinner_cb), tb_crop); } if (AMITK_DATA_SET_NUM_FRAMES(tb_crop->data_set) > 1) { g_signal_handlers_block_by_func(G_OBJECT(tb_crop->frame_spinner[view]), G_CALLBACK(frame_spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->frame_spinner[view]), tb_crop->frame); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->frame_spinner[view]), G_CALLBACK(frame_spinner_cb), tb_crop); } for (i_dim=0; i_dimdata_set), i_dim) > 1) { for (i_range=0; i_rangespinner[view][i_dim][i_range]), G_CALLBACK(spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->spinner[view][i_dim][i_range]), voxel_get_dim(tb_crop->range[i_range], i_dim)); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->spinner[view][i_dim][i_range]), G_CALLBACK(spinner_cb), tb_crop); } } } gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(tb_crop->canvas[view]), tb_crop->zoom); gtk_widget_set_size_request(tb_crop->canvas[view], tb_crop->zoom*tb_crop->canvas_width[view], tb_crop->zoom*tb_crop->canvas_height[view]); add_canvas_update(tb_crop, view); update_crop_lines(tb_crop, view); update_mm_labels(tb_crop, view); amitk_data_set_set_color_table(tb_crop->projections[view], AMITK_VIEW_MODE_SINGLE, tb_crop->color_table); amitk_data_set_set_threshold_min(tb_crop->projections[view], 0, tb_crop->threshold_min); amitk_data_set_set_threshold_max(tb_crop->projections[view], 0, tb_crop->threshold_max); break; default: break; } return; } static void zoom_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_crop_t * tb_crop = data; AmitkView view; gdouble value; value = gtk_spin_button_get_value(spin_button); view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "which_view")); if (value < 0.2) tb_crop->zoom = 0.2; else if (value >= 5.0) tb_crop->zoom = 5.0; else tb_crop->zoom = value; gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(tb_crop->canvas[view]), tb_crop->zoom); gtk_widget_set_size_request(tb_crop->canvas[view], tb_crop->zoom*tb_crop->canvas_width[view], tb_crop->zoom*tb_crop->canvas_height[view]); return; } static void frame_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_crop_t * tb_crop = data; AmitkView view; AmitkView i_view; gint int_value; int_value = gtk_spin_button_get_value_as_int(spin_button); view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "which_view")); if (int_value < 0) int_value = 0; else if (int_value >= AMITK_DATA_SET_NUM_FRAMES(tb_crop->data_set)) int_value = AMITK_DATA_SET_NUM_FRAMES(tb_crop->data_set)-1; if (int_value != tb_crop->frame) { tb_crop->frame = int_value; g_signal_handlers_block_by_func(G_OBJECT(tb_crop->frame_spinner[view]), G_CALLBACK(frame_spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->frame_spinner[view]), tb_crop->frame); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->frame_spinner[view]), G_CALLBACK(frame_spinner_cb), tb_crop); /* unref all the computed projections */ for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) if (tb_crop->projections[i_view] != NULL) tb_crop->projections[i_view] = amitk_object_unref(tb_crop->projections[i_view]); /* just update the current projection for now */ add_canvas_update(tb_crop, view); } return; } static void gate_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_crop_t * tb_crop = data; AmitkView view; AmitkView i_view; gint int_value; int_value = gtk_spin_button_get_value_as_int(spin_button); view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "which_view")); if (int_value < 0) int_value = 0; else if (int_value >= AMITK_DATA_SET_NUM_GATES(tb_crop->data_set)) int_value = AMITK_DATA_SET_NUM_GATES(tb_crop->data_set)-1; if (int_value != tb_crop->gate) { tb_crop->gate = int_value; g_signal_handlers_block_by_func(G_OBJECT(tb_crop->gate_spinner[view]), G_CALLBACK(gate_spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->gate_spinner[view]), tb_crop->gate); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->gate_spinner[view]), G_CALLBACK(gate_spinner_cb), tb_crop); /* unref all the computed projections */ for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) if (tb_crop->projections[i_view] != NULL) tb_crop->projections[i_view] = amitk_object_unref(tb_crop->projections[i_view]); /* just update the current projection for now */ add_canvas_update(tb_crop, view); } return; } static void spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_crop_t * tb_crop = data; AmitkView view; AmitkDim dim; range_t which_range; gint int_value; view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "which_view")); dim = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "which_dim")); which_range = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "which_range")); int_value = gtk_spin_button_get_value_as_int(spin_button); if (which_range == RANGE_MIN) { if (int_value > voxel_get_dim(tb_crop->range[RANGE_MAX], dim)) { int_value = voxel_get_dim(tb_crop->range[RANGE_MAX], dim); } } else { /* RANGE_MAX */ if (int_value < voxel_get_dim(tb_crop->range[RANGE_MIN], dim)) { int_value = voxel_get_dim(tb_crop->range[RANGE_MIN], dim); } } voxel_set_dim(&(tb_crop->range[which_range]), dim, int_value); g_signal_handlers_block_by_func(G_OBJECT(tb_crop->spinner[view][dim][which_range]), G_CALLBACK(spinner_cb), tb_crop); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_crop->spinner[view][dim][which_range]), voxel_get_dim(tb_crop->range[which_range], dim)); g_signal_handlers_unblock_by_func(G_OBJECT(tb_crop->spinner[view][dim][which_range]), G_CALLBACK(spinner_cb), tb_crop); update_crop_lines(tb_crop, view); update_mm_labels(tb_crop, view); return; } static void projection_thresholds_changed_cb(AmitkDataSet * projection, gpointer data) { tb_crop_t * tb_crop = data; AmitkView view; view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(projection), "which_view")); tb_crop->threshold_max = AMITK_DATA_SET_THRESHOLD_MAX(projection, 0); tb_crop->threshold_min = AMITK_DATA_SET_THRESHOLD_MIN(projection, 0); add_canvas_update(tb_crop, view); update_crop_lines(tb_crop, view); return; } static void projection_color_table_changed_cb(AmitkDataSet * projection, AmitkViewMode view_mode, gpointer data) { tb_crop_t * tb_crop = data; AmitkView view; if (view_mode == AMITK_VIEW_MODE_SINGLE) { view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(projection), "which_view")); tb_crop->color_table = AMITK_DATA_SET_COLOR_TABLE(projection, AMITK_VIEW_MODE_SINGLE); add_canvas_update(tb_crop, view); update_crop_lines(tb_crop, view); } return; } /* function called to change the desired format */ static void change_format_cb(GtkWidget * widget, gpointer data) { tb_crop_t * tb_crop = data; tb_crop->format = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); return; } /* function called to change the desired scaling */ static void change_scaling_type_cb(GtkWidget * widget, gpointer data) { tb_crop_t * tb_crop = data; tb_crop->scaling_type = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); return; } static void update_mm_labels(tb_crop_t * tb_crop, AmitkView view) { AmitkPoint temp_rp; range_t i_range; AmitkDim i_dim; gchar * temp_string; for (i_range=0; i_rangerange[i_range], AMITK_DATA_SET_VOXEL_SIZE(tb_crop->data_set), temp_rp); temp_rp = amitk_space_s2b(AMITK_SPACE(tb_crop->data_set), temp_rp); for (i_dim=0; i_dim<=AMITK_DIM_Z; i_dim++) { if (voxel_get_dim(AMITK_DATA_SET_DIM(tb_crop->data_set), i_dim) > 1) { temp_string = g_strdup_printf("%g", point_get_component(temp_rp, i_dim)); gtk_label_set_text(GTK_LABEL(tb_crop->mm_label[view][i_dim][i_range]), temp_string); g_free(temp_string); } } } return; } static void update_crop_lines(tb_crop_t * tb_crop, AmitkView view) { GnomeCanvasPoints * points; range_t i_range; rgba_t outline_color; gint j; gint x_range[NUM_RANGES]; gint y_range[NUM_RANGES]; if (tb_crop->canvas[view] == NULL) return; points = gnome_canvas_points_new(2); outline_color = amitk_color_table_outline_color(AMITK_DATA_SET_COLOR_TABLE(tb_crop->projections[view], AMITK_VIEW_MODE_SINGLE), FALSE); switch(view) { case AMITK_VIEW_CORONAL: for (i_range=0; i_rangerange[i_range].x; y_range[i_range] = tb_crop->range[i_range].z; } break; case AMITK_VIEW_SAGITTAL: for (i_range=0; i_rangerange[i_range].y; y_range[i_range] = tb_crop->range[i_range].z; } break; case AMITK_VIEW_TRANSVERSE: default: for (i_range=0; i_rangerange[i_range].x; y_range[i_range] = tb_crop->range[i_range].y; } break; } for (j=0; j<2; j++) { for (i_range=0; i_rangecoords[0]=points->coords[2] = x_range[i_range]+0.5; else points->coords[0]=points->coords[2] = x_range[i_range]+0.5+2*CURSOR_SIZE; if (view == AMITK_VIEW_TRANSVERSE) { points->coords[1] = tb_crop->canvas_height[view]-y_range[RANGE_MIN]-1+0.5-CURSOR_SIZE; points->coords[3] = tb_crop->canvas_height[view]-y_range[RANGE_MAX]-1+0.5-CURSOR_SIZE; } else { /* our z direction points down */ points->coords[1] = y_range[RANGE_MIN]+0.5; points->coords[3] = y_range[RANGE_MAX]+0.5+2*CURSOR_SIZE; } } else { /* y direction, compensate for X Window's coordinate axis */ if (i_range == RANGE_MIN) { if (view == AMITK_VIEW_TRANSVERSE) points->coords[1]=points->coords[3] = tb_crop->canvas_height[view]-y_range[i_range]+0.5-CURSOR_SIZE; else /* our z direction points down */ points->coords[1]=points->coords[3] = y_range[i_range]+0.5; } else { if (view == AMITK_VIEW_TRANSVERSE) points->coords[1]=points->coords[3] = tb_crop->canvas_height[view]-y_range[i_range]-1+0.5-2*CURSOR_SIZE; else /* our z direction points down */ points->coords[1]=points->coords[3] = y_range[i_range]+0.5+2*CURSOR_SIZE; } points->coords[0] = x_range[RANGE_MIN]+0.5; points->coords[2] = x_range[RANGE_MAX]+0.5+2*CURSOR_SIZE; } if (tb_crop->line[view][j][i_range] == NULL) { tb_crop->line[view][j][i_range] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_crop->canvas[view])), gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", amitk_color_table_rgba_to_uint32(outline_color), "width_units", 1.0, "cap_style", GDK_CAP_PROJECTING, NULL); } else { gnome_canvas_item_set(tb_crop->line[view][j][i_range], "points", points, "fill_color_rgba", amitk_color_table_rgba_to_uint32(outline_color),NULL); } } } gnome_canvas_points_unref(points); return; } static void add_canvas_update(tb_crop_t * tb_crop, AmitkView view) { if (g_list_index(tb_crop->update_view, GINT_TO_POINTER(view)) < 0) tb_crop->update_view = g_list_append(tb_crop->update_view, GINT_TO_POINTER(view)); if (tb_crop->idle_handler_id == 0) tb_crop->idle_handler_id = g_idle_add_full(G_PRIORITY_HIGH_IDLE,update_canvas_while_idle, tb_crop, NULL); } static gboolean update_canvas_while_idle(gpointer data) { tb_crop_t * tb_crop = data; GdkPixbuf * pixbuf; AmitkView view, i_view; while (tb_crop->update_view != NULL) { view = GPOINTER_TO_INT(tb_crop->update_view->data); tb_crop->update_view = g_list_remove(tb_crop->update_view, GINT_TO_POINTER(view)); /* create the projections if we haven't already */ if (tb_crop->projections[view] == NULL) amitk_data_set_get_projections(tb_crop->data_set, tb_crop->frame, tb_crop->gate, tb_crop->projections, amitk_progress_dialog_update, tb_crop->progress_dialog); for (i_view=0; i_viewprojections[i_view] != NULL) { if (!tb_crop->threshold_info_set) { tb_crop->threshold_info_set = TRUE; tb_crop->color_table = AMITK_DATA_SET_COLOR_TABLE(tb_crop->projections[i_view], AMITK_VIEW_MODE_SINGLE); tb_crop->threshold_max = AMITK_DATA_SET_THRESHOLD_MAX(tb_crop->projections[i_view], 0); tb_crop->threshold_min = AMITK_DATA_SET_THRESHOLD_MIN(tb_crop->projections[i_view], 0); } else { amitk_data_set_set_color_table(tb_crop->projections[i_view], AMITK_VIEW_MODE_SINGLE, tb_crop->color_table ); amitk_data_set_set_threshold_max(tb_crop->projections[i_view], 0, tb_crop->threshold_max); amitk_data_set_set_threshold_min(tb_crop->projections[i_view], 0, tb_crop->threshold_min); } g_object_set_data(G_OBJECT(tb_crop->projections[i_view]), "which_view", GINT_TO_POINTER(i_view)); g_signal_connect(G_OBJECT(tb_crop->projections[i_view]), "thresholds_changed", G_CALLBACK(projection_thresholds_changed_cb), tb_crop); g_signal_connect(G_OBJECT(tb_crop->projections[i_view]), "color_table_changed", G_CALLBACK(projection_color_table_changed_cb), tb_crop); // if (tb_crop->threshold[i_view] != NULL) // amitk_threshold_new_data_set(AMITK_THRESHOLD(tb_crop->threshold[i_view]), // tb_crop->projections[i_view]); } } if ((tb_crop->canvas[view] != NULL) && (tb_crop->projections[view] != NULL)) { /* make a pixbuf based on the projection */ pixbuf = image_from_projection(tb_crop->projections[view]); if (tb_crop->image[view] == NULL) {/* create the canvas image if we don't have it */ tb_crop->image[view] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_crop->canvas[view])), gnome_canvas_pixbuf_get_type(), "pixbuf", pixbuf, "x", (gdouble) CURSOR_SIZE, "y", (gdouble) CURSOR_SIZE, NULL); tb_crop->canvas_width[view] =gdk_pixbuf_get_width(pixbuf)+2*CURSOR_SIZE; tb_crop->canvas_height[view] = gdk_pixbuf_get_height(pixbuf)+2*CURSOR_SIZE; gtk_widget_set_size_request(tb_crop->canvas[view], tb_crop->canvas_width[view], tb_crop->canvas_height[view]); gnome_canvas_set_scroll_region(GNOME_CANVAS(tb_crop->canvas[view]), 0,0, tb_crop->canvas_width[view], tb_crop->canvas_height[view]); } else { gnome_canvas_item_set(tb_crop->image[view], "pixbuf", pixbuf, NULL); } g_object_unref(pixbuf); } } tb_crop->idle_handler_id=0; return FALSE; } static tb_crop_t * tb_crop_free(tb_crop_t * tb_crop) { AmitkView i_view; gboolean return_val; /* sanity checks */ g_return_val_if_fail(tb_crop != NULL, NULL); g_return_val_if_fail(tb_crop->reference_count > 0, NULL); /* remove a reference count */ tb_crop->reference_count--; /* things to do if we've removed all reference's */ if (tb_crop->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_crop\n"); #endif if (tb_crop->idle_handler_id != 0) { g_source_remove(tb_crop->idle_handler_id); tb_crop->idle_handler_id = 0; } if (tb_crop->data_set != NULL) { amitk_object_unref(tb_crop->data_set); tb_crop->data_set = NULL; } if (tb_crop->study != NULL) { amitk_object_unref(tb_crop->study); tb_crop->study = NULL; } for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) { if (tb_crop->projections[i_view] != NULL) { amitk_object_unref(tb_crop->projections[i_view]); tb_crop->projections[i_view] = NULL; } } if (tb_crop->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_crop->progress_dialog), "delete_event", NULL, &return_val); tb_crop->progress_dialog = NULL; } g_free(tb_crop); tb_crop = NULL; } #ifdef AMIDE_DEBUG else { g_print("unrefering tb_crop\n"); } #endif return tb_crop; } static tb_crop_t * tb_crop_init(void) { AmitkView i_view; tb_crop_t * tb_crop; gint j; range_t i_range; /* alloc space for the data structure for passing ui info */ if ((tb_crop = g_try_new(tb_crop_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_crop_t")); return NULL; } tb_crop->reference_count = 1; tb_crop->frame = 0; tb_crop->gate=0; tb_crop->dialog = NULL; tb_crop->data_set = NULL; tb_crop->study = NULL; tb_crop->zoom = 1.0; tb_crop->threshold_info_set = FALSE; tb_crop->format = AMITK_FORMAT_FLOAT; tb_crop->scaling_type = AMITK_SCALING_TYPE_0D; for (i_range=0; i_rangerange[i_range] = zero_voxel; for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) { tb_crop->image[i_view] = NULL; tb_crop->projections[i_view] = NULL; tb_crop->threshold[i_view] = NULL; tb_crop->canvas[i_view]=NULL; for (j=0; j<2; j++) for (i_range=0; i_rangeline[i_view][j][i_range]=NULL; } tb_crop->update_view=NULL; tb_crop->idle_handler_id = 0; return tb_crop; } void tb_crop(AmitkStudy * study, AmitkDataSet * active_ds, GtkWindow * parent) { tb_crop_t * tb_crop; GdkPixbuf * logo; AmitkView i_view; gint i; if (active_ds == NULL) { g_warning(_("No data set is currently marked as active")); return; } tb_crop = tb_crop_init(); tb_crop->study = amitk_object_ref(study); tb_crop->data_set = amitk_object_ref(active_ds); tb_crop->format = AMITK_DATA_SET_FORMAT(active_ds); tb_crop->scaling_type = AMITK_DATA_SET_SCALING_TYPE(active_ds); tb_crop->frame = amitk_data_set_get_frame(active_ds, AMITK_STUDY_VIEW_START_TIME(study)); tb_crop->gate = AMITK_DATA_SET_VIEW_START_GATE(active_ds); tb_crop->dialog = gtk_assistant_new(); gtk_window_set_transient_for(GTK_WINDOW(tb_crop->dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW(tb_crop->dialog), TRUE); g_signal_connect(G_OBJECT(tb_crop->dialog), "cancel", G_CALLBACK(close_cb), tb_crop); g_signal_connect(G_OBJECT(tb_crop->dialog), "close", G_CALLBACK(close_cb), tb_crop); g_signal_connect(G_OBJECT(tb_crop->dialog), "apply", G_CALLBACK(apply_cb), tb_crop); g_signal_connect(G_OBJECT(tb_crop->dialog), "prepare", G_CALLBACK(prepare_page_cb), tb_crop); tb_crop->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_crop->dialog)); tb_crop->range[RANGE_MAX] = voxel_sub(AMITK_DATA_SET_DIM(tb_crop->data_set), one_voxel); /* setup the projection pages */ for (i_view=0; i_viewpage[i_view] = create_projection_page(tb_crop, i_view); gtk_assistant_append_page(GTK_ASSISTANT(tb_crop->dialog), tb_crop->page[i_view]); } /* setup the conversion page */ tb_crop->page[CONVERSION_PAGE] = create_conversion_page(tb_crop); gtk_assistant_append_page(GTK_ASSISTANT(tb_crop->dialog), tb_crop->page[CONVERSION_PAGE]); /* setup the conclusion page */ tb_crop->page[FINISH_PAGE] = gtk_label_new(_(finish_page_text)); gtk_assistant_append_page(GTK_ASSISTANT(tb_crop->dialog), tb_crop->page[FINISH_PAGE]); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_crop->dialog), tb_crop->page[FINISH_PAGE], GTK_ASSISTANT_PAGE_CONFIRM); /* set the title, icon, and other info */ logo = gtk_widget_render_icon(GTK_WIDGET(tb_crop->dialog), "amide_icon_logo", GTK_ICON_SIZE_DIALOG, 0); for (i=0; idialog), tb_crop->page[i], _("Data Set Cropping Wizard")); gtk_assistant_set_page_header_image(GTK_ASSISTANT(tb_crop->dialog), tb_crop->page[i], logo); g_object_set_data(G_OBJECT(tb_crop->page[i]),"which_page", GINT_TO_POINTER(i)); /* by default, everything's finished in this wizard */ gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_crop->dialog), tb_crop->page[i], TRUE); } g_object_unref(logo); gtk_widget_show_all(tb_crop->dialog); return; } amide-1.0.6/amide-current/src/tb_crop.h000066400000000000000000000020341423227705100177260ustar00rootroot00000000000000/* tb_crop.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_study.h" /* external functions */ void tb_crop(AmitkStudy * study, AmitkDataSet * active_ds, GtkWindow * parent_window); amide-1.0.6/amide-current/src/tb_distance.c000066400000000000000000000273371423227705100205650ustar00rootroot00000000000000/* tb_distance.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2012-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_tree_view.h" gchar * explanation_text = N_("To make a distance measurement, pick two objects (fiducial marks or ROIs). " "For ROIs, the distance measurement will be with respect to the center of " "the ROI."); typedef struct tb_distance_t { GtkWidget * dialog; GtkTextBuffer * result_text_buffer; GtkWidget * tree_view1; GtkWidget * tree_view2; AmitkObject * object1; AmitkObject * object2; guint reference_count; } tb_distance_t; static tb_distance_t * tb_distance_free(tb_distance_t * tb_distance); static tb_distance_t * tb_distance_init(void); static void corner_changed_cb(gpointer unused1, AmitkPoint * unused2, gpointer data); static void space_changed_cb(gpointer unused, gpointer data); static void update_result_text(tb_distance_t * tb_distance); static void update_objects(tb_distance_t * tb_distance); static void tree_view_activate_object(GtkWidget * tree_view, AmitkObject * object, gpointer data); static void destroy_cb(GtkObject * object, gpointer data); static void response_cb (GtkDialog * dialog, gint response_id, gpointer data); static tb_distance_t * tb_distance_free(tb_distance_t * tb_distance) { /* sanity checks */ g_return_val_if_fail(tb_distance != NULL, NULL); g_return_val_if_fail(tb_distance->reference_count > 0, NULL); /* remove a reference count */ tb_distance->reference_count--; /* things to do if we've removed all references */ if (tb_distance->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_distance\n"); #endif if (tb_distance->object1 != NULL) { if (AMITK_IS_ROI(tb_distance->object1)) g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object1), corner_changed_cb, tb_distance); g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object1), space_changed_cb, tb_distance); amitk_object_unref(tb_distance->object1); tb_distance->object1 = NULL; } if (tb_distance->object2 != NULL) { if (AMITK_IS_ROI(tb_distance->object2)) g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object2), corner_changed_cb, tb_distance); g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object2), space_changed_cb, tb_distance); amitk_object_unref(tb_distance->object2); tb_distance->object2 = NULL; } g_free(tb_distance); tb_distance = NULL; } return tb_distance; } static tb_distance_t * tb_distance_init(void) { tb_distance_t * tb_distance; if ((tb_distance = g_try_new(tb_distance_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_distance_t")); return NULL; } tb_distance->reference_count=1; tb_distance->object1 = NULL; tb_distance->object2 = NULL; return tb_distance; } static void corner_changed_cb(gpointer unused1, AmitkPoint * unused2, gpointer data) { tb_distance_t * tb_distance = data; update_result_text(tb_distance); return; } static void space_changed_cb(gpointer unused, gpointer data) { tb_distance_t * tb_distance = data; update_result_text(tb_distance); return; } static void update_result_text(tb_distance_t * tb_distance) { AmitkPoint point1; AmitkPoint point2; amide_real_t distance; gchar * temp_string; if ((tb_distance->object1 == NULL) || (tb_distance->object2 == NULL) || (tb_distance->object1 == tb_distance->object2)) { gtk_text_buffer_set_text (tb_distance->result_text_buffer, _(explanation_text), -1); } else { /* allright, have two good objects, let's calculate distance */ if (AMITK_IS_ROI(tb_distance->object1)) point1 = amitk_volume_get_center(AMITK_VOLUME(tb_distance->object1)); else /* is fiducial */ point1 = AMITK_FIDUCIAL_MARK_GET(tb_distance->object1); if (AMITK_IS_ROI(tb_distance->object2)) point2 = amitk_volume_get_center(AMITK_VOLUME(tb_distance->object2)); else /* is fiducial */ point2 = AMITK_FIDUCIAL_MARK_GET(tb_distance->object2); distance = point_mag(point_sub(point1, point2)); temp_string = g_strdup_printf("Point1: %s\nPoint2: %s\nDistance %5.3f (mm)", AMITK_OBJECT_NAME(tb_distance->object1), AMITK_OBJECT_NAME(tb_distance->object2), distance); gtk_text_buffer_set_text(tb_distance->result_text_buffer, temp_string, -1); g_free(temp_string); } } static void update_objects(tb_distance_t * tb_distance) { AmitkObject * object; /* unref prior objects */ if (tb_distance->object1 != NULL) { if (AMITK_IS_ROI(tb_distance->object1)) g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object1), corner_changed_cb, tb_distance); g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object1), space_changed_cb, tb_distance); tb_distance->object1=amitk_object_unref(tb_distance->object1); } if (tb_distance->object2 != NULL) { if (AMITK_IS_ROI(tb_distance->object2)) g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object2), corner_changed_cb, tb_distance); g_signal_handlers_disconnect_by_func(G_OBJECT(tb_distance->object2), space_changed_cb, tb_distance); tb_distance->object2=amitk_object_unref(tb_distance->object2); } /* reference the new objects */ object = amitk_tree_view_get_active_object(AMITK_TREE_VIEW(tb_distance->tree_view1)); if (object != NULL) if ((AMITK_IS_ROI(object) || AMITK_IS_FIDUCIAL_MARK(object))) { tb_distance->object1=amitk_object_ref(object); if (AMITK_IS_VOLUME(object)) g_signal_connect_after(G_OBJECT(object), "volume_corner_changed", G_CALLBACK(corner_changed_cb), tb_distance); g_signal_connect_after(G_OBJECT(object), "space_changed", G_CALLBACK(space_changed_cb), tb_distance); } object = amitk_tree_view_get_active_object(AMITK_TREE_VIEW(tb_distance->tree_view2)); if (object != NULL) if ((AMITK_IS_ROI(object) || AMITK_IS_FIDUCIAL_MARK(object))) { tb_distance->object2=amitk_object_ref(object); if (AMITK_IS_VOLUME(object)) g_signal_connect_after(G_OBJECT(object), "volume_corner_changed", G_CALLBACK(corner_changed_cb), tb_distance); g_signal_connect_after(G_OBJECT(object), "space_changed", G_CALLBACK(space_changed_cb), tb_distance); } update_result_text(tb_distance); return; } static void tree_view_activate_object(GtkWidget * tree_view, AmitkObject * object, gpointer data) { tb_distance_t * tb_distance = data; if (AMITK_IS_ROI(object) || AMITK_IS_FIDUCIAL_MARK(object)) amitk_tree_view_set_active_object(AMITK_TREE_VIEW(tree_view), object); else amitk_tree_view_set_active_object(AMITK_TREE_VIEW(tree_view), NULL); update_objects(tb_distance); } static void destroy_cb(GtkObject * object, gpointer data) { tb_distance_t * tb_distance = data; tb_distance = tb_distance_free(tb_distance); return; } static void response_cb (GtkDialog * dialog, gint response_id, gpointer data) { switch(response_id) { case GTK_RESPONSE_CANCEL: gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } void tb_distance(AmitkStudy * study, GtkWindow * parent_window) { GtkWidget * table; GtkWidget * label; GtkWidget * scrolled; GtkWidget * text_view; guint table_row=0; tb_distance_t * tb_distance; tb_distance = tb_distance_init(); tb_distance->dialog = gtk_dialog_new_with_buttons(_("Distance Measurement Tool"), parent_window, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); g_signal_connect(G_OBJECT(tb_distance->dialog), "destroy", G_CALLBACK(destroy_cb), tb_distance); g_signal_connect(G_OBJECT(tb_distance->dialog), "response", G_CALLBACK(response_cb), tb_distance); gtk_window_set_resizable(GTK_WINDOW(tb_distance->dialog), TRUE); /* make the widgets for this dialog box */ table = gtk_table_new(2,3,FALSE); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(tb_distance->dialog)->vbox), table); label = gtk_label_new(_("Starting Point")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("Ending Point")); gtk_table_attach(GTK_TABLE(table), label, 1,2, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* make the starting point tree view */ tb_distance->tree_view1 = amitk_tree_view_new(AMITK_TREE_VIEW_MODE_SINGLE_SELECTION,NULL, NULL); amitk_tree_view_set_study(AMITK_TREE_VIEW(tb_distance->tree_view1), study); amitk_tree_view_expand_object(AMITK_TREE_VIEW(tb_distance->tree_view1), AMITK_OBJECT(study)); g_signal_connect(G_OBJECT(tb_distance->tree_view1), "activate_object", G_CALLBACK(tree_view_activate_object), tb_distance); /* and a scrolled area for the tree */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,250,250); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), tb_distance->tree_view1); gtk_table_attach(GTK_TABLE(table), scrolled, 0,1, table_row, table_row+1,GTK_FILL, GTK_FILL | GTK_EXPAND, X_PADDING, Y_PADDING); /* and make the ending point tree view */ tb_distance->tree_view2 = amitk_tree_view_new(AMITK_TREE_VIEW_MODE_SINGLE_SELECTION,NULL, NULL); amitk_tree_view_set_study(AMITK_TREE_VIEW(tb_distance->tree_view2), study); amitk_tree_view_expand_object(AMITK_TREE_VIEW(tb_distance->tree_view2), AMITK_OBJECT(study)); g_signal_connect(G_OBJECT(tb_distance->tree_view2), "activate_object", G_CALLBACK(tree_view_activate_object), tb_distance); /* and a scrolled area for the tree */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,250,250); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), tb_distance->tree_view2); gtk_table_attach(GTK_TABLE(table), scrolled, 1,2, table_row, table_row+1,GTK_FILL, GTK_FILL | GTK_EXPAND, X_PADDING, Y_PADDING); table_row++; /* and finally, the result buffer */ text_view = gtk_text_view_new(); tb_distance->result_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); update_result_text(tb_distance); gtk_table_attach(GTK_TABLE(table), text_view, 0,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_WORD); gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE); gtk_widget_set_size_request(text_view,400,-1); table_row++; gtk_widget_show_all(GTK_WIDGET(tb_distance->dialog)); /* needed, as the process of showing selects an object in the tree view */ amitk_tree_view_set_active_object(AMITK_TREE_VIEW(tb_distance->tree_view1), NULL); /* make sure nothing selected */ amitk_tree_view_set_active_object(AMITK_TREE_VIEW(tb_distance->tree_view2), NULL); /* make sure nothing selected */ return; } amide-1.0.6/amide-current/src/tb_distance.h000066400000000000000000000020041423227705100205520ustar00rootroot00000000000000/* tb_distance.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2012-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_study.h" /* external functions */ void tb_distance(AmitkStudy * study, GtkWindow * parent); amide-1.0.6/amide-current/src/tb_export_data_set.c000066400000000000000000000603751423227705100221570ustar00rootroot00000000000000/* tb_export_data_set.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2006-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amide.h" #include "amide_gconf.h" #include "amitk_progress_dialog.h" #include "tb_export_data_set.h" #ifdef AMIDE_LIBMDC_SUPPORT #include "libmdc_interface.h" #endif #ifdef AMIDE_LIBDCMDATA_SUPPORT #include "dcmtk_interface.h" #endif #define GCONF_AMIDE_EXPORT "EXPORT" typedef struct tb_export_t { AmitkStudy * study; AmitkDataSet * active_ds; AmitkPreferences * preferences; GtkWidget * dialog; GtkWidget * progress_dialog; GtkWidget * vs_spin_button[AMITK_AXIS_NUM]; GtkWidget * bb_radio_button[2]; guint reference_count; } tb_export_t; static tb_export_t * tb_export_unref(tb_export_t * tb_export) { g_return_val_if_fail(tb_export != NULL, NULL); gboolean return_val; /* sanity checks */ g_return_val_if_fail(tb_export->reference_count > 0, NULL); /* remove a reference count */ tb_export->reference_count--; /* things to do if we've removed all reference's */ if (tb_export->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_export\n"); #endif if (tb_export->study != NULL) { amitk_object_unref(tb_export->study); tb_export->study = NULL; } if (tb_export->active_ds != NULL) { amitk_object_unref(tb_export->active_ds); tb_export->active_ds = NULL; } if (tb_export->preferences != NULL) { g_object_unref(tb_export->preferences); tb_export->preferences = NULL; } if (tb_export->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_export->progress_dialog), "delete_event", NULL, &return_val); tb_export->progress_dialog = NULL; } g_free(tb_export); tb_export = NULL; } return tb_export; } /* allocate and initialize a tb_export data structure */ static tb_export_t * tb_export_init(void) { tb_export_t * tb_export; /* alloc space for the data structure for passing ui info */ if ((tb_export = g_try_new(tb_export_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_export_t")); return NULL; } tb_export->reference_count = 1; /* set any needed parameters */ tb_export->study = NULL; tb_export->active_ds = NULL; tb_export->preferences = NULL; tb_export->progress_dialog = NULL; return tb_export; } static void destroy_cb(GtkObject * object, gpointer data) { tb_export_t * tb_export = data; tb_export = tb_export_unref(tb_export); /* free the associated data structure */ } static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { // tb_export_t * tb_export = data; return FALSE; } static void read_preferences(gboolean * resliced, gboolean * all_visible, gboolean * inclusive_bounding_box, AmitkExportMethod * method, gint * submethod, AmitkPoint * voxel_size) { if (resliced != NULL) *resliced = amide_gconf_get_bool(GCONF_AMIDE_EXPORT,"ResliceDataSet"); if (all_visible != NULL) *all_visible = amide_gconf_get_bool(GCONF_AMIDE_EXPORT,"AllVisibleDataSets"); if (inclusive_bounding_box != NULL) *inclusive_bounding_box = amide_gconf_get_bool(GCONF_AMIDE_EXPORT,"InclusiveBoundingBox"); if (method != NULL) *method = amide_gconf_get_int(GCONF_AMIDE_EXPORT,"Method"); if (submethod != NULL) *submethod = amide_gconf_get_int(GCONF_AMIDE_EXPORT,"Submethod"); if (voxel_size != NULL) { (*voxel_size).z = amide_gconf_get_float(GCONF_AMIDE_EXPORT,"VoxelSizeZ"); if (EQUAL_ZERO((*voxel_size).z)) (*voxel_size).z = 1.0; (*voxel_size).y = amide_gconf_get_float(GCONF_AMIDE_EXPORT,"VoxelSizeY"); if (EQUAL_ZERO((*voxel_size).y)) (*voxel_size).y = 1.0; (*voxel_size).x = amide_gconf_get_float(GCONF_AMIDE_EXPORT,"VoxelSizeX"); if (EQUAL_ZERO((*voxel_size).x)) (*voxel_size).x = 1.0; } return; } /* function called when we hit "ok" on the export file dialog */ static gboolean export_data_set(tb_export_t * tb_export, gchar * filename) { GList * data_sets; AmitkVolume * bounding_box = NULL; gboolean resliced; gboolean all_visible; gboolean inclusive_bounding_box; AmitkExportMethod method; gint submethod; AmitkPoint voxel_size; gboolean successful = FALSE; g_return_val_if_fail(filename != NULL, FALSE); read_preferences(&resliced, &all_visible, &inclusive_bounding_box, &method, &submethod, &voxel_size); /* get total bounding box if needed */ if (inclusive_bounding_box) { AmitkCorners corner; bounding_box = amitk_volume_new(); /* in base coordinate frame */ g_return_val_if_fail(bounding_box != NULL, FALSE); data_sets = amitk_object_get_children_of_type(AMITK_OBJECT(tb_export->study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); amitk_volumes_get_enclosing_corners(data_sets, AMITK_SPACE(bounding_box), corner); amitk_space_set_offset(AMITK_SPACE(bounding_box), corner[0]); amitk_volume_set_corner(bounding_box, amitk_space_b2s(AMITK_SPACE(bounding_box), corner[1])); amitk_objects_unref(data_sets); } if (!all_visible) { successful = amitk_data_set_export_to_file(tb_export->active_ds, method, submethod, filename, AMITK_OBJECT_NAME(tb_export->study), resliced, voxel_size, bounding_box, amitk_progress_dialog_update, tb_export->progress_dialog); } else { data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(tb_export->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_SELECTED_0, TRUE); if (data_sets == NULL) { g_warning(_("No Data Sets are current visible")); } else { successful = amitk_data_sets_export_to_file(data_sets, method, submethod, filename, AMITK_OBJECT_NAME(tb_export->study), voxel_size, bounding_box, amitk_progress_dialog_update, tb_export->progress_dialog); amitk_objects_unref(data_sets); } } if (bounding_box != NULL) bounding_box = amitk_object_unref(bounding_box); return successful; } static void response_cb (GtkDialog * main_dialog, gint response_id, gpointer data) { tb_export_t * tb_export = data; GtkWidget * file_chooser; gint return_val; gchar * filename; AmitkExportMethod method; gboolean close_dialog=FALSE; switch(response_id) { case AMITK_RESPONSE_EXECUTE: /* the rest of this function runs the file selection dialog box */ file_chooser = gtk_file_chooser_dialog_new(_("Export to File"), GTK_WINDOW(main_dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(tb_export->preferences, file_chooser); /* set the default directory if applicable */ /* for DCMTK dicom files we don't want to complain about file existing, as we might be appending */ read_preferences(NULL, NULL, NULL, &method, NULL, NULL); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_chooser), #ifdef AMIDE_LIBDCMDATA_SUPPORT method!=AMITK_EXPORT_METHOD_DCMTK #else TRUE #endif ); if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy(file_chooser); if (filename == NULL) return; /* return to export dialog */ else { /* export the dataset */ close_dialog = export_data_set(tb_export, filename); /* close if successful */ g_free(filename); } break; case GTK_RESPONSE_CANCEL: close_dialog = TRUE; break; default: break; } if (close_dialog) { g_signal_emit_by_name(G_OBJECT(main_dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(main_dialog)); } return; } static void write_voxel_size(AmitkPoint voxel_size) { amide_gconf_set_float(GCONF_AMIDE_EXPORT,"VoxelSizeZ", voxel_size.z); amide_gconf_set_float(GCONF_AMIDE_EXPORT,"VoxelSizeY", voxel_size.y); amide_gconf_set_float(GCONF_AMIDE_EXPORT,"VoxelSizeX", voxel_size.x); return; } static void write_inclusive_bounding_box(gboolean inclusive) { amide_gconf_set_bool(GCONF_AMIDE_EXPORT,"InclusiveBoundingBox", inclusive); return; } static void change_voxel_size_cb(GtkWidget * widget, gpointer data) { gdouble size; AmitkAxis which_axis; gboolean resliced; gboolean all_visible; gboolean inclusive_bounding_box; AmitkExportMethod method; gint submethod; AmitkPoint voxel_size; read_preferences(&resliced, &all_visible, &inclusive_bounding_box, &method, &submethod, &voxel_size); /* figure out which widget this is */ which_axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "axis")); size = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); switch(which_axis) { case (AMITK_AXIS_X): voxel_size.x = size; break; case (AMITK_AXIS_Y): voxel_size.y = size; break; case (AMITK_AXIS_Z): voxel_size.z = size; break; default: break; /* do nothing */ } write_voxel_size(voxel_size); return; } static void recommend_voxel_size(tb_export_t * tb_export) { GList * data_sets; AmitkAxis i_axis; gboolean resliced; gboolean all_visible; gboolean inclusive_bounding_box; AmitkExportMethod method; gint submethod; AmitkPoint voxel_size; read_preferences(&resliced, &all_visible, &inclusive_bounding_box, &method, &submethod, &voxel_size); if (all_visible) { data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(tb_export->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_SELECTED_0, TRUE); if (data_sets == NULL) { g_warning(_("No Data Sets are current visible")); } else { /* for all visible datasets */ voxel_size.z = voxel_size.y = voxel_size.x = amitk_data_sets_get_min_voxel_size(data_sets); amitk_objects_unref(data_sets); } } else if (resliced) { voxel_size.z = voxel_size.y = voxel_size.x = point_min_dim(AMITK_DATA_SET_VOXEL_SIZE(tb_export->active_ds)); } else {/* if not resliced */ voxel_size = AMITK_DATA_SET_VOXEL_SIZE(tb_export->active_ds); } write_voxel_size(voxel_size); /* update entries */ for (i_axis=0; i_axisvs_spin_button[i_axis])); g_signal_handlers_block_by_func(G_OBJECT(tb_export->vs_spin_button[i_axis]), change_voxel_size_cb, tb_export); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_export->vs_spin_button[i_axis]), point_get_component(voxel_size, i_axis)); g_signal_handlers_unblock_by_func(G_OBJECT(tb_export->vs_spin_button[i_axis]), change_voxel_size_cb, tb_export); } return; } static void reslice_radio_buttons_cb(GtkWidget * widget, gpointer data) { tb_export_t * tb_export = data; AmitkAxis i_axis; gboolean resliced; gboolean all_visible; gboolean inclusive_bounding_box; resliced = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "resliced")); all_visible = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "all_visible")); amide_gconf_set_bool(GCONF_AMIDE_EXPORT,"ResliceDataSet", resliced); amide_gconf_set_bool(GCONF_AMIDE_EXPORT,"AllVisibleDataSets", all_visible); /* recalculate voxel sizes */ recommend_voxel_size(tb_export); /* whether or not we can change the voxel sizes */ for (i_axis=0; i_axisvs_spin_button[i_axis]), resliced || all_visible); } /* whether or not we can change the bounding box type */ gtk_widget_set_sensitive(tb_export->bb_radio_button[0], resliced || all_visible); gtk_widget_set_sensitive(tb_export->bb_radio_button[1], resliced || all_visible); if (!resliced && !all_visible) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_export->bb_radio_button[0]), TRUE); inclusive_bounding_box=FALSE; write_inclusive_bounding_box(inclusive_bounding_box); } return; } static void bb_radio_buttons_cb(GtkWidget * widget, gpointer data) { gboolean inclusive_bounding_box; inclusive_bounding_box = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "inclusive_bounding_box")); write_inclusive_bounding_box(inclusive_bounding_box); return; } /* function called when the export type of a data set gets changed */ static void change_export_cb(GtkWidget * widget, gpointer data) { AmitkExportMethod method=0; gint submethod=0; gint counter; gint combo_method; AmitkImportMethod i_export_method; #ifdef AMIDE_LIBMDC_SUPPORT libmdc_export_t i_libmdc_export; #endif combo_method = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); counter = 0; for (i_export_method = AMITK_EXPORT_METHOD_RAW; i_export_method < AMITK_EXPORT_METHOD_NUM; i_export_method++) { #ifdef AMIDE_LIBMDC_SUPPORT if (i_export_method == AMITK_EXPORT_METHOD_LIBMDC) { for (i_libmdc_export=0; i_libmdc_export < LIBMDC_NUM_EXPORT_METHODS; i_libmdc_export++) { if (libmdc_supports(libmdc_export_to_format[i_libmdc_export])) { if (counter == combo_method) { method = i_export_method; submethod = libmdc_export_to_format[i_libmdc_export]; } counter++; } } } else #endif { if (counter == combo_method) { method = i_export_method; submethod = 0; } counter++; } } amide_gconf_set_int(GCONF_AMIDE_EXPORT,"Method", method); amide_gconf_set_int(GCONF_AMIDE_EXPORT,"Submethod", submethod); return; } /* function to setup a dialog to allow us to choice options for rendering */ void tb_export_data_set(AmitkStudy * study, AmitkDataSet * active_ds, AmitkPreferences * preferences, GtkWindow * parent) { gchar * temp_string; GtkWidget * table; GtkWidget * label; guint table_row; GtkWidget * radio_button[3]; GtkWidget * hseparator; GtkWidget * export_menu; // GtkObject * adjustment; // GtkWidget * spin_buttons[3]; gint counter; gint current; AmitkExportMethod i_export_method; tb_export_t * tb_export; AmitkAxis i_axis; #ifdef AMIDE_LIBMDC_SUPPORT libmdc_export_t i_libmdc_export; #endif gboolean resliced; gboolean all_visible; gboolean inclusive_bounding_box; AmitkExportMethod method; gint submethod; AmitkPoint voxel_size; read_preferences(&resliced, &all_visible, &inclusive_bounding_box, &method, &submethod, &voxel_size); /* sanity checks */ g_return_if_fail(AMITK_IS_STUDY(study)); g_return_if_fail(AMITK_IS_DATA_SET(active_ds)); tb_export = tb_export_init(); tb_export->study = AMITK_STUDY(amitk_object_ref(AMITK_OBJECT(study))); tb_export->active_ds = amitk_object_ref(active_ds); tb_export->preferences = g_object_ref(preferences); temp_string = g_strdup_printf(_("%s: Export Data Set Dialog"), PACKAGE); tb_export->dialog = gtk_dialog_new_with_buttons (temp_string, parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_EXECUTE, AMITK_RESPONSE_EXECUTE, NULL); gtk_window_set_title(GTK_WINDOW(tb_export->dialog), temp_string); g_free(temp_string); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(tb_export->dialog), "delete_event", G_CALLBACK(delete_event_cb), tb_export); g_signal_connect(G_OBJECT(tb_export->dialog), "destroy", G_CALLBACK(destroy_cb), tb_export); g_signal_connect(G_OBJECT(tb_export->dialog), "response", G_CALLBACK(response_cb), tb_export); gtk_container_set_border_width(GTK_CONTAINER(tb_export->dialog), 10); /* create the progress dialog */ tb_export->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_export->dialog)); amitk_progress_dialog_set_text(AMITK_PROGRESS_DIALOG(tb_export->progress_dialog), _("Exporting Data Sets")); /* start making the widgets for this dialog box */ table = gtk_table_new(5,4,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(tb_export->dialog)->vbox), table); label = gtk_label_new(_("Export:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); // tooltip N_("Export the data set in its original orientation (unresliced)") temp_string = g_strdup_printf(_("Original Orientation - %s"), AMITK_OBJECT_NAME(tb_export->active_ds)); radio_button[0] = gtk_radio_button_new_with_label(NULL, temp_string); g_free(temp_string); gtk_table_attach(GTK_TABLE(table), radio_button[0], 1,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[0]), "resliced", GINT_TO_POINTER(FALSE)); g_object_set_data(G_OBJECT(radio_button[0]), "all_visible", GINT_TO_POINTER(FALSE)); table_row++; // tooltip N_("Export the data set in its current orientation (resliced)") temp_string = g_strdup_printf(_("Resliced Orientation - %s"), AMITK_OBJECT_NAME(tb_export->active_ds)); radio_button[1] = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button[0])), temp_string); g_free(temp_string); gtk_table_attach(GTK_TABLE(table), radio_button[1], 1,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[1]), "resliced", GINT_TO_POINTER(TRUE)); g_object_set_data(G_OBJECT(radio_button[1]), "all_visible", GINT_TO_POINTER(FALSE)); table_row++; // tooltip N_("Export all the visible data sets into a single file") radio_button[2] = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button[0])), _("All Visible Data Sets (resliced)")); gtk_table_attach(GTK_TABLE(table), radio_button[2], 1,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[2]), "resliced", GINT_TO_POINTER(TRUE)); g_object_set_data(G_OBJECT(radio_button[2]), "all_visible", GINT_TO_POINTER(TRUE)); table_row++; if (!resliced && !all_visible) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[0]), TRUE); else if (resliced && !all_visible) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[1]), TRUE); else // all_visible gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[2]), TRUE); g_signal_connect(G_OBJECT(radio_button[0]), "clicked", G_CALLBACK(reslice_radio_buttons_cb), tb_export); g_signal_connect(G_OBJECT(radio_button[1]), "clicked", G_CALLBACK(reslice_radio_buttons_cb), tb_export); g_signal_connect(G_OBJECT(radio_button[2]), "clicked", G_CALLBACK(reslice_radio_buttons_cb), tb_export); /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0,4,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("export format:")); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); /* select the export type */ export_menu = gtk_combo_box_new_text(); counter = 0; current = 0; for (i_export_method = AMITK_EXPORT_METHOD_RAW; i_export_method < AMITK_EXPORT_METHOD_NUM; i_export_method++) { #ifdef AMIDE_LIBMDC_SUPPORT if (i_export_method == AMITK_EXPORT_METHOD_LIBMDC) { for (i_libmdc_export=0; i_libmdc_export < LIBMDC_NUM_EXPORT_METHODS; i_libmdc_export++) { if (libmdc_supports(libmdc_export_to_format[i_libmdc_export])) { gtk_combo_box_append_text(GTK_COMBO_BOX(export_menu), libmdc_export_menu_names[i_libmdc_export]); // add tooltips at some point libmdc_export_menu_explanations[i_libmdc_export] if ((method == i_export_method) && (submethod == libmdc_export_to_format[i_libmdc_export])) current = counter; counter++; } } } else #endif { gtk_combo_box_append_text(GTK_COMBO_BOX(export_menu), amitk_export_menu_names[i_export_method]); // add tooltips at some point amitk_export_menu_explanations[i_export_method], if (method == i_export_method) current = counter; counter++; } } g_signal_connect(G_OBJECT(export_menu), "changed", G_CALLBACK(change_export_cb), NULL); gtk_combo_box_set_active(GTK_COMBO_BOX(export_menu), current); /* done after signal attachment, in case current never got matched and is still zero */ gtk_table_attach(GTK_TABLE(table), export_menu, 1,4, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(export_menu); table_row++; /* widgets to change the voxel size of the data set */ label = gtk_label_new(_("voxel size (mm) [x,y,z]:")); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); for (i_axis=0; i_axisvs_spin_button[i_axis] = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 0.2); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_export->vs_spin_button[i_axis]), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(tb_export->vs_spin_button[i_axis]), 4); g_object_set_data(G_OBJECT(tb_export->vs_spin_button[i_axis]), "axis", GINT_TO_POINTER(i_axis)); g_signal_connect(G_OBJECT(tb_export->vs_spin_button[i_axis]), "value_changed", G_CALLBACK(change_voxel_size_cb), tb_export); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(tb_export->vs_spin_button[i_axis]),i_axis+1,i_axis+2, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); gtk_widget_set_sensitive(GTK_WIDGET(tb_export->vs_spin_button[i_axis]), resliced || all_visible); } recommend_voxel_size(tb_export); /* updates voxel size guestimate, and updates the entry boxes */ table_row++; // gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_buttons[0]),FALSE); // gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_buttons[0]), FALSE); // gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_buttons[0]), GTK_UPDATE_ALWAYS); label = gtk_label_new(_("bounding box:")); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(label), 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); // tooltip N_("Export the data set in its original orientation (unresliced)") tb_export->bb_radio_button[0] = gtk_radio_button_new_with_label(NULL, "tight"); gtk_table_attach(GTK_TABLE(table), tb_export->bb_radio_button[0], 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(tb_export->bb_radio_button[0]), "inclusive_bounding_box", GINT_TO_POINTER(FALSE)); // tooltip N_("Export the data set in its current orientation (resliced)") tb_export->bb_radio_button[1] = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(tb_export->bb_radio_button[0])), "inclusive (of all data sets)"); gtk_table_attach(GTK_TABLE(table), tb_export->bb_radio_button[1], 2,4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(tb_export->bb_radio_button[1]), "inclusive_bounding_box", GINT_TO_POINTER(TRUE)); table_row++; if (!inclusive_bounding_box) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_export->bb_radio_button[0]), TRUE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_export->bb_radio_button[1]), TRUE); g_signal_connect(G_OBJECT(tb_export->bb_radio_button[0]), "clicked", G_CALLBACK(bb_radio_buttons_cb), NULL); g_signal_connect(G_OBJECT(tb_export->bb_radio_button[1]), "clicked", G_CALLBACK(bb_radio_buttons_cb), NULL); gtk_widget_set_sensitive(tb_export->bb_radio_button[0], resliced || all_visible); gtk_widget_set_sensitive(tb_export->bb_radio_button[1], resliced || all_visible); /* and show all our widgets */ gtk_widget_show_all(tb_export->dialog); return; } amide-1.0.6/amide-current/src/tb_export_data_set.h000066400000000000000000000023031423227705100221470ustar00rootroot00000000000000/* tb_export_data_set.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2006-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __TB_EXPORT_DATA_SET_H__ #define __TB_EXPORT_DATA_SET_H__ /* header files always needed with this one */ #include "amitk_study.h" /* external functions */ void tb_export_data_set(AmitkStudy * study, AmitkDataSet * active_ds, AmitkPreferences * preferences, GtkWindow * parent); #endif /* __TB_EXPORT_DATA_SET_H__ */ amide-1.0.6/amide-current/src/tb_fads.c000066400000000000000000001245151423227705100177040ustar00rootroot00000000000000/* tb_fads.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_progress_dialog.h" #include "fads.h" #include "tb_fads.h" #include "ui_common.h" #ifdef AMIDE_LIBGSL_SUPPORT #define LABEL_WIDTH 400 #define SPIN_BUTTON_X_SIZE 100 #define MAX_ITERATIONS 1e8 static const char * wizard_name = N_("Factor Analysis Wizard"); static const char *svd_page_text = N_("This page allows the computation of the singular value decomposition " "for the data set in question. These values can give you an idea of " "how many important factors the data set has." "\n\n" "This process can be extremely slow, so skip this page if you already " "know the answer."); static const char * finish_page_text = N_("When the apply button is hit, the appropriate factor analysis data " "structures will be created, and placed underneath the given data set " "in the study tree\n"); static gchar * start_page_text = N_("Welcome to the factor analysis of dynamic structures wizard. " "\n\n" "None of this code has been validated, and it's probably wrong, " "so use at your own risk"); static gchar * not_enough_frames_text = N_("Welcome to the factor analysis of dynamic structures wizard. " "\n\n" "This wizard only works with dynamic studies"); static gchar * curve_explanation_text = N_("You can select a text file to set the initial starting point for the fitted curves." "\n\n" "The file should have one line per time point, with one column for each parameter"); static gchar * no_curve_explanation_text = N_("Selected factor analysis method does not utilize initial curves"); typedef enum { INTRO_PAGE, SVD_PAGE, FACTOR_CHOICE_PAGE, PARAMETERS_PAGE, CURVES_PAGE, CONCLUSION_PAGE, NUM_PAGES } which_page_t; /* data structures */ typedef struct tb_fads_t { GtkWidget * dialog; AmitkDataSet * data_set; AmitkPreferences * preferences; gint num_factors; gint max_iterations; gdouble stopping_criteria; gboolean sum_factors_equal_one; gdouble beta; gdouble k12; gdouble k21; gdouble k23; gdouble k32; fads_type_t fads_type; fads_minimizer_algorithm_t algorithm; GArray * initial_curves; GtkWidget * page[NUM_PAGES]; GtkWidget * progress_dialog; GtkWidget * algorithm_menu; GtkWidget * num_factors_spin; GtkWidget * num_iterations_spin; GtkWidget * stopping_criteria_spin; GtkWidget * sum_factors_equal_one_button; GtkWidget * beta_spin; GtkWidget * k12_spin; GtkWidget * k21_spin; GtkWidget * svd_tree; GtkWidget * blood_add_button; GtkWidget * blood_remove_button; GtkWidget * blood_tree; GtkWidget * curve_add_button; GtkWidget * curve_remove_button; GtkWidget * curve_view; GtkTextBuffer * curve_text; GtkTextBuffer * explanation_buffer; guint reference_count; } tb_fads_t; static void set_text(tb_fads_t * tb_fads); static void update_curve_text(tb_fads_t * tb_fads, gboolean allow_curve_entries); static gchar * get_filename(tb_fads_t * tb_fads); static void fads_type_cb(GtkWidget * widget, gpointer data); static void algorithm_cb(GtkWidget * widget, gpointer data); static void svd_pressed_cb(GtkButton * button, gpointer data); static void blood_cell_edited(GtkCellRendererText *cellrenderertext, gchar *arg1, gchar *arg2,gpointer data); static void add_blood_pressed_cb(GtkButton * button, gpointer data); static void remove_blood_pressed_cb(GtkButton * button, gpointer data); static void read_in_curve_file(tb_fads_t * tb_fads, gchar * filename); static void add_curve_pressed_cb(GtkButton * button, gpointer data); static void remove_curve_pressed_cb(GtkButton * button, gpointer data); static void num_factors_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void max_iterations_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void stopping_criteria_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void sum_factors_equal_one_toggle_cb(GtkToggleButton * button, gpointer data); static void beta_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void k12_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void k21_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void apply_cb(GtkAssistant * assistant, gpointer data); static void close_cb(GtkAssistant * assistant, gpointer data); static tb_fads_t * tb_fads_free(tb_fads_t * tb_fads); static tb_fads_t * tb_fads_init(void); static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data); static GtkWidget * create_page(tb_fads_t * tb_fads, which_page_t i_page); static void set_text(tb_fads_t * tb_fads) { gchar * temp_string; GtkTextIter iter; GdkPixbuf * pixbuf; /* the output page text */ if (tb_fads->page[CONCLUSION_PAGE] != NULL) { temp_string = g_strdup_printf(_("%s\nMethod Picked: %s"), _(finish_page_text), _(fads_type_explanation[tb_fads->fads_type])); gtk_label_set_text(GTK_LABEL(tb_fads->page[CONCLUSION_PAGE]),temp_string); g_free(temp_string); } /* the factor analysis type picking page */ if (tb_fads->explanation_buffer != NULL) { gtk_text_buffer_set_text (tb_fads->explanation_buffer, _(fads_type_explanation[tb_fads->fads_type]), -1); if (fads_type_icon[tb_fads->fads_type] != NULL) { gtk_text_buffer_get_end_iter(tb_fads->explanation_buffer, &iter); gtk_text_buffer_insert(tb_fads->explanation_buffer, &iter, "\n", -1); pixbuf = gdk_pixbuf_new_from_inline(-1,fads_type_icon[tb_fads->fads_type] , FALSE, NULL); gtk_text_buffer_get_end_iter(tb_fads->explanation_buffer, &iter); gtk_text_buffer_insert_pixbuf(tb_fads->explanation_buffer, &iter, pixbuf); g_object_unref(pixbuf); } } return; } static void update_curve_text(tb_fads_t * tb_fads, gboolean allow_curve_entries) { gint i; gint j; gint k; GString * text_str; if (!allow_curve_entries) { /* using a method that doesn't use initial curves */ gtk_text_buffer_set_text(tb_fads->curve_text, _(no_curve_explanation_text), -1); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tb_fads->curve_view), GTK_WRAP_WORD); } else if (tb_fads->initial_curves == NULL) { gtk_text_buffer_set_text(tb_fads->curve_text, _(curve_explanation_text), -1); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tb_fads->curve_view), GTK_WRAP_WORD); } else { text_str = g_string_new("frame/curve:"); for (j=0; j < tb_fads->num_factors; j++) g_string_append_printf(text_str, " %10d", j); g_string_append(text_str, "\n\n"); for (i=0,j=0,k=0; i < tb_fads->initial_curves->len; i++,j++) { if (j >= tb_fads->num_factors) { g_string_append(text_str, "\n"); j=0; } if (j==0) { /* new row, first column */ g_string_append_printf(text_str, "%12d", k); k++; } g_string_append_printf(text_str, " %10.9g", g_array_index(tb_fads->initial_curves, gdouble, i)); } g_string_append(text_str, "\n"); gtk_text_buffer_set_text(tb_fads->curve_text, text_str->str, -1); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tb_fads->curve_view), GTK_WRAP_NONE); g_string_free(text_str, TRUE); } return; } /* function to get a name to save the output as: returned string will need to be free'd if not NULL */ static gchar * get_filename(tb_fads_t * tb_fads) { GtkWidget * file_chooser; gchar * analysis_name; gchar * save_filename; file_chooser = gtk_file_chooser_dialog_new (_("Filename for Factor Data"), GTK_WINDOW(tb_fads->dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(tb_fads->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ analysis_name = g_strdup_printf("%s_fads_analysis.tsv",AMITK_OBJECT_NAME(tb_fads->data_set)); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (file_chooser), analysis_name); g_free(analysis_name); /* run the dialog */ if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) save_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); else save_filename = NULL; gtk_widget_destroy (file_chooser); return save_filename; } static void svd_pressed_cb(GtkButton * button, gpointer data) { tb_fads_t * tb_fads = data; gdouble * factors = NULL; gint num_factors; gint i; GtkTreeIter iter; GtkTreeModel * model; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_fads->svd_tree)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ /* calculate factors */ ui_common_place_cursor(UI_CURSOR_WAIT, tb_fads->page[PARAMETERS_PAGE]); fads_svd_factors(tb_fads->data_set, &num_factors, &factors); ui_common_remove_wait_cursor(tb_fads->page[PARAMETERS_PAGE]); for (i=0; iblood_tree)); /* switch the following 3 lines with path = gtk_tree_path_new_from_indices(row, -1); when gtk 2.2 is ready */ temp_string = g_strdup_printf("%d", row); path = gtk_tree_path_new_from_string(temp_string); g_free(temp_string); if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_list_store_set (GTK_LIST_STORE(model), &iter,column,value, -1, -1); } gtk_tree_path_free(path); } } return; } static void add_blood_pressed_cb(GtkButton * button, gpointer data) { tb_fads_t * tb_fads = data; GtkTreeIter iter; GtkTreeModel * model; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_fads->blood_tree)); gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set (GTK_LIST_STORE(model), &iter,0,0.0,1,0.0,-1); return; } static void remove_blood_pressed_cb(GtkButton * button, gpointer data) { tb_fads_t * tb_fads = data; GtkTreeIter iter; GtkTreeSelection * selection; GtkTreeModel * model; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_fads->blood_tree)); if(gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_list_store_remove(GTK_LIST_STORE(model), &iter); } return; } static void read_in_curve_file(tb_fads_t * tb_fads, gchar * filename) { FILE * file; gdouble return_val; gchar line[1024]; gchar ** string_chunks; gint i; if ((file = fopen(filename, "r")) == NULL) { g_warning(_("Could not open file: %s"), filename); return; } if (tb_fads->initial_curves != NULL) g_array_free(tb_fads->initial_curves, TRUE); tb_fads->initial_curves = g_array_new(FALSE, TRUE, sizeof(gdouble)); while(fgets(line, 1024, file) != NULL) { if (line[0] != '#') {/* skip comment lines */ /* split the line by tabs */ string_chunks = g_strsplit(line, "\t", -1); i=0; while (string_chunks[i] != NULL) { if (sscanf(string_chunks[i], "%lf", &return_val) == 1) tb_fads->initial_curves = g_array_append_val(tb_fads->initial_curves, return_val); i++; } g_strfreev(string_chunks); } } if (tb_fads->initial_curves->len == 0) { g_warning(_("Could not find any numerical values in file: %s\n"), filename); g_array_free(tb_fads->initial_curves, TRUE); tb_fads->initial_curves = NULL; } update_curve_text(tb_fads, TRUE); fclose(file); return; } static void add_curve_pressed_cb(GtkButton * button, gpointer data) { tb_fads_t * tb_fads = data; GtkWidget * file_chooser; gchar * filename; /* get the name of the file to import */ file_chooser = gtk_file_chooser_dialog_new (_("Import Curve File"), GTK_WINDOW(tb_fads->dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(tb_fads->preferences, file_chooser); if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy (file_chooser); if (filename == NULL) return; if (!ui_common_check_filename(filename)) { g_warning(_("Inappropriate Filename: %s"), filename); g_free(filename); return; } #ifdef AMIDE_DEBUG g_print("Curve file to import: %s\n",filename); #endif read_in_curve_file(tb_fads, filename); g_free(filename); return; } static void remove_curve_pressed_cb(GtkButton * button, gpointer data) { tb_fads_t * tb_fads = data; if (tb_fads->initial_curves != NULL) { g_array_free(tb_fads->initial_curves, TRUE); tb_fads->initial_curves = NULL; } /* and reset the explanation text */ gtk_text_buffer_set_text(tb_fads->curve_text, _(curve_explanation_text), -1); return; } static void fads_type_cb(GtkWidget * widget, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->fads_type = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); set_text(tb_fads); return; } static void algorithm_cb(GtkWidget * widget, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->algorithm = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); set_text(tb_fads); return; } static void num_factors_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->num_factors = gtk_spin_button_get_value_as_int(spin_button); return; } static void max_iterations_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->max_iterations = gtk_spin_button_get_value_as_int(spin_button); return; } static void stopping_criteria_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->stopping_criteria = gtk_spin_button_get_value(spin_button); return; } static void sum_factors_equal_one_toggle_cb(GtkToggleButton * button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->sum_factors_equal_one = gtk_toggle_button_get_active(button); return; } static void beta_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->beta = gtk_spin_button_get_value(spin_button); return; } static void k12_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->k12 = gtk_spin_button_get_value(spin_button); return; } static void k21_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_fads_t * tb_fads = data; tb_fads->k21 = gtk_spin_button_get_value(spin_button); return; } /* function called when the finish button is hit */ static void apply_cb(GtkAssistant * assistant, gpointer data) { tb_fads_t * tb_fads = data; gchar * output_filename; gint num=0; gint i; gint * frames=NULL; amide_data_t * vals=NULL; amide_data_t value; amide_time_t time; GtkTreeModel *model; GtkTreeIter iter; output_filename = get_filename(tb_fads); if (output_filename == NULL) return; /* no filename, no go */ /* get the blood values */ model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_fads->blood_tree)); num = gtk_tree_model_iter_n_children(model, NULL); if (num > 0) { if ((frames = g_try_new(gint, num)) == NULL) { g_warning(_("failed malloc for frames array")); return; } if ((vals = g_try_new(amide_data_t, num)) == NULL) { g_warning(_("failed malloc for vals array")); g_free(frames); return; } for (i=0; idata_set, time); } #if AMIDE_DEBUG g_print("blood values: frame\tval\n"); for (i=0; ipage[CONCLUSION_PAGE]); switch(tb_fads->fads_type) { case FADS_TYPE_PCA: fads_pca(tb_fads->data_set, tb_fads->num_factors, output_filename, amitk_progress_dialog_update, tb_fads->progress_dialog); break; case FADS_TYPE_PLS: fads_pls(tb_fads->data_set, tb_fads->num_factors, tb_fads->algorithm, tb_fads->max_iterations, tb_fads->stopping_criteria, tb_fads->sum_factors_equal_one, tb_fads->beta, output_filename, num, frames, vals, tb_fads->initial_curves, amitk_progress_dialog_update, tb_fads->progress_dialog); break; case FADS_TYPE_TWO_COMPARTMENT: fads_two_comp(tb_fads->data_set, tb_fads->algorithm, tb_fads->max_iterations, tb_fads->num_factors-1, tb_fads->k12, tb_fads->k21, tb_fads->stopping_criteria, tb_fads->sum_factors_equal_one, output_filename, num, frames, vals, amitk_progress_dialog_update, tb_fads->progress_dialog); break; default: g_error("fads type %d not defined", tb_fads->fads_type); break; } ui_common_remove_wait_cursor(tb_fads->page[CONCLUSION_PAGE]); if (frames != NULL) { g_free(frames); frames = NULL; } if (vals != NULL) { g_free(vals); vals = NULL; } if (output_filename != NULL) { g_free(output_filename); output_filename = NULL; } return; } /* function called to close the dialog */ static void close_cb(GtkAssistant * assistant, gpointer data) { tb_fads_t * tb_fads = data; GtkWidget * dialog = tb_fads->dialog; tb_fads = tb_fads_free(tb_fads); /* trash collection */ gtk_widget_destroy(dialog); return; } static tb_fads_t * tb_fads_free(tb_fads_t * tb_fads) { gboolean return_val; /* sanity checks */ g_return_val_if_fail(tb_fads != NULL, NULL); g_return_val_if_fail(tb_fads->reference_count > 0, NULL); /* remove a reference count */ tb_fads->reference_count--; /* things to do if we've removed all reference's */ if (tb_fads->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_fads\n"); #endif if (tb_fads->initial_curves != NULL) { g_array_free(tb_fads->initial_curves, TRUE); tb_fads->initial_curves = NULL; } if (tb_fads->data_set != NULL) { amitk_object_unref(tb_fads->data_set); tb_fads->data_set = NULL; } if (tb_fads->preferences != NULL) { g_object_unref(tb_fads->preferences); tb_fads->preferences = NULL; } if (tb_fads->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_fads->progress_dialog), "delete_event", NULL, &return_val); tb_fads->progress_dialog = NULL; } g_free(tb_fads); tb_fads = NULL; } return tb_fads; } static tb_fads_t * tb_fads_init(void) { tb_fads_t * tb_fads; /* alloc space for the data structure for passing ui info */ if ((tb_fads = g_try_new(tb_fads_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_fads_t")); return NULL; } tb_fads->reference_count = 1; tb_fads->dialog = NULL; tb_fads->data_set = NULL; tb_fads->preferences = NULL; tb_fads->num_factors = 2; tb_fads->max_iterations = 1e6; tb_fads->stopping_criteria = 1e-2; tb_fads->sum_factors_equal_one = FALSE; tb_fads->beta = 0.0; tb_fads->k12 = 0.01; tb_fads->k21 = 0.1; tb_fads->k23 = 0.01; tb_fads->k32 = 0.1; tb_fads->fads_type = FADS_TYPE_PCA; // tb_fads->algorithm = FADS_MINIMIZER_VECTOR_BFGS; tb_fads->algorithm = FADS_MINIMIZER_CONJUGATE_PR; tb_fads->initial_curves = NULL; tb_fads->explanation_buffer = NULL; tb_fads->progress_dialog = NULL; return tb_fads; } static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data) { tb_fads_t * tb_fads = data; which_page_t which_page; gboolean num_factors; gboolean blood_entries; gboolean curve_entries; gboolean num_iterations; gboolean k_values; which_page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(page), "which_page")); switch(tb_fads->fads_type) { case FADS_TYPE_PCA: k_values = FALSE; blood_entries = FALSE; curve_entries = FALSE; num_factors = TRUE; num_iterations = FALSE; break; case FADS_TYPE_TWO_COMPARTMENT: k_values = TRUE; blood_entries = TRUE; curve_entries = FALSE; num_factors = TRUE; num_iterations = TRUE; break; case FADS_TYPE_PLS: k_values = FALSE; blood_entries = TRUE; curve_entries = TRUE; num_factors = TRUE; num_iterations = TRUE; break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); k_values = FALSE; blood_entries = TRUE; curve_entries = TRUE; num_factors = TRUE; num_iterations = TRUE; break; } switch(which_page) { case PARAMETERS_PAGE: /* fill in the proper text for the option to add initial curves */ gtk_text_buffer_set_text(tb_fads->curve_text, curve_entries ? _(curve_explanation_text) : "", -1); /* hide options we don't need */ gtk_widget_set_sensitive(tb_fads->blood_tree, blood_entries); gtk_widget_set_sensitive(tb_fads->blood_remove_button, blood_entries); gtk_widget_set_sensitive(tb_fads->blood_add_button, blood_entries); gtk_widget_set_sensitive(tb_fads->algorithm_menu, num_iterations); gtk_widget_set_sensitive(tb_fads->num_factors_spin, num_factors); gtk_widget_set_sensitive(tb_fads->num_iterations_spin, num_iterations); gtk_widget_set_sensitive(tb_fads->stopping_criteria_spin, num_iterations); gtk_widget_set_sensitive(tb_fads->sum_factors_equal_one_button, num_iterations); gtk_widget_set_sensitive(tb_fads->beta_spin, num_iterations); gtk_widget_set_sensitive(tb_fads->k12_spin, k_values); gtk_widget_set_sensitive(tb_fads->k21_spin, k_values); break; case CURVES_PAGE: /* hide options we don't need */ gtk_widget_set_sensitive(tb_fads->curve_remove_button, curve_entries); gtk_widget_set_sensitive(tb_fads->curve_add_button, curve_entries); update_curve_text(tb_fads, curve_entries); default: break; } } static GtkWidget * create_page(tb_fads_t * tb_fads, which_page_t i_page) { fads_type_t i_fads_type; fads_minimizer_algorithm_t i_algorithm; GtkWidget * label; GtkWidget * button; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkListStore * store; gint table_row; GtkWidget * table; GtkWidget * scrolled; GtkWidget * menu; GtkWidget * view; GtkWidget * vseparator; GtkWidget * hseparator; GtkTextBuffer *buffer; table = gtk_table_new(8,6,FALSE); table_row=0; switch(i_page) { case SVD_PAGE: view = gtk_text_view_new (); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); gtk_text_buffer_set_text (buffer, _(svd_page_text), -1); gtk_table_attach(GTK_TABLE(table), view, 0,1, table_row,table_row+2, FALSE,FALSE, X_PADDING, Y_PADDING); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD); gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE); gtk_widget_set_size_request(view,300,-1); /* a separator for clarity */ vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(table), vseparator, 1,2,table_row, table_row+2,0, GTK_FILL, X_PADDING, Y_PADDING); /* do I need to compute factors? */ button = gtk_button_new_with_label(_("Compute Singular Values?")); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(svd_pressed_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), button, 2,3, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* the scroll widget which the list will go into */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,200,200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_table_attach(GTK_TABLE(table), scrolled, 2, 3, table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); /* the table itself */ store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_DOUBLE); tb_fads->svd_tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); /* above command adds a reference */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("singular entry"), renderer,"text", 0, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_fads->svd_tree), column); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("value"), renderer,"text", 1, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_fads->svd_tree), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_fads->svd_tree)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); gtk_container_add(GTK_CONTAINER(scrolled),tb_fads->svd_tree); table_row++; break; case FACTOR_CHOICE_PAGE: /* ask for the fads method to use */ label = gtk_label_new(_("FADS Method:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_fads_type = 0; i_fads_type < NUM_FADS_TYPES; i_fads_type++) gtk_combo_box_append_text(GTK_COMBO_BOX(menu), _(fads_type_name[i_fads_type])); gtk_combo_box_set_active(GTK_COMBO_BOX(menu), tb_fads->fads_type); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(fads_type_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), menu, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0,2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* the explanation */ view = gtk_text_view_new (); tb_fads->explanation_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); gtk_text_buffer_set_text (tb_fads->explanation_buffer, _(fads_type_explanation[tb_fads->fads_type]), -1); gtk_table_attach(GTK_TABLE(table), view, 0,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD); gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE); gtk_widget_set_size_request(view,300,-1); table_row++; break; case PARAMETERS_PAGE: /* ask for the minimizer algorithm to use */ label = gtk_label_new(_("Minimization Algorithm:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->algorithm_menu = gtk_combo_box_new_text(); for (i_algorithm = 0; i_algorithm < NUM_FADS_MINIMIZERS; i_algorithm++) gtk_combo_box_append_text(GTK_COMBO_BOX(tb_fads->algorithm_menu), _(fads_minimizer_algorithm_name[i_algorithm])); gtk_combo_box_set_active(GTK_COMBO_BOX(tb_fads->algorithm_menu), tb_fads->algorithm); g_signal_connect(G_OBJECT(tb_fads->algorithm_menu), "changed", G_CALLBACK(algorithm_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->algorithm_menu, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* max # of iterations */ label = gtk_label_new(_("Max. # of iterations:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->num_iterations_spin = gtk_spin_button_new_with_range(1, MAX_ITERATIONS, 1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(tb_fads->num_iterations_spin),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fads->num_iterations_spin), tb_fads->max_iterations); gtk_widget_set_size_request(tb_fads->num_iterations_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_fads->num_iterations_spin), "value_changed", G_CALLBACK(max_iterations_spinner_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->num_iterations_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* stopping criteria */ label = gtk_label_new(_("Stopping Criteria:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->stopping_criteria_spin = gtk_spin_button_new_with_range(EPSILON, 1.0, tb_fads->stopping_criteria); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fads->stopping_criteria_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fads->stopping_criteria_spin), tb_fads->stopping_criteria); gtk_widget_set_size_request(tb_fads->stopping_criteria_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_fads->stopping_criteria_spin), "value_changed", G_CALLBACK(stopping_criteria_spinner_cb), tb_fads); g_signal_connect(G_OBJECT(tb_fads->stopping_criteria_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), tb_fads->stopping_criteria_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* whether to force sum of factors to equal one */ label = gtk_label_new(_("Constrain sum of factors = 1:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->sum_factors_equal_one_button = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_fads->sum_factors_equal_one_button), tb_fads->sum_factors_equal_one); g_signal_connect(G_OBJECT(tb_fads->sum_factors_equal_one_button), "toggled", G_CALLBACK(sum_factors_equal_one_toggle_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->sum_factors_equal_one_button, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* stopping criteria */ label = gtk_label_new(_("Beta:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->beta_spin = gtk_spin_button_new_with_range(0.0, 1.0, 0.01); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fads->beta_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fads->beta_spin), tb_fads->beta); gtk_widget_set_size_request(tb_fads->beta_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_fads->beta_spin), "value_changed", G_CALLBACK(beta_spinner_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->beta_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* how many factors to solve for? */ label = gtk_label_new(_("# of Factors to use")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->num_factors_spin = gtk_spin_button_new_with_range(1, AMITK_DATA_SET_NUM_FRAMES(tb_fads->data_set), 1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(tb_fads->num_factors_spin),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fads->num_factors_spin), tb_fads->num_factors); gtk_widget_set_size_request(tb_fads->num_factors_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_fads->num_factors_spin), "value_changed", G_CALLBACK(num_factors_spinner_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->num_factors_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* k12 criteria */ label = gtk_label_new(_("initial k12 (1/s):")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->k12_spin = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 0.01); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fads->k12_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fads->k12_spin), tb_fads->k12); gtk_widget_set_size_request(tb_fads->k12_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_fads->k12_spin), "value_changed", G_CALLBACK(k12_spinner_cb), tb_fads); g_signal_connect(G_OBJECT(tb_fads->k12_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), tb_fads->k12_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* k21 criteria */ label = gtk_label_new(_("initial K21 (1/s):")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); tb_fads->k21_spin = gtk_spin_button_new_with_range(0.0, G_MAXDOUBLE, 0.01); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fads->k21_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fads->k21_spin), tb_fads->k21); gtk_widget_set_size_request(tb_fads->k21_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_fads->k21_spin), "value_changed", G_CALLBACK(k21_spinner_cb), tb_fads); g_signal_connect(G_OBJECT(tb_fads->k21_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), tb_fads->k21_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); // table_row++; table_row = 0; /* a separator for clarity */ vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(table), vseparator, 2,3,table_row, table_row+6, 0, GTK_FILL, X_PADDING, Y_PADDING); /* A table to add blood sample measurements */ tb_fads->blood_add_button = gtk_button_new_with_label(_("Add Blood Sample")); g_signal_connect(G_OBJECT(tb_fads->blood_add_button), "pressed", G_CALLBACK(add_blood_pressed_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->blood_add_button, 3,4, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* the scroll widget which the list will go into */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,200,200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_table_attach(GTK_TABLE(table), scrolled, 3, 4, table_row, table_row+4, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); table_row+=4; /* the table itself */ store = gtk_list_store_new(2, G_TYPE_DOUBLE, G_TYPE_DOUBLE); tb_fads->blood_tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); /* above command adds a reference */ renderer = gtk_cell_renderer_text_new (); g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); g_object_set_data(G_OBJECT(renderer),"column", GINT_TO_POINTER(0)); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(blood_cell_edited), tb_fads); column = gtk_tree_view_column_new_with_attributes("time pt (s)", renderer,"text", 0, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_fads->blood_tree), column); renderer = gtk_cell_renderer_text_new (); g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); g_object_set_data(G_OBJECT(renderer),"column", GINT_TO_POINTER(1)); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(blood_cell_edited), tb_fads); column = gtk_tree_view_column_new_with_attributes("value", renderer,"text", 1,NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_fads->blood_tree), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_fads->blood_tree)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); gtk_container_add(GTK_CONTAINER(scrolled),tb_fads->blood_tree); tb_fads->blood_remove_button = gtk_button_new_with_label(_("Remove Blood Sample")); g_signal_connect(G_OBJECT(tb_fads->blood_remove_button), "pressed", G_CALLBACK(remove_blood_pressed_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->blood_remove_button, 3,4, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); break; case CURVES_PAGE: /* A button to add initial curves */ tb_fads->curve_add_button = gtk_button_new_with_label(_("Add Initial Curves")); g_signal_connect(G_OBJECT(tb_fads->curve_add_button), "pressed", G_CALLBACK(add_curve_pressed_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->curve_add_button, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* the scroll widget which the list will go into */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,200,200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_table_attach(GTK_TABLE(table), scrolled, 0, 1, table_row, table_row+4, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); table_row+=4; /* the curve text area */ tb_fads->curve_view = gtk_text_view_new(); tb_fads->curve_text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tb_fads->curve_view)); gtk_widget_modify_font(tb_fads->curve_view, amitk_fixed_font_desc); gtk_text_view_set_editable(GTK_TEXT_VIEW(tb_fads->curve_view), FALSE); gtk_container_add(GTK_CONTAINER(scrolled),tb_fads->curve_view); tb_fads->curve_remove_button = gtk_button_new_with_label(_("Remove Initial Curves")); g_signal_connect(G_OBJECT(tb_fads->curve_remove_button), "pressed", G_CALLBACK(remove_curve_pressed_cb), tb_fads); gtk_table_attach(GTK_TABLE(table), tb_fads->curve_remove_button, 0,1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; break; default: table = NULL; g_error("unhandled case in %s at line %d\n", __FILE__, __LINE__); break; } return table; } void tb_fads(AmitkDataSet * active_ds, AmitkPreferences * preferences, GtkWindow * parent) { tb_fads_t * tb_fads; GdkPixbuf * logo; which_page_t i_page; g_return_if_fail(AMITK_IS_DATA_SET(active_ds)); tb_fads = tb_fads_init(); tb_fads->data_set = amitk_object_ref(active_ds); tb_fads->preferences = g_object_ref(preferences); tb_fads->dialog = gtk_assistant_new(); gtk_window_set_transient_for(GTK_WINDOW(tb_fads->dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW(tb_fads->dialog), TRUE); g_signal_connect(G_OBJECT(tb_fads->dialog), "cancel", G_CALLBACK(close_cb), tb_fads); g_signal_connect(G_OBJECT(tb_fads->dialog), "close", G_CALLBACK(close_cb), tb_fads); g_signal_connect(G_OBJECT(tb_fads->dialog), "apply", G_CALLBACK(apply_cb), tb_fads); g_signal_connect(G_OBJECT(tb_fads->dialog), "prepare", G_CALLBACK(prepare_page_cb), tb_fads); tb_fads->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_fads->dialog)); /* --------------- initial page ------------------ */ tb_fads->page[INTRO_PAGE]= gtk_label_new(((AMITK_DATA_SET_NUM_FRAMES(tb_fads->data_set) > 1) ? _(start_page_text) : _(not_enough_frames_text))); gtk_widget_set_size_request(tb_fads->page[INTRO_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_fads->page[INTRO_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[INTRO_PAGE]); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[INTRO_PAGE], GTK_ASSISTANT_PAGE_INTRO); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[INTRO_PAGE], (AMITK_DATA_SET_NUM_FRAMES(tb_fads->data_set) > 1)); /* --------------- the pages in the middle ---------------- */ for (i_page=INTRO_PAGE+1; i_pagepage[i_page] = create_page(tb_fads, i_page); gtk_assistant_append_page(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[i_page]); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[i_page], TRUE); /* all pages have default values */ } /* ---------------- conclusion page ---------------------------------- */ tb_fads->page[CONCLUSION_PAGE] = gtk_label_new("?"); set_text(tb_fads); gtk_widget_set_size_request(tb_fads->page[CONCLUSION_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_fads->page[CONCLUSION_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[CONCLUSION_PAGE]); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[CONCLUSION_PAGE], GTK_ASSISTANT_PAGE_CONFIRM); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[CONCLUSION_PAGE], TRUE); logo = gtk_widget_render_icon(GTK_WIDGET(tb_fads->dialog), "amide_icon_logo", GTK_ICON_SIZE_DIALOG, 0); for (i_page=0; i_pagedialog), tb_fads->page[i_page], logo); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_fads->dialog), tb_fads->page[i_page], _(wizard_name)); g_object_set_data(G_OBJECT(tb_fads->page[i_page]),"which_page", GINT_TO_POINTER(i_page)); } g_object_unref(logo); gtk_widget_show_all(tb_fads->dialog); return; } #endif /* AMIDE_LIBGSL_SUPPORT */ amide-1.0.6/amide-current/src/tb_fads.h000066400000000000000000000021111423227705100176740ustar00rootroot00000000000000/* tb_fads.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_data_set.h" #ifdef AMIDE_LIBGSL_SUPPORT /* external functions */ void tb_fads(AmitkDataSet * active_ds, AmitkPreferences * preferences, GtkWindow * parent); #endif amide-1.0.6/amide-current/src/tb_filter.c000066400000000000000000000365641423227705100202620ustar00rootroot00000000000000/* tb_filter.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_data_set.h" #include "amitk_progress_dialog.h" #include "tb_filter.h" #define LABEL_WIDTH 375 #define MIN_FIR_FILTER_SIZE 7 #define MAX_FIR_FILTER_SIZE 31 #define MIN_NONLINEAR_FILTER_SIZE 3 #define MAX_NONLINEAR_FILTER_SIZE 11 #define DEFAULT_GAUSSIAN_FILTER_SIZE 15 #define DEFAULT_MEDIAN_FILTER_SIZE 3 #define MAX_FWHM 100.0 /* mm */ #define MIN_FWHM 0.0 /* mm */ static const char * wizard_name = N_("Data Set Filtering Wizard"); static const char * finish_page_text = N_("When the apply button is hit, a new data set will be created " "and placed into the study's tree, consisting of the appropriately " "filtered data\n"); #ifdef AMIDE_LIBGSL_SUPPORT static const char * gaussian_filter_text = N_("The Gaussian filter is an effective smoothing filter"); #endif static const char * median_3d_filter_text = N_("Median filter work relatively well at preserving edges while\n" "removing speckle noise.\n" "\n" "This filter is the 3D median filter, so the neighborhood used for\n" "determining the median will be KSxKSxKS, KS=kernel size"); static const char * median_linear_filter_text = N_("Median filters work relatively well at preserving edges while\n" "removing speckle noise.\n" "\n" "This filter is the 1D median filter, so the neighboorhood used for\n" "determining the median will be of the given kernel size, and the\n" "data set will be filtered 3x (once for each direction)."); #ifndef AMIDE_LIBGSL_SUPPORT static const char *no_libgsl_text = N_("This filter requires support from the GNU Scientific Library (GSL).\n" "This version of AMIDE has not been compiled with GSL support enabled."); #endif typedef enum { PICK_FILTER_PAGE, GAUSSIAN_FILTER_PAGE, MEDIAN_LINEAR_FILTER_PAGE, MEDIAN_3D_FILTER_PAGE, CONCLUSION_PAGE, NUM_PAGES } which_page_t; /* data structures */ typedef struct tb_filter_t { GtkWidget * dialog; AmitkFilter filter; gint kernel_size; amide_real_t fwhm; AmitkDataSet * data_set; AmitkStudy * study; GtkWidget * page[NUM_PAGES]; GtkWidget * progress_dialog; guint reference_count; } tb_filter_t; static void filter_cb(GtkWidget * widget, gpointer data); static void kernel_size_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void fwhm_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void apply_cb(GtkAssistant * assistant, gpointer data); static void close_cb(GtkAssistant * assistant, gpointer data); static gint forward_page_function (gint current_page, gpointer data); static tb_filter_t * tb_filter_free(tb_filter_t * tb_filter); static tb_filter_t * tb_filter_init(void); static GtkWidget * create_page(tb_filter_t * tb_filter, which_page_t i_page); /* function to change the color table */ static void filter_cb(GtkWidget * widget, gpointer data) { tb_filter_t * tb_filter = data; tb_filter->filter = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); return; } static void kernel_size_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_filter_t * tb_filter = data; gint int_value; int_value = gtk_spin_button_get_value_as_int(spin_button); if (!(int_value & 0x1)) { int_value++; /* make it odd */ } tb_filter->kernel_size = int_value; g_signal_handlers_block_by_func(G_OBJECT(spin_button), G_CALLBACK(kernel_size_spinner_cb), tb_filter); gtk_spin_button_set_value(spin_button, tb_filter->kernel_size); g_signal_handlers_unblock_by_func(G_OBJECT(spin_button), G_CALLBACK(kernel_size_spinner_cb), tb_filter); return; } static void fwhm_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_filter_t * tb_filter = data; amide_real_t value; value = gtk_spin_button_get_value(spin_button); if (value < MIN_FWHM) value = MIN_FWHM; else if (value > MAX_FWHM) value = MAX_FWHM; tb_filter->fwhm = value; g_signal_handlers_block_by_func(G_OBJECT(spin_button), G_CALLBACK(fwhm_spinner_cb), tb_filter); gtk_spin_button_set_value(spin_button, tb_filter->fwhm); g_signal_handlers_unblock_by_func(G_OBJECT(spin_button), G_CALLBACK(fwhm_spinner_cb), tb_filter); return; } /* function called when the finish button is hit */ static void apply_cb(GtkAssistant * assistant, gpointer data) { tb_filter_t * tb_filter = data; AmitkDataSet * filtered; /* disable the buttons */ gtk_widget_set_sensitive(GTK_WIDGET(assistant), FALSE); /* generate the new data set */ filtered = amitk_data_set_get_filtered(tb_filter->data_set, tb_filter->filter, tb_filter->kernel_size, tb_filter->fwhm, amitk_progress_dialog_update, tb_filter->progress_dialog); if (filtered != NULL) { /* and add the new data set to the study */ amitk_object_add_child(AMITK_OBJECT(tb_filter->study), AMITK_OBJECT(filtered)); /* this adds a reference to the data set*/ amitk_object_unref(filtered); /* so remove a reference */ } else g_warning("Failed to generate filtered data set"); return; } /* function called to cancel the dialog */ static void close_cb(GtkAssistant * assistant, gpointer data) { tb_filter_t * tb_filter = data; GtkWidget * dialog = tb_filter->dialog; tb_filter = tb_filter_free(tb_filter); /* trash collection */ gtk_widget_destroy(dialog); return; } static gint forward_page_function (gint current_page, gpointer data) { tb_filter_t * tb_filter=data; switch(current_page) { case PICK_FILTER_PAGE: return GAUSSIAN_FILTER_PAGE+tb_filter->filter; break; case GAUSSIAN_FILTER_PAGE: case MEDIAN_LINEAR_FILTER_PAGE: case MEDIAN_3D_FILTER_PAGE: return CONCLUSION_PAGE; break; default: return current_page+1; break; } } static tb_filter_t * tb_filter_free(tb_filter_t * tb_filter) { gboolean return_val; /* sanity checks */ g_return_val_if_fail(tb_filter != NULL, NULL); g_return_val_if_fail(tb_filter->reference_count > 0, NULL); /* remove a reference count */ tb_filter->reference_count--; /* things to do if we've removed all reference's */ if (tb_filter->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_filter\n"); #endif if (tb_filter->data_set != NULL) { amitk_object_unref(tb_filter->data_set); tb_filter->data_set = NULL; } if (tb_filter->study != NULL) { amitk_object_unref(tb_filter->study); tb_filter->study = NULL; } if (tb_filter->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_filter->progress_dialog), "delete_event", NULL, &return_val); tb_filter->progress_dialog = NULL; } g_free(tb_filter); tb_filter = NULL; } return tb_filter; } static tb_filter_t * tb_filter_init(void) { tb_filter_t * tb_filter; /* alloc space for the data structure for passing ui info */ if ((tb_filter = g_try_new(tb_filter_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_filter_t")); return NULL; } tb_filter->reference_count = 1; tb_filter->filter = AMITK_FILTER_GAUSSIAN; /* default filter */ tb_filter->dialog = NULL; tb_filter->study = NULL; tb_filter->kernel_size=3; tb_filter->fwhm = 1.0; return tb_filter; } static GtkWidget * create_page(tb_filter_t * tb_filter, which_page_t i_page) { GtkWidget * label; GtkWidget * spin_button; gint table_row; gint table_column; AmitkFilter i_filter; GtkWidget * table; GtkWidget * menu; table = gtk_table_new(3,3,FALSE); table_row=0; table_column=0; switch(i_page) { case PICK_FILTER_PAGE: label = gtk_label_new(_("Which Filter")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_filter=0; i_filterfilter); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(filter_cb), tb_filter); gtk_table_attach(GTK_TABLE(table), menu, table_column+1, table_column+2, table_row, table_row+1, FALSE, FALSE, X_PADDING, Y_PADDING); gtk_widget_show_all(menu); table_row++; break; case GAUSSIAN_FILTER_PAGE: #ifdef AMIDE_LIBGSL_SUPPORT tb_filter->kernel_size = DEFAULT_GAUSSIAN_FILTER_SIZE; label = gtk_label_new(_(gaussian_filter_text)); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* the kernel selection */ label = gtk_label_new(_("Kernel Size")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(MIN_FIR_FILTER_SIZE, MAX_FIR_FILTER_SIZE,2); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), tb_filter->kernel_size); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(kernel_size_spinner_cb), tb_filter); gtk_table_attach(GTK_TABLE(table), spin_button, table_column+1,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("FWHM (mm)")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(MIN_FWHM, MAX_FWHM,0.2); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), tb_filter->fwhm); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(fwhm_spinner_cb), tb_filter); g_signal_connect(G_OBJECT(spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), spin_button, table_column+1,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); #else /* no libgsl support */ label = gtk_label_new(_(no_libgsl_text)); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; #endif break; case MEDIAN_3D_FILTER_PAGE: case MEDIAN_LINEAR_FILTER_PAGE: tb_filter->kernel_size = DEFAULT_MEDIAN_FILTER_SIZE; label = gtk_label_new((i_page == MEDIAN_3D_FILTER_PAGE) ? _(median_3d_filter_text) : _(median_linear_filter_text)); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; /* the kernel selection */ label = gtk_label_new(_("Kernel Size")); gtk_table_attach(GTK_TABLE(table), label, table_column,table_column+1, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(MIN_NONLINEAR_FILTER_SIZE, MAX_NONLINEAR_FILTER_SIZE,2); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), tb_filter->kernel_size); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(kernel_size_spinner_cb), tb_filter); gtk_table_attach(GTK_TABLE(table), spin_button, table_column+1,table_column+2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; break; default: table = NULL; g_error("unhandled case in %s at line %d\n", __FILE__, __LINE__); break; } return table; } void tb_filter(AmitkStudy * study, AmitkDataSet * active_ds, GtkWindow * parent) { tb_filter_t * tb_filter; GdkPixbuf * logo; which_page_t i_page; if (active_ds == NULL) { g_warning(_("No data set is currently marked as active")); return; } tb_filter = tb_filter_init(); tb_filter->study = amitk_object_ref(study); tb_filter->data_set = amitk_object_ref(active_ds); /* take a guess at a good fwhm */ tb_filter->fwhm = point_min_dim(AMITK_DATA_SET_VOXEL_SIZE(tb_filter->data_set)); tb_filter->dialog = gtk_assistant_new(); gtk_window_set_transient_for(GTK_WINDOW(tb_filter->dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW(tb_filter->dialog), TRUE); g_signal_connect(G_OBJECT(tb_filter->dialog), "cancel", G_CALLBACK(close_cb), tb_filter); g_signal_connect(G_OBJECT(tb_filter->dialog), "close", G_CALLBACK(close_cb), tb_filter); g_signal_connect(G_OBJECT(tb_filter->dialog), "apply", G_CALLBACK(apply_cb), tb_filter); gtk_assistant_set_forward_page_func(GTK_ASSISTANT(tb_filter->dialog), forward_page_function, tb_filter, NULL); tb_filter->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_filter->dialog)); /* --------------intro page and the various filter pages ------------------- */ for (i_page=PICK_FILTER_PAGE; i_pagepage[i_page] = create_page(tb_filter, i_page); gtk_assistant_append_page(GTK_ASSISTANT(tb_filter->dialog), tb_filter->page[i_page]); } /* ---------------- conclusion page ---------------------------------- */ tb_filter->page[CONCLUSION_PAGE] = gtk_label_new(_(finish_page_text)); gtk_widget_set_size_request(tb_filter->page[CONCLUSION_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_filter->page[CONCLUSION_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_filter->dialog), tb_filter->page[CONCLUSION_PAGE]); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_filter->dialog), tb_filter->page[CONCLUSION_PAGE], GTK_ASSISTANT_PAGE_CONFIRM); /* things for all pages */ logo = gtk_widget_render_icon(GTK_WIDGET(tb_filter->dialog), "amide_icon_logo", GTK_ICON_SIZE_DIALOG, 0); for (i_page=0; i_pagedialog), tb_filter->page[i_page], logo); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_filter->dialog), tb_filter->page[i_page], _(wizard_name)); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_filter->dialog), tb_filter->page[i_page], TRUE); /* all pages have default values */ g_object_set_data(G_OBJECT(tb_filter->page[i_page]),"which_page", GINT_TO_POINTER(i_page)); } g_object_unref(logo); #ifndef AMIDE_LIBGSL_SUPPORT gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_filter->dialog), tb_filter->page[GAUSSIAN_FILTER_PAGE], FALSE); #endif gtk_widget_show_all(tb_filter->dialog); return; } amide-1.0.6/amide-current/src/tb_filter.h000066400000000000000000000020311423227705100202450ustar00rootroot00000000000000/* tb_filter.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_study.h" /* external functions */ void tb_filter(AmitkStudy * study, AmitkDataSet * active_ds, GtkWindow * parent); amide-1.0.6/amide-current/src/tb_fly_through.c000066400000000000000000001152421423227705100213160ustar00rootroot00000000000000/* tb_fly_through.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) #include #include #include "amide.h" #include "amitk_threshold.h" #include "amitk_progress_dialog.h" #include "mpeg_encode.h" #include "tb_fly_through.h" #include "amitk_canvas.h" typedef enum { NOT_DYNAMIC, OVER_TIME, OVER_FRAMES, OVER_FRAMES_SMOOTHED, OVER_GATES, DYNAMIC_TYPES } dynamic_t; typedef struct tb_fly_through_t { AmitkStudy * study; AmitkSpace * space; AmitkPreferences * preferences; amide_time_t start_time; amide_time_t end_time; guint start_frame; guint end_frame; amide_real_t start_z; amide_real_t end_z; amide_time_t duration; gboolean in_generation; gboolean dynamic; gboolean gated; dynamic_t type; GtkWidget * dialog; GtkWidget * canvas; GtkWidget * start_time_label; GtkWidget * end_time_label; GtkWidget * start_frame_label; GtkWidget * end_frame_label; GtkWidget * start_time_spin_button; GtkWidget * end_time_spin_button; GtkWidget * start_frame_spin_button; GtkWidget * end_frame_spin_button; GtkWidget * time_on_image_label; GtkWidget * time_on_image_button; GtkWidget * dynamic_type; GtkWidget * start_position_button; GtkWidget * end_position_button; GtkWidget * start_position_spin; GtkWidget * end_position_spin; GtkWidget * duration_spin_button; GtkWidget * position_entry; GtkWidget * progress_dialog; guint reference_count; } tb_fly_through_t; static void view_changed_cb(GtkWidget * canvas, AmitkPoint *position, amide_real_t thickness, gpointer data); static void dynamic_type_cb(GtkWidget * widget, gpointer data); static void change_start_time_cb(GtkWidget * widget, gpointer data); static void change_start_frame_cb(GtkWidget * widget, gpointer data); static void change_end_time_cb(GtkWidget * widget, gpointer data); static void change_end_frame_cb(GtkWidget * widget, gpointer data); static void time_on_image_cb(GtkWidget * widget, gpointer data); static void set_start_position_pressed_cb(GtkWidget * button, gpointer data); static void set_end_position_pressed_cb(GtkWidget * button, gpointer data); static void change_start_position_spin_cb(GtkWidget * widget, gpointer data); static void change_end_position_spin_cb(GtkWidget * widget, gpointer data); static void change_duration_spin_cb(GtkWidget * widget, gpointer data); static void destroy_cb(GtkObject * object, gpointer data); static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void response_cb (GtkDialog * dialog, gint response_id, gpointer data); static void movie_generate(tb_fly_through_t * tb_fly_through, gchar * output_filename); static void dialog_update_position_entry(tb_fly_through_t * tb_fly_through); static void dialog_set_sensitive(tb_fly_through_t * tb_fly_through, gboolean sensitive); static void dialog_update_entries(tb_fly_through_t * tb_fly_through); static tb_fly_through_t * tb_fly_through_unref(tb_fly_through_t * tb_fly_through); static tb_fly_through_t * tb_fly_through_init(void); static void view_changed_cb(GtkWidget * canvas, AmitkPoint *position, amide_real_t thickness, gpointer data) { tb_fly_through_t * tb_fly_through = data; amitk_study_set_view_center(tb_fly_through->study, *position); dialog_update_position_entry(tb_fly_through); return; } static void dynamic_type_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; dynamic_t type; type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "dynamic_type")); if (type != tb_fly_through->type) { tb_fly_through->type = type; if (tb_fly_through->dynamic) { if (type == OVER_TIME) { gtk_widget_show(tb_fly_through->start_time_label); gtk_widget_show(tb_fly_through->start_time_spin_button); gtk_widget_show(tb_fly_through->end_time_label); gtk_widget_show(tb_fly_through->end_time_spin_button); } if ((type == OVER_FRAMES) || (type == OVER_FRAMES_SMOOTHED)) { gtk_widget_show(tb_fly_through->start_frame_label); gtk_widget_show(tb_fly_through->start_frame_spin_button); gtk_widget_show(tb_fly_through->end_frame_label); gtk_widget_show(tb_fly_through->end_frame_spin_button); } if ((type == OVER_FRAMES) || (type == OVER_FRAMES_SMOOTHED) || (type == OVER_TIME)) { gtk_widget_show(tb_fly_through->time_on_image_label); gtk_widget_show(tb_fly_through->time_on_image_button); } else { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_fly_through->time_on_image_button), FALSE); gtk_widget_hide(tb_fly_through->time_on_image_label); gtk_widget_hide(tb_fly_through->time_on_image_button); } if ((type != OVER_FRAMES) && (type != OVER_FRAMES_SMOOTHED)) { gtk_widget_hide(tb_fly_through->start_frame_label); gtk_widget_hide(tb_fly_through->start_frame_spin_button); gtk_widget_hide(tb_fly_through->end_frame_label); gtk_widget_hide(tb_fly_through->end_frame_spin_button); } if (type != OVER_TIME) { gtk_widget_hide(tb_fly_through->start_time_label); gtk_widget_hide(tb_fly_through->start_time_spin_button); gtk_widget_hide(tb_fly_through->end_time_label); gtk_widget_hide(tb_fly_through->end_time_spin_button); } } } return; } /* function to change the start time */ static void change_start_time_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through->start_time = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } /* function to change the start frame */ static void change_start_frame_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; gint temp_val; temp_val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); if (temp_val >= 0) tb_fly_through->start_frame = temp_val; return; } /* function to change the end time */ static void change_end_time_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through->end_time = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } /* function to change the end frame */ static void change_end_frame_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through->end_frame = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static void time_on_image_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; amitk_canvas_set_time_on_image(AMITK_CANVAS(tb_fly_through->canvas), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void set_start_position_pressed_cb(GtkWidget * button, gpointer data) { AmitkPoint temp_point; tb_fly_through_t * tb_fly_through = data; temp_point = amitk_space_b2s(tb_fly_through->space, AMITK_STUDY_VIEW_CENTER(tb_fly_through->study)); tb_fly_through->start_z = temp_point.z; dialog_update_entries(tb_fly_through); } static void set_end_position_pressed_cb(GtkWidget * button, gpointer data) { AmitkPoint temp_point; tb_fly_through_t * tb_fly_through = data; temp_point = amitk_space_b2s(tb_fly_through->space, AMITK_STUDY_VIEW_CENTER(tb_fly_through->study)); tb_fly_through->end_z = temp_point.z; dialog_update_entries(tb_fly_through); } static void change_start_position_spin_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through->start_z = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static void change_end_position_spin_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through->end_z = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static void change_duration_spin_cb(GtkWidget * widget, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through->duration = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static void destroy_cb(GtkObject * object, gpointer data) { tb_fly_through_t * tb_fly_through = data; tb_fly_through = tb_fly_through_unref(tb_fly_through); /* free the associated data structure */ } /* function to run for a delete_event */ static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { tb_fly_through_t * tb_fly_through = data; /* trying to close while we're generating */ if (tb_fly_through->in_generation) { tb_fly_through->in_generation = FALSE; /* signal we need to exit */ return TRUE; } return FALSE; } /* function called when we hit the apply button */ static void response_cb (GtkDialog * dialog, gint response_id, gpointer data) { tb_fly_through_t * tb_fly_through = data; GtkWidget * file_chooser; gchar * filename; static guint save_image_num = 0; gboolean return_val; switch(response_id) { case AMITK_RESPONSE_EXECUTE: /* the rest of this function runs the file selection dialog box */ file_chooser = gtk_file_chooser_dialog_new(_("Output MPEG As"), GTK_WINDOW(dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(tb_fly_through->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ filename = g_strdup_printf("%s_FlyThrough_%d.mpg", AMITK_OBJECT_NAME(tb_fly_through->study), save_image_num++); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), filename); g_free(filename); if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy(file_chooser); if (filename == NULL) return; /* return to flythrough generation dialog */ else { /* generate the movie */ movie_generate(tb_fly_through, filename); g_free(filename); } /* and fall through to close out the dialog */ case GTK_RESPONSE_CANCEL: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } /* perform the movie generation */ static void movie_generate(tb_fly_through_t * tb_fly_through, gchar * output_filename) { guint i_frame; gint return_val = 1; gint num_frames; amide_real_t increment_z; amide_time_t duration=1.0; amide_time_t initial_duration; amide_time_t initial_start; amide_time_t start_time; AmitkPoint current_point; gpointer mpeg_encode_context; gboolean continue_work=TRUE; GList * data_sets; GList * temp_sets; AmitkDataSet * most_frames_ds=NULL; guint ds_frame=0; gdouble ds_frame_real; gint ds_gate; GdkPixbuf * pixbuf; /* gray out anything that could screw up the movie */ dialog_set_sensitive(tb_fly_through, FALSE); tb_fly_through->in_generation = TRUE; /* indicate we're generating */ /* figure out which data set has the most frames, need this if we're doing a movie over frames */ data_sets = amitk_object_get_children_of_type(AMITK_OBJECT(tb_fly_through->study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); temp_sets = data_sets; while (temp_sets != NULL) { if (most_frames_ds == NULL) most_frames_ds = AMITK_DATA_SET(temp_sets->data); else if (AMITK_DATA_SET_NUM_FRAMES(most_frames_ds) < AMITK_DATA_SET_NUM_FRAMES(temp_sets->data)) most_frames_ds = AMITK_DATA_SET(temp_sets->data); temp_sets = temp_sets->next; } num_frames = ceil(tb_fly_through->duration*FRAMES_PER_SECOND); if (num_frames > 1) increment_z = (tb_fly_through->end_z-tb_fly_through->start_z)/(num_frames-1); else increment_z = 0; /* erroneous */ current_point = amitk_space_b2s(AMITK_SPACE(tb_fly_through->space), AMITK_STUDY_VIEW_CENTER(tb_fly_through->study)); current_point.z = tb_fly_through->start_z; pixbuf = amitk_canvas_get_pixbuf(AMITK_CANVAS(tb_fly_through->canvas)); g_return_if_fail(pixbuf != NULL); mpeg_encode_context = mpeg_encode_setup(output_filename, ENCODE_MPEG1, gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); g_object_unref(pixbuf); g_return_if_fail(mpeg_encode_context != NULL); #ifdef AMIDE_DEBUG g_print("Total number of movie frames to do: %d\tincrement %f\n",num_frames, increment_z); #endif initial_start = AMITK_STUDY_VIEW_START_TIME(tb_fly_through->study); initial_duration = AMITK_STUDY_VIEW_DURATION (tb_fly_through->study); if (tb_fly_through->type == OVER_TIME) { duration = (tb_fly_through->end_time-tb_fly_through->start_time)/((amide_time_t) num_frames); amitk_study_set_view_duration(tb_fly_through->study, duration); } /* start generating the frames, continue while we haven't hit cancel */ for (i_frame = 0; (i_frame < num_frames) && tb_fly_through->in_generation && (return_val==1) && (continue_work); i_frame++) { switch (tb_fly_through->type) { case OVER_FRAMES: case OVER_FRAMES_SMOOTHED: ds_frame_real = (i_frame/((gdouble) num_frames)) * AMITK_DATA_SET_NUM_FRAMES(most_frames_ds); ds_frame = floor(ds_frame_real); start_time = amitk_data_set_get_start_time(most_frames_ds, ds_frame); duration = amitk_data_set_get_end_time(most_frames_ds, ds_frame)-start_time; start_time = start_time + EPSILON*fabs(start_time) + ((tb_fly_through->type == OVER_FRAMES_SMOOTHED) ? ((ds_frame_real-ds_frame)*duration) : 0.0); duration = duration - EPSILON*fabs(duration); amitk_study_set_view_start_time(tb_fly_through->study, start_time); amitk_study_set_view_duration(tb_fly_through->study, duration); break; case OVER_TIME: start_time = tb_fly_through->start_time + i_frame*duration; amitk_study_set_view_start_time(tb_fly_through->study, start_time); break; case OVER_GATES: temp_sets = data_sets; while (temp_sets != NULL) { ds_gate = floor((i_frame/((gdouble) num_frames))*AMITK_DATA_SET_NUM_GATES(temp_sets->data)); amitk_data_set_set_view_start_gate(AMITK_DATA_SET(temp_sets->data), ds_gate); amitk_data_set_set_view_end_gate(AMITK_DATA_SET(temp_sets->data), ds_gate); temp_sets = temp_sets->next; } break; default: /* NOT_DYNAMIC */ break; } dialog_update_position_entry(tb_fly_through); continue_work = amitk_progress_dialog_set_fraction(AMITK_PROGRESS_DIALOG(tb_fly_through->progress_dialog), (i_frame)/((gdouble) num_frames)); /* advance the canvas */ amitk_study_set_view_center(tb_fly_through->study, amitk_space_s2b(tb_fly_through->space, current_point)); /* do any events pending, and make sure the canvas gets updated */ while (gtk_events_pending() || AMITK_CANVAS(tb_fly_through->canvas)->next_update) gtk_main_iteration(); pixbuf = amitk_canvas_get_pixbuf(AMITK_CANVAS(tb_fly_through->canvas)); g_return_if_fail(pixbuf != NULL); return_val = mpeg_encode_frame(mpeg_encode_context, pixbuf); g_object_unref(pixbuf); if (return_val != 1) g_warning(_("encoding of frame %d failed"), i_frame); current_point.z += increment_z; } mpeg_encode_close(mpeg_encode_context); amitk_progress_dialog_set_fraction(AMITK_PROGRESS_DIALOG(tb_fly_through->progress_dialog),2.0); /* reset the canvas */ amitk_study_set_view_start_time(tb_fly_through->study, initial_start); amitk_study_set_view_duration(tb_fly_through->study, initial_duration); /* free up references */ amitk_objects_unref(data_sets); tb_fly_through->in_generation = FALSE; /* done generating */ dialog_set_sensitive(tb_fly_through, TRUE); /* let user change stuff again */ return; } static void dialog_update_position_entry(tb_fly_through_t * tb_fly_through) { gchar * temp_str; AmitkPoint temp_point; temp_point = amitk_space_b2s(tb_fly_through->space, AMITK_STUDY_VIEW_CENTER(tb_fly_through->study)); temp_str = g_strdup_printf("%f", temp_point.z); gtk_entry_set_text(GTK_ENTRY(tb_fly_through->position_entry), temp_str); g_free(temp_str); return; } static void dialog_set_sensitive(tb_fly_through_t * tb_fly_through, gboolean sensitive) { gtk_widget_set_sensitive(tb_fly_through->start_position_button, sensitive); gtk_widget_set_sensitive(tb_fly_through->end_position_button, sensitive); gtk_widget_set_sensitive(tb_fly_through->position_entry, sensitive); gtk_widget_set_sensitive(tb_fly_through->start_position_spin, sensitive); gtk_widget_set_sensitive(tb_fly_through->end_position_spin, sensitive); gtk_widget_set_sensitive(tb_fly_through->duration_spin_button, sensitive); gtk_widget_set_sensitive(GTK_WIDGET(tb_fly_through->canvas), sensitive); if (tb_fly_through->dynamic || tb_fly_through->gated) { gtk_widget_set_sensitive(tb_fly_through->dynamic_type, sensitive); } if (tb_fly_through->dynamic) { gtk_widget_set_sensitive(tb_fly_through->start_frame_spin_button, sensitive); gtk_widget_set_sensitive(tb_fly_through->end_frame_spin_button, sensitive); gtk_widget_set_sensitive(tb_fly_through->start_time_spin_button, sensitive); gtk_widget_set_sensitive(tb_fly_through->end_time_spin_button, sensitive); } gtk_dialog_set_response_sensitive(GTK_DIALOG(tb_fly_through->dialog), AMITK_RESPONSE_EXECUTE, sensitive); } static void dialog_update_entries(tb_fly_through_t * tb_fly_through) { g_signal_handlers_block_by_func(G_OBJECT(tb_fly_through->start_position_spin), G_CALLBACK(change_start_position_spin_cb), tb_fly_through); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->start_position_spin), tb_fly_through->start_z); g_signal_handlers_unblock_by_func(G_OBJECT(tb_fly_through->start_position_spin), G_CALLBACK(change_start_position_spin_cb), tb_fly_through); g_signal_handlers_block_by_func(G_OBJECT(tb_fly_through->end_position_spin), G_CALLBACK(change_end_position_spin_cb), tb_fly_through); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->end_position_spin), tb_fly_through->end_z); g_signal_handlers_unblock_by_func(G_OBJECT(tb_fly_through->end_position_spin), G_CALLBACK(change_end_position_spin_cb), tb_fly_through); g_signal_handlers_block_by_func(G_OBJECT(tb_fly_through->duration_spin_button), G_CALLBACK(change_duration_spin_cb), tb_fly_through); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->duration_spin_button), tb_fly_through->duration); g_signal_handlers_unblock_by_func(G_OBJECT(tb_fly_through->duration_spin_button), G_CALLBACK(change_duration_spin_cb), tb_fly_through); return; } static tb_fly_through_t * tb_fly_through_unref(tb_fly_through_t * tb_fly_through) { g_return_val_if_fail(tb_fly_through != NULL, NULL); gboolean return_val; /* sanity checks */ g_return_val_if_fail(tb_fly_through->reference_count > 0, NULL); /* remove a reference count */ tb_fly_through->reference_count--; /* things to do if we've removed all reference's */ if (tb_fly_through->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_fly_through\n"); #endif if (tb_fly_through->study != NULL) { amitk_object_unref(tb_fly_through->study); tb_fly_through->study = NULL; } if (tb_fly_through->space != NULL) { g_object_unref(tb_fly_through->space); tb_fly_through->space = NULL; } if (tb_fly_through->preferences != NULL) { g_object_unref(tb_fly_through->preferences); tb_fly_through->preferences = NULL; } if (tb_fly_through->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_fly_through->progress_dialog), "delete_event", NULL, &return_val); tb_fly_through->progress_dialog = NULL; } g_free(tb_fly_through); tb_fly_through = NULL; } return tb_fly_through; } /* adds one to the reference count */ //static tb_fly_through_t * fly_through_ref(tb_fly_through_t * fly_through) { // // g_return_val_if_fail(fly_through != NULL, NULL); // // fly_through->reference_count++; // // return fly_through; //} /* allocate and initialize a tb_fly_through data structure */ static tb_fly_through_t * tb_fly_through_init(void) { tb_fly_through_t * tb_fly_through; /* alloc space for the data structure for passing ui info */ if ((tb_fly_through = g_try_new(tb_fly_through_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_fly_through_t")); return NULL; } tb_fly_through->reference_count = 1; /* set any needed parameters */ tb_fly_through->study = NULL; tb_fly_through->space = NULL; tb_fly_through->preferences = NULL; tb_fly_through->start_z = 0.0; tb_fly_through->end_z = 0.0; tb_fly_through->duration = 10.0; /* seconds */ tb_fly_through->in_generation = FALSE; tb_fly_through->start_time = 0.0; tb_fly_through->end_time = 1.0; tb_fly_through->start_frame = 0; tb_fly_through->end_frame = 0; tb_fly_through->type = NOT_DYNAMIC; return tb_fly_through; } void tb_fly_through(AmitkStudy * study, AmitkView view, AmitkPreferences * preferences, GtkWindow * parent) { tb_fly_through_t * tb_fly_through; GtkWidget * packing_table; GtkWidget * right_table; GtkWidget * label; gint table_row=0; AmitkCorners corners; GList * objects; GList * temp_objects; gboolean dynamic = FALSE; gboolean gated = FALSE; gboolean valid; gint temp_end_frame; amide_time_t temp_end_time; amide_time_t temp_start_time; GtkWidget * radio_button1; GtkWidget * radio_button2=NULL; GtkWidget * radio_button3=NULL; GtkWidget * radio_button4=NULL; GtkWidget * radio_button5=NULL; GtkWidget * hbox; GtkWidget * hseparator; AmitkDataSet * temp_ds; /* sanity checks */ g_return_if_fail(AMITK_IS_STUDY(study)); objects = amitk_object_get_selected_children(AMITK_OBJECT(study), AMITK_SELECTION_SELECTED_0, TRUE); if (amitk_data_sets_count(objects, FALSE) == 0) return; tb_fly_through = tb_fly_through_init(); tb_fly_through->study = AMITK_STUDY(amitk_object_copy(AMITK_OBJECT(study))); tb_fly_through->space = amitk_space_get_view_space(view, AMITK_STUDY_CANVAS_LAYOUT(study)); tb_fly_through->preferences = g_object_ref(preferences); /* need to reset the view center, as this gets overwritten in amitk_object_copy because study_add_child gets called */ amitk_study_set_view_center(tb_fly_through->study, AMITK_STUDY_VIEW_CENTER(study)); tb_fly_through->dialog = gtk_dialog_new_with_buttons(_("Fly Through Generation"), parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Generate Fly Through"), AMITK_RESPONSE_EXECUTE, NULL); g_signal_connect(G_OBJECT(tb_fly_through->dialog), "delete_event", G_CALLBACK(delete_event_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->dialog), "destroy", G_CALLBACK(destroy_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->dialog), "response", G_CALLBACK(response_cb), tb_fly_through); gtk_window_set_resizable(GTK_WINDOW(tb_fly_through->dialog), TRUE); /* make the widgets for this dialog box */ packing_table = gtk_table_new(2,3,FALSE); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(tb_fly_through->dialog)->vbox), packing_table); right_table = gtk_table_new(9,2,FALSE); gtk_table_attach(GTK_TABLE(packing_table), right_table, 2,3, 0,2, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("Current Position (mm):")); gtk_table_attach(GTK_TABLE(right_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->position_entry = gtk_entry_new(); gtk_editable_set_editable(GTK_EDITABLE(tb_fly_through->position_entry), FALSE); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->position_entry, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Start Position (mm):")); gtk_table_attach(GTK_TABLE(right_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->start_position_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fly_through->start_position_spin), FALSE); g_signal_connect(G_OBJECT(tb_fly_through->start_position_spin), "value_changed", G_CALLBACK(change_start_position_spin_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->start_position_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->start_position_spin, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("End Position (mm):")); gtk_table_attach(GTK_TABLE(right_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->end_position_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fly_through->end_position_spin), FALSE); g_signal_connect(G_OBJECT(tb_fly_through->end_position_spin), "value_changed", G_CALLBACK(change_end_position_spin_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->end_position_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->end_position_spin, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Movie Duration (sec):")); gtk_table_attach(GTK_TABLE(right_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->duration_spin_button = gtk_spin_button_new_with_range(0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fly_through->duration_spin_button), FALSE); g_signal_connect(G_OBJECT(tb_fly_through->duration_spin_button), "value_changed", G_CALLBACK(change_duration_spin_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->duration_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->duration_spin_button, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* the progress dialog */ tb_fly_through->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_fly_through->dialog)); amitk_progress_dialog_set_text(AMITK_PROGRESS_DIALOG(tb_fly_through->progress_dialog), _("Fly through movie generation")); /* setup the canvas */ tb_fly_through->canvas = amitk_canvas_new(tb_fly_through->study, view, AMITK_VIEW_MODE_SINGLE, AMITK_CANVAS_TYPE_FLY_THROUGH); g_signal_connect(G_OBJECT(tb_fly_through->canvas), "view_changed", G_CALLBACK(view_changed_cb), tb_fly_through); gtk_table_attach(GTK_TABLE(packing_table), tb_fly_through->canvas, 0,2,0,1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); tb_fly_through->start_position_button = gtk_button_new_with_label(_("Set Start Position")); g_signal_connect(G_OBJECT(tb_fly_through->start_position_button), "pressed", G_CALLBACK(set_start_position_pressed_cb), tb_fly_through); gtk_table_attach(GTK_TABLE(packing_table), tb_fly_through->start_position_button, 0,1,1,2, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->end_position_button = gtk_button_new_with_label(_("Set End Position")); g_signal_connect(G_OBJECT(tb_fly_through->end_position_button), "pressed", G_CALLBACK(set_end_position_pressed_cb), tb_fly_through); gtk_table_attach(GTK_TABLE(packing_table), tb_fly_through->end_position_button, 1,2,1,2, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* load up the canvases and get some initial info */ amitk_volumes_get_enclosing_corners(objects, tb_fly_through->space, corners); tb_fly_through->start_z = point_get_component(corners[0], AMITK_AXIS_Z); tb_fly_through->end_z = point_get_component(corners[1], AMITK_AXIS_Z); temp_objects = objects; valid = FALSE; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { temp_ds = AMITK_DATA_SET(temp_objects->data); temp_end_frame = AMITK_DATA_SET_NUM_FRAMES(temp_ds)-1; temp_start_time = amitk_data_set_get_start_time(temp_ds,0); temp_end_time = amitk_data_set_get_end_time(temp_ds, temp_end_frame); if (!valid) { tb_fly_through->end_frame = temp_end_frame; tb_fly_through->start_time = temp_start_time; tb_fly_through->end_time = temp_end_time; } else { if (temp_end_frame > tb_fly_through->end_frame) tb_fly_through->end_frame = temp_end_frame; if (temp_start_time < tb_fly_through->start_time) tb_fly_through->start_time = temp_start_time; if (temp_end_time > tb_fly_through->end_time) tb_fly_through->end_time = temp_end_time; } valid = TRUE; if (AMITK_DATA_SET_NUM_FRAMES(temp_objects->data) > 1) dynamic = TRUE; if (AMITK_DATA_SET_NUM_GATES(temp_objects->data) > 1) gated = TRUE; } temp_objects = temp_objects->next; } tb_fly_through->dynamic=dynamic; tb_fly_through->gated=gated; /* garbage collection */ amitk_objects_unref(objects); if (tb_fly_through->dynamic || tb_fly_through->gated) { /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(right_table), hseparator, 0,2, table_row, table_row+1,GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* do we want to make a movie over time or over frames */ label = gtk_label_new(_("Dynamic Movie:")); gtk_table_attach(GTK_TABLE(right_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(right_table), hbox,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); table_row++; /* the radio buttons */ radio_button1 = gtk_radio_button_new_with_label(NULL, _("No")); gtk_box_pack_start(GTK_BOX(hbox), radio_button1, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button1), "dynamic_type", GINT_TO_POINTER(NOT_DYNAMIC)); tb_fly_through->dynamic_type = radio_button1; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button1), TRUE); if (tb_fly_through->dynamic) { radio_button2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over time")); gtk_box_pack_start(GTK_BOX(hbox), radio_button2, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button2), "dynamic_type", GINT_TO_POINTER(OVER_TIME)); radio_button3 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over frames")); gtk_box_pack_start(GTK_BOX(hbox), radio_button3, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button3), "dynamic_type", GINT_TO_POINTER(OVER_FRAMES)); } hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(right_table), hbox,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); table_row++; if (tb_fly_through->dynamic) { radio_button4 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over frames smoothed")); gtk_box_pack_start(GTK_BOX(hbox), radio_button4, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button4), "dynamic_type", GINT_TO_POINTER(OVER_FRAMES_SMOOTHED)); } if (tb_fly_through->gated) { radio_button5 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over gates")); gtk_box_pack_start(GTK_BOX(hbox), radio_button5, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button5), "dynamic_type", GINT_TO_POINTER(OVER_GATES)); } g_signal_connect(G_OBJECT(radio_button1), "clicked", G_CALLBACK(dynamic_type_cb), tb_fly_through); if (tb_fly_through->dynamic) { g_signal_connect(G_OBJECT(radio_button2), "clicked", G_CALLBACK(dynamic_type_cb), tb_fly_through); g_signal_connect(G_OBJECT(radio_button3), "clicked", G_CALLBACK(dynamic_type_cb), tb_fly_through); g_signal_connect(G_OBJECT(radio_button4), "clicked", G_CALLBACK(dynamic_type_cb), tb_fly_through); } if (tb_fly_through->gated) { g_signal_connect(G_OBJECT(radio_button5), "clicked", G_CALLBACK(dynamic_type_cb), tb_fly_through); } } if (tb_fly_through->dynamic) { /* widgets to specify the start and end times */ tb_fly_through->start_time_label = gtk_label_new(_("Start Time (s)")); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->start_time_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); tb_fly_through->start_frame_label = gtk_label_new(_("Start Frame")); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->start_frame_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); tb_fly_through->start_time_spin_button = gtk_spin_button_new_with_range(tb_fly_through->start_time, tb_fly_through->end_time, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fly_through->start_time_spin_button), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->start_time_spin_button), tb_fly_through->start_time); g_signal_connect(G_OBJECT(tb_fly_through->start_time_spin_button), "value_changed", G_CALLBACK(change_start_time_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->start_time_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->start_time_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->start_frame_spin_button = gtk_spin_button_new_with_range(tb_fly_through->start_frame,tb_fly_through->end_frame+0.1, 1.0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(tb_fly_through->start_frame_spin_button),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->start_frame_spin_button), tb_fly_through->start_frame); g_signal_connect(G_OBJECT(tb_fly_through->start_frame_spin_button), "value_changed", G_CALLBACK(change_start_frame_cb), tb_fly_through); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->start_frame_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; tb_fly_through->end_time_label = gtk_label_new(_("End Time (s)")); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->end_time_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); tb_fly_through->end_frame_label = gtk_label_new(_("End Frame")); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->end_frame_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); tb_fly_through->end_time_spin_button = gtk_spin_button_new_with_range(tb_fly_through->start_time, tb_fly_through->end_time, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_fly_through->end_time_spin_button), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->end_time_spin_button), tb_fly_through->end_time); g_signal_connect(G_OBJECT(tb_fly_through->end_time_spin_button), "value_changed", G_CALLBACK(change_end_time_cb), tb_fly_through); g_signal_connect(G_OBJECT(tb_fly_through->end_time_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->end_time_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); tb_fly_through->end_frame_spin_button = gtk_spin_button_new_with_range(tb_fly_through->start_frame,tb_fly_through->end_frame+0.1, 1.0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(tb_fly_through->end_frame_spin_button),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_fly_through->end_frame_spin_button), tb_fly_through->end_frame); g_signal_connect(G_OBJECT(tb_fly_through->end_frame_spin_button), "value_changed", G_CALLBACK(change_end_frame_cb), tb_fly_through); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->end_frame_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; tb_fly_through->time_on_image_label = gtk_label_new(_("Display time on image")); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->time_on_image_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); tb_fly_through->time_on_image_button = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_fly_through->time_on_image_button), FALSE); g_signal_connect(G_OBJECT(tb_fly_through->time_on_image_button), "toggled", G_CALLBACK(time_on_image_cb), tb_fly_through); gtk_table_attach(GTK_TABLE(right_table), tb_fly_through->time_on_image_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; } /* update entries */ dialog_update_position_entry(tb_fly_through); dialog_update_entries(tb_fly_through); /* and show all our widgets */ gtk_widget_show_all(tb_fly_through->dialog); /* and hide the appropriate widgets */ if (tb_fly_through->dynamic) { gtk_widget_hide(tb_fly_through->start_frame_label); gtk_widget_hide(tb_fly_through->start_frame_spin_button); gtk_widget_hide(tb_fly_through->end_frame_label); gtk_widget_hide(tb_fly_through->end_frame_spin_button); gtk_widget_hide(tb_fly_through->start_time_label); gtk_widget_hide(tb_fly_through->start_time_spin_button); gtk_widget_hide(tb_fly_through->end_time_label); gtk_widget_hide(tb_fly_through->end_time_spin_button); gtk_widget_hide(tb_fly_through->time_on_image_label); gtk_widget_hide(tb_fly_through->time_on_image_button); } return; } #endif /* AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT */ amide-1.0.6/amide-current/src/tb_fly_through.h000066400000000000000000000024431423227705100213210ustar00rootroot00000000000000/* tb_fly_through.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2002-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) #ifndef __TB_FLY_THROUGH_H__ #define __TB_FLY_THROUGH_H__ /* header files that are always needed with this file */ #include "amitk_study.h" /* external functions */ void tb_fly_through(AmitkStudy * study, AmitkView view, AmitkPreferences * preferences, GtkWindow * parent); #endif /* TB_FLY_THROUGH_H */ #endif /* AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT */ amide-1.0.6/amide-current/src/tb_math.c000066400000000000000000000674701423227705100177260ustar00rootroot00000000000000/* tb_math.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2006-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_progress_dialog.h" #include "tb_math.h" #define SPIN_BUTTON_X_SIZE 100 #define LABEL_WIDTH 375 static gchar * data_set_error_page_text = N_("There are no data sets in this study to perform " "mathematical operations on."); static gchar * start_page_text = N_("Welcome to the data set math wizard, used for " "performing mathematical operations on and between medical " "image data sets.\n" "\n" "Note - If performing an operation between two data sets, you " "will likely get more pleasing results if the data sets in " "question are set to trilinear interpolation mode."); typedef enum { COLUMN_DATA_SET_NAME, COLUMN_DATA_SET_POINTER, NUM_DATA_SET_COLUMNS } data_set_column_t; typedef enum { COLUMN_OPERATION_NAME, COLUMN_OPERATION_NUMBER, NUM_OPERATION_COLUMNS } point_column_t; typedef enum { INTRO_PAGE, OPERATION_PAGE, DATA_SETS_PAGE, PARAMETERS_PAGE, CONCLUSION_PAGE, NUM_PAGES } which_page_t; /* data structures */ typedef struct tb_math_t { GtkWidget * dialog; GtkWidget * page[NUM_PAGES]; GtkWidget * progress_dialog; GtkWidget * scrolled_ds1; GtkWidget * list_ds1; GtkWidget * scrolled_ds2; GtkWidget * list_ds2; GtkWidget * list_operation; GtkWidget * parameter0_label; GtkWidget * parameter0_spin; GtkWidget * parameter1_label; GtkWidget * parameter1_spin; GtkWidget * by_frames_check_button; GtkWidget * maintain_ds1_dim_check_button; AmitkStudy * study; gint ds_count; AmitkDataSet * ds1; AmitkDataSet * ds2; gint operation; amide_data_t parameter0; amide_data_t parameter1; gboolean by_frames; gboolean maintain_ds1_dim; guint reference_count; } tb_math_t; static void operation_update_model(tb_math_t * math); static void data_sets_update_model(tb_math_t * math); static void parameters_update_page(tb_math_t * math); static void operation_selection_changed_cb(GtkTreeSelection * selection, gpointer data); static void data_set_selection_changed_cb(GtkTreeSelection * selection, gpointer data); static void parameter0_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void parameter1_spinner_cb(GtkSpinButton * spin_button, gpointer data); static void by_frames_cb(GtkWidget * widget, gpointer data); static void maintain_ds1_dim_cb(GtkWidget * widget, gpointer data); static tb_math_t * tb_math_free(tb_math_t * math); static tb_math_t * tb_math_init(void); static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data); static void apply_cb(GtkAssistant * assistant, gpointer data); static void close_cb(GtkAssistant * assistant, gpointer data); static GtkWidget * create_operation_page(tb_math_t * tb_math); static GtkWidget * create_data_sets_page(tb_math_t * tb_math); static GtkWidget * create_parameters_page(tb_math_t * tb_math); static void operation_update_model(tb_math_t * tb_math) { GtkTreeIter iter; GtkTreeModel * model; gint i_operation; GtkTreeSelection *selection; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_math->list_operation)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_math->list_operation)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ /* put in the unary operations */ for (i_operation=0; i_operation < AMITK_OPERATION_UNARY_NUM; i_operation++) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_OPERATION_NAME, amitk_operation_unary_get_name(i_operation), COLUMN_OPERATION_NUMBER, i_operation, -1); if (i_operation == tb_math->operation) gtk_tree_selection_select_iter (selection, &iter); } /* put in the binary operations if we have more then one data set */ if (tb_math->ds_count > 1) { for (i_operation=AMITK_OPERATION_UNARY_NUM; i_operation < AMITK_OPERATION_UNARY_NUM+AMITK_OPERATION_BINARY_NUM; i_operation++) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_OPERATION_NAME, amitk_operation_binary_get_name(i_operation-AMITK_OPERATION_UNARY_NUM), COLUMN_OPERATION_NUMBER, i_operation, -1); if (i_operation == tb_math->operation) gtk_tree_selection_select_iter (selection, &iter); } } return; } static void data_sets_update_model(tb_math_t * tb_math) { GtkTreeIter iter; GtkTreeModel * model; GtkTreeSelection *selection; GList * data_sets; GList * temp_data_sets; gint count; /* update data set 1 */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_math->list_ds1)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_math->list_ds1)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ data_sets = amitk_object_get_children_of_type(AMITK_OBJECT(tb_math->study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); count = 0; temp_data_sets = data_sets; while (temp_data_sets != NULL) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set (GTK_LIST_STORE(model), &iter, COLUMN_DATA_SET_NAME, AMITK_OBJECT_NAME(temp_data_sets->data), COLUMN_DATA_SET_POINTER, temp_data_sets->data, -1); if ( ((tb_math->ds1 == NULL) && (count == 0)) || (tb_math->ds1 == temp_data_sets->data)) gtk_tree_selection_select_iter (selection, &iter); count++; temp_data_sets = temp_data_sets->next; } /* update the data set 2 */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_math->list_ds2)); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tb_math->list_ds2)); gtk_list_store_clear(GTK_LIST_STORE(model)); /* make sure the list is clear */ if (tb_math->operation < AMITK_OPERATION_UNARY_NUM) { gtk_widget_hide(tb_math->scrolled_ds2); } else { /* binary operation */ gtk_widget_show(tb_math->scrolled_ds2); temp_data_sets = data_sets; count = 0; while (temp_data_sets != NULL) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); /* Acquire an iterator */ gtk_list_store_set (GTK_LIST_STORE(model), &iter, COLUMN_DATA_SET_NAME, AMITK_OBJECT_NAME(temp_data_sets->data), COLUMN_DATA_SET_POINTER, temp_data_sets->data, -1); if (((tb_math->ds2 == NULL) && (tb_math->ds1 != temp_data_sets->data)) || (tb_math->ds2 == temp_data_sets->data)) if (count == 1) gtk_tree_selection_select_iter (selection, &iter); count++; temp_data_sets = temp_data_sets->next; } } if (data_sets != NULL) data_sets = amitk_objects_unref(data_sets); return; } static void parameters_update_page(tb_math_t * tb_math) { if (tb_math->operation == AMITK_OPERATION_UNARY_RESCALE) { gtk_label_set_text(GTK_LABEL(tb_math->parameter0_label), _("Set to 0 below:")); gtk_widget_show(tb_math->parameter0_label); gtk_widget_show(tb_math->parameter0_spin); gtk_label_set_text(GTK_LABEL(tb_math->parameter1_label), _("Set to 1 above:")); gtk_widget_show(tb_math->parameter1_label); gtk_widget_show(tb_math->parameter1_spin); gtk_widget_hide(tb_math->by_frames_check_button); gtk_widget_hide(tb_math->maintain_ds1_dim_check_button); } else if (tb_math->operation < AMITK_OPERATION_UNARY_NUM){ /* other unary operations */ gtk_widget_hide(tb_math->parameter0_label); gtk_widget_hide(tb_math->parameter0_spin); gtk_widget_hide(tb_math->parameter1_label); gtk_widget_hide(tb_math->parameter1_spin); gtk_widget_hide(tb_math->by_frames_check_button); gtk_widget_hide(tb_math->maintain_ds1_dim_check_button); } else if (tb_math->operation == (AMITK_OPERATION_UNARY_NUM+AMITK_OPERATION_BINARY_DIVISION)) { gtk_label_set_text(GTK_LABEL(tb_math->parameter0_label), _("Set to 0 if Divisor below:")); gtk_widget_show(tb_math->parameter0_label); gtk_widget_show(tb_math->parameter0_spin); gtk_widget_hide(tb_math->parameter1_label); gtk_widget_hide(tb_math->parameter1_spin); gtk_widget_show(tb_math->by_frames_check_button); gtk_widget_show(tb_math->maintain_ds1_dim_check_button); } else if (tb_math->operation == (AMITK_OPERATION_UNARY_NUM+AMITK_OPERATION_BINARY_T2STAR)) { gtk_label_set_text(GTK_LABEL(tb_math->parameter0_label), _("Data Set 1 echo time (ms):")); gtk_widget_show(tb_math->parameter0_label); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_math->parameter0_spin), AMITK_DATA_SET_ECHO_TIME(tb_math->ds1)); gtk_widget_show(tb_math->parameter0_spin); gtk_label_set_text(GTK_LABEL(tb_math->parameter1_label), _("Data Set 2 echo time (ms):")); gtk_widget_show(tb_math->parameter1_label); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_math->parameter1_spin), AMITK_DATA_SET_ECHO_TIME(tb_math->ds2)); gtk_widget_show(tb_math->parameter1_spin); gtk_widget_show(tb_math->by_frames_check_button); gtk_widget_show(tb_math->maintain_ds1_dim_check_button); } else{ /* other binary operations */ gtk_widget_hide(tb_math->parameter0_label); gtk_widget_hide(tb_math->parameter0_spin); gtk_widget_hide(tb_math->parameter1_label); gtk_widget_hide(tb_math->parameter1_spin); gtk_widget_show(tb_math->by_frames_check_button); gtk_widget_show(tb_math->maintain_ds1_dim_check_button); } return; } static void operation_selection_changed_cb(GtkTreeSelection * selection, gpointer data) { tb_math_t * tb_math = data; gint operation; GtkTreeIter iter; GtkTreeModel * model; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get(model, &iter, COLUMN_OPERATION_NUMBER, &operation, -1); tb_math->operation = operation; } return; } static void data_set_selection_changed_cb(GtkTreeSelection * selection, gpointer data) { tb_math_t * tb_math = data; AmitkDataSet * ds; gboolean which_ds; gboolean can_continue; GtkTreeIter iter; GtkTreeModel * model; which_ds = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(selection), "which_ds")); if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get(model, &iter, COLUMN_DATA_SET_POINTER, &ds, -1); g_return_if_fail(AMITK_IS_DATA_SET(ds)); switch(which_ds) { case 0: if (tb_math->ds1 != NULL) amitk_object_unref(tb_math->ds1); tb_math->ds1 = amitk_object_ref(ds); break; case 1: if (tb_math->ds2 != NULL) amitk_object_unref(tb_math->ds2); tb_math->ds2 = amitk_object_ref(ds); break; default: g_error("unexpected case in %s at line %d", __FILE__, __LINE__); break; } } if (tb_math->operation < AMITK_OPERATION_UNARY_NUM) can_continue = (tb_math->ds1 != NULL); else /* binary operation */ can_continue = ((tb_math->ds1 != NULL) && (tb_math->ds2 != NULL) && (tb_math->ds1 != tb_math->ds2)); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_math->dialog), tb_math->page[DATA_SETS_PAGE], can_continue); return; } static void parameter0_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_math_t * tb_math = data; tb_math->parameter0 = gtk_spin_button_get_value(spin_button); return; } static void parameter1_spinner_cb(GtkSpinButton * spin_button, gpointer data) { tb_math_t * tb_math = data; tb_math->parameter1 = gtk_spin_button_get_value(spin_button); return; } static void by_frames_cb(GtkWidget * widget, gpointer data) { tb_math_t * tb_math = data; tb_math->by_frames = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); return; } static void maintain_ds1_dim_cb(GtkWidget * widget, gpointer data) { tb_math_t * tb_math = data; tb_math->maintain_ds1_dim = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); return; } static void prepare_page_cb(GtkAssistant * wizard, GtkWidget * page, gpointer data) { tb_math_t * tb_math = data; which_page_t which_page; gchar * temp_string; which_page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(page), "which_page")); switch(which_page) { case OPERATION_PAGE: operation_update_model(tb_math); break; case DATA_SETS_PAGE: data_sets_update_model(tb_math); // gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_math->dialog), page, // (tb_math->ds1 != NULL) && (tb_math->ds2 != NULL) && (tb_math->ds1 != tb_math->ds2)); break; case PARAMETERS_PAGE: parameters_update_page(tb_math); break; case CONCLUSION_PAGE: temp_string = g_strdup_printf(_("A new data set will be created with the math operation, press Apply to calculate this data set, or Cancel to quit.")); gtk_label_set_text(GTK_LABEL(page), temp_string); g_free(temp_string); break; default: break; } return; } /* function called when the finish button is hit */ static void apply_cb(GtkAssistant * assistant, gpointer data) { tb_math_t * tb_math = data; AmitkDataSet * output_ds; /* sanity check */ g_return_if_fail(tb_math->ds1 != NULL); /* apply the math */ if (tb_math->operation < AMITK_OPERATION_UNARY_NUM) { output_ds = amitk_data_sets_math_unary(tb_math->ds1, tb_math->operation, tb_math->parameter0, tb_math->parameter1, amitk_progress_dialog_update, tb_math->progress_dialog); } else { g_return_if_fail(tb_math->ds2 != NULL); /* sanity check */ output_ds = amitk_data_sets_math_binary(tb_math->ds1, tb_math->ds2, tb_math->operation-AMITK_OPERATION_UNARY_NUM, tb_math->parameter0, tb_math->parameter1, tb_math->by_frames, tb_math->maintain_ds1_dim, amitk_progress_dialog_update, tb_math->progress_dialog); } if (output_ds != NULL) { amitk_object_add_child(AMITK_OBJECT(tb_math->study), AMITK_OBJECT(output_ds)); amitk_object_unref(output_ds); } else { g_warning(_("Math operation failed - results not added to study")); } return; } /* function called to cancel the dialog */ static void close_cb(GtkAssistant * assistant, gpointer data) { tb_math_t * tb_math = data; GtkWidget * dialog = tb_math->dialog; tb_math = tb_math_free(tb_math); /* trash collection */ gtk_widget_destroy(dialog); return; } /* destroy a math data structure */ static tb_math_t * tb_math_free(tb_math_t * tb_math) { gboolean return_val; g_return_val_if_fail(tb_math != NULL, NULL); /* sanity checks */ g_return_val_if_fail(tb_math->reference_count > 0, NULL); /* remove a reference count */ tb_math->reference_count--; /* things to do if we've removed all reference's */ if (tb_math->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_math\n"); #endif if (tb_math->study != NULL) { tb_math->study = amitk_object_unref(tb_math->study); tb_math->study = NULL; } if (tb_math->ds1 != NULL) { amitk_object_unref(tb_math->ds1); tb_math->ds1 = NULL; } if (tb_math->ds2 != NULL) { amitk_object_unref(tb_math->ds2); tb_math->ds2 = NULL; } if (tb_math->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(tb_math->progress_dialog), "delete_event", NULL, &return_val); tb_math->progress_dialog = NULL; } g_free(tb_math); tb_math = NULL; } return tb_math; } /* allocate and initialize a math data structure */ static tb_math_t * tb_math_init(void) { tb_math_t * tb_math; /* alloc space for the data structure for passing ui info */ if ((tb_math = g_try_new(tb_math_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_math_t")); return NULL; } tb_math->reference_count = 1; tb_math->dialog = NULL; tb_math->study = NULL; tb_math->ds_count=0; tb_math->ds1 = NULL; tb_math->ds2 = NULL; tb_math->operation = AMITK_OPERATION_BINARY_ADD; tb_math->parameter0 = 0.0; tb_math->parameter1 = 0.0; tb_math->by_frames = FALSE; tb_math->maintain_ds1_dim = FALSE; return tb_math; } static GtkWidget * create_operation_page(tb_math_t * tb_math) { GtkWidget * table; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; table = gtk_table_new(3,2,FALSE); store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); tb_math->list_operation = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Math Operation"), renderer, "text", COLUMN_OPERATION_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_math->list_operation), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_math->list_operation)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(operation_selection_changed_cb), tb_math); gtk_table_attach(GTK_TABLE(table),tb_math->list_operation, 0,1,0,1, GTK_FILL|GTK_EXPAND, GTK_FILL | GTK_EXPAND,X_PADDING, Y_PADDING); return table; } static GtkWidget * create_data_sets_page(tb_math_t * tb_math) { GtkWidget * table; GtkWidget * vseparator; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; table = gtk_table_new(3,3,FALSE); /* the first data set */ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); tb_math->list_ds1 = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Data Set 1:"), renderer, "text", COLUMN_DATA_SET_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_math->list_ds1), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_math->list_ds1)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_object_set_data(G_OBJECT(selection), "which_ds", GINT_TO_POINTER(0)); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(data_set_selection_changed_cb), tb_math); tb_math->scrolled_ds1 = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tb_math->scrolled_ds1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tb_math->scrolled_ds1), tb_math->list_ds1); gtk_table_attach(GTK_TABLE(table),tb_math->scrolled_ds1, 0,1,0,1, GTK_FILL|GTK_EXPAND, GTK_FILL | GTK_EXPAND,X_PADDING, Y_PADDING); vseparator = gtk_vseparator_new(); gtk_table_attach(GTK_TABLE(table), vseparator, 1,2,0,2, 0, GTK_FILL, X_PADDING, Y_PADDING); /* the second data set */ store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); tb_math->list_ds2 = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes(_("Data Set 2:"), renderer, "text", COLUMN_DATA_SET_NAME, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tb_math->list_ds2), column); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tb_math->list_ds2)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); g_object_set_data(G_OBJECT(selection), "which_ds", GINT_TO_POINTER(1)); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(data_set_selection_changed_cb), tb_math); tb_math->scrolled_ds2 = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tb_math->scrolled_ds2), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tb_math->scrolled_ds2), tb_math->list_ds2); gtk_table_attach(GTK_TABLE(table),tb_math->scrolled_ds2, 2,3,0,1, GTK_FILL|GTK_EXPAND, GTK_FILL | GTK_EXPAND,X_PADDING, Y_PADDING); return table; } static GtkWidget * create_parameters_page(tb_math_t * tb_math) { GtkWidget * table; gint table_row = 0; table = gtk_table_new(3,2,FALSE); tb_math->parameter0_label = gtk_label_new(NULL); /* label set in parameter_page_update function */ gtk_table_attach(GTK_TABLE(table), tb_math->parameter0_label, 0,1, table_row,table_row+1, FALSE, FALSE, X_PADDING, Y_PADDING); tb_math->parameter0_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_math->parameter0_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_math->parameter0_spin), tb_math->parameter0); gtk_widget_set_size_request(tb_math->parameter0_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_math->parameter0_spin), "value_changed", G_CALLBACK(parameter0_spinner_cb), tb_math); g_signal_connect(G_OBJECT(tb_math->parameter0_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), tb_math->parameter0_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; tb_math->parameter1_label = gtk_label_new(NULL); /* label set in parameter_page_update function */ gtk_table_attach(GTK_TABLE(table), tb_math->parameter1_label, 0,1, table_row,table_row+1, FALSE, FALSE, X_PADDING, Y_PADDING); tb_math->parameter1_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_math->parameter1_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_math->parameter1_spin), tb_math->parameter1); gtk_widget_set_size_request(tb_math->parameter1_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(tb_math->parameter1_spin), "value_changed", G_CALLBACK(parameter1_spinner_cb), tb_math); g_signal_connect(G_OBJECT(tb_math->parameter1_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(table), tb_math->parameter1_spin, 1,2, table_row,table_row+1, FALSE,FALSE, X_PADDING, Y_PADDING); table_row++; tb_math->by_frames_check_button = gtk_check_button_new_with_label (_("Do binary operation frame-by-frame (default is by time)")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_math->by_frames_check_button), tb_math->by_frames); g_signal_connect(G_OBJECT(tb_math->by_frames_check_button), "toggled", G_CALLBACK(by_frames_cb),tb_math); gtk_table_attach(GTK_TABLE(table), tb_math->by_frames_check_button,0,2,table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; tb_math->maintain_ds1_dim_check_button = gtk_check_button_new_with_label(_("Maintain data set 1 dimensions (default is superset of both data sets)")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb_math->maintain_ds1_dim_check_button), tb_math->maintain_ds1_dim); g_signal_connect(G_OBJECT(tb_math->maintain_ds1_dim_check_button), "toggled", G_CALLBACK(maintain_ds1_dim_cb),tb_math); gtk_table_attach(GTK_TABLE(table), tb_math->maintain_ds1_dim_check_button,0,2,table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; return table; } /* function that sets up an image math dialog */ void tb_math(AmitkStudy * study, GtkWindow * parent) { tb_math_t * tb_math; GdkPixbuf * logo; GList * data_sets; gint i; g_return_if_fail(AMITK_IS_STUDY(study)); tb_math = tb_math_init(); tb_math->study = amitk_object_ref(AMITK_OBJECT(study)); tb_math->dialog = gtk_assistant_new(); gtk_window_set_transient_for(GTK_WINDOW(tb_math->dialog), parent); gtk_window_set_destroy_with_parent(GTK_WINDOW(tb_math->dialog), TRUE); g_signal_connect(G_OBJECT(tb_math->dialog), "cancel", G_CALLBACK(close_cb), tb_math); g_signal_connect(G_OBJECT(tb_math->dialog), "close", G_CALLBACK(close_cb), tb_math); g_signal_connect(G_OBJECT(tb_math->dialog), "apply", G_CALLBACK(apply_cb), tb_math); g_signal_connect(G_OBJECT(tb_math->dialog), "prepare", G_CALLBACK(prepare_page_cb), tb_math); tb_math->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(tb_math->dialog)); /* --------------- initial page ------------------ */ /* figure out how many data sets there are */ data_sets = amitk_object_get_children_of_type(AMITK_OBJECT(tb_math->study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); tb_math->ds_count = amitk_data_sets_count(data_sets, TRUE); if (data_sets != NULL) data_sets = amitk_objects_unref(data_sets); tb_math->page[INTRO_PAGE]= gtk_label_new((tb_math->ds_count >= 1) ? _(start_page_text) : _(data_set_error_page_text)); gtk_widget_set_size_request(tb_math->page[INTRO_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_math->page[INTRO_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_math->dialog), tb_math->page[INTRO_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_math->dialog), tb_math->page[INTRO_PAGE], _("Data Set Math Wizard")); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_math->dialog), tb_math->page[INTRO_PAGE], GTK_ASSISTANT_PAGE_INTRO); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_math->dialog), tb_math->page[INTRO_PAGE], tb_math->ds_count >= 1); /*------------------ pick your operation page ------------------ */ tb_math->page[OPERATION_PAGE] = create_operation_page(tb_math); gtk_assistant_append_page(GTK_ASSISTANT(tb_math->dialog), tb_math->page[OPERATION_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_math->dialog), tb_math->page[OPERATION_PAGE], _("Operation Selection")); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_math->dialog),tb_math->page[OPERATION_PAGE], TRUE); /* we always have one selected */ /*------------------ pick your data set page ------------------ */ tb_math->page[DATA_SETS_PAGE] = create_data_sets_page(tb_math); gtk_assistant_append_page(GTK_ASSISTANT(tb_math->dialog), tb_math->page[DATA_SETS_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_math->dialog), tb_math->page[DATA_SETS_PAGE], _("Data Set Selection")); /*------------------ additional parameters ------------------ */ tb_math->page[PARAMETERS_PAGE] = create_parameters_page(tb_math); gtk_assistant_append_page(GTK_ASSISTANT(tb_math->dialog), tb_math->page[PARAMETERS_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_math->dialog), tb_math->page[PARAMETERS_PAGE], _("Parameter Selection")); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_math->dialog),tb_math->page[PARAMETERS_PAGE], TRUE); /* ---------------- conclusion page ---------------------------------- */ tb_math->page[CONCLUSION_PAGE] = gtk_label_new(""); gtk_widget_set_size_request(tb_math->page[CONCLUSION_PAGE],LABEL_WIDTH, -1); gtk_label_set_line_wrap(GTK_LABEL(tb_math->page[CONCLUSION_PAGE]), TRUE); gtk_assistant_append_page(GTK_ASSISTANT(tb_math->dialog), tb_math->page[CONCLUSION_PAGE]); gtk_assistant_set_page_title(GTK_ASSISTANT(tb_math->dialog), tb_math->page[CONCLUSION_PAGE], _("Conclusion")); gtk_assistant_set_page_type(GTK_ASSISTANT(tb_math->dialog), tb_math->page[CONCLUSION_PAGE], GTK_ASSISTANT_PAGE_CONFIRM); gtk_assistant_set_page_complete(GTK_ASSISTANT(tb_math->dialog), tb_math->page[CONCLUSION_PAGE], TRUE); /* always set to complete here */ logo = gtk_widget_render_icon(GTK_WIDGET(tb_math->dialog), "amide_icon_logo", GTK_ICON_SIZE_DIALOG, 0); for (i=0; idialog), tb_math->page[i], logo); g_object_set_data(G_OBJECT(tb_math->page[i]),"which_page", GINT_TO_POINTER(i)); } g_object_unref(logo); gtk_widget_show_all(tb_math->dialog); return; } amide-1.0.6/amide-current/src/tb_math.h000066400000000000000000000017741423227705100177260ustar00rootroot00000000000000/* tb_math.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2006-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_study.h" /* external functions */ void tb_math(AmitkStudy * study, GtkWindow * parent); amide-1.0.6/amide-current/src/tb_profile.c000066400000000000000000001234621423227705100204270ustar00rootroot00000000000000/* tb_profile.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amide.h" #include "amitk_study.h" #include "tb_profile.h" #include "ui_common.h" #ifdef AMIDE_LIBGSL_SUPPORT #include #include #endif #define CANVAS_WIDTH 400 #define CANVAS_HEIGHT 300 #define TEXT_HEIGHT 12.0 #define EDGE_SPACING 2.0 #define NUM_COLOR_ROTATIONS 6 guint32 color_rotation[NUM_COLOR_ROTATIONS] = { 0x00FFFFFF, 0xFFFF00FF, 0xFF00FFFF, 0xFF0000FF, 0x00FF00FF, 0x0000FFFF, }; /* data structures */ typedef struct tb_profile_t { GtkWidget * dialog; AmitkStudy * study; AmitkPreferences * preferences; GtkWidget * angle_spin; guint idle_handler_id; GtkWidget * canvas; GtkWidget * text; gdouble min_x, max_x; gdouble scale_x; GPtrArray * results; /* gaussian fit stuff */ GnomeCanvasItem * x_label[2]; gboolean calc_gaussian_fit; gdouble initial_x; gdouble x_limit[2]; gboolean fix_x; gboolean fix_dc_zero; GnomeCanvasItem * x_limit_item[2]; guint reference_count; } tb_profile_t; typedef struct result_t { gchar * name; GPtrArray * line; GnomeCanvasItem * line_item; amide_data_t min_y, max_y, peak_location; gdouble scale_y; GnomeCanvasItem * y_label[2]; GnomeCanvasItem * legend; /* gaussian fit stuff */ gdouble b_fit, b_err; gdouble p_fit, p_err; gdouble c_fit, c_err; gdouble s_fit, s_err; gint iterations; gint status; GnomeCanvasItem * fit_item; } result_t; static GPtrArray * results_free(GPtrArray * results); static tb_profile_t * profile_free(tb_profile_t * tb_profile); static tb_profile_t * profile_init(void); #ifdef AMIDE_LIBGSL_SUPPORT static gboolean canvas_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void calc_gaussian_fit_cb(GtkWidget * button, gpointer data); static void fix_x_cb(GtkWidget * widget, gpointer data); static void fix_dc_zero_cb(GtkWidget * widget, gpointer data); static double calc_gaussian(double b, double p, double c, double s, double loc); static int gaussian_f(const gsl_vector * func_p, void *params, gsl_vector * f); static int gaussian_df (const gsl_vector * func_p, void *params, gsl_matrix * J); static int gaussian_fdf (const gsl_vector * func_p, void *params, gsl_vector * f, gsl_matrix * J); static void fit_gaussian(tb_profile_t * tb_profile); static void display_gaussian_fit(tb_profile_t * tb_profile); #endif static void export_profiles(tb_profile_t * tb_profile); static void save_profiles(const gchar * save_filename, tb_profile_t * tb_profile); static void recalc_profiles(tb_profile_t * tb_profile); static gboolean update_while_idle(gpointer data); static void response_cb (GtkDialog * dialog, gint response_id, gpointer data); static void destroy_cb(GtkObject * object, gpointer data); static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * delete_event, gpointer data); static void view_center_changed_cb(AmitkStudy * study, gpointer data); static void selections_changed_cb(AmitkObject * object, gpointer data); static void profile_changed_cb(AmitkLineProfile * line_profile, gpointer data); static void profile_switch_view_cb(GtkWidget * widget, gpointer data); static void profile_angle_cb(GtkWidget * widget, gpointer data); static void profile_update_entries(tb_profile_t * tb_profile); static GPtrArray * results_free(GPtrArray * results) { gint i; result_t * result; if (results == NULL) return NULL; for (i=0; i < results->len; i++) { result = g_ptr_array_index(results, i); g_ptr_array_free(result->line, TRUE); if (result->name != NULL) g_free(result->name); if (result->line_item != NULL) gtk_object_destroy(GTK_OBJECT(result->line_item)); if (result->y_label[0] != NULL) gtk_object_destroy(GTK_OBJECT(result->y_label[0])); if (result->y_label[1] != NULL) gtk_object_destroy(GTK_OBJECT(result->y_label[1])); if (result->legend != NULL) gtk_object_destroy(GTK_OBJECT(result->legend)); if (result->fit_item != NULL) gtk_object_destroy(GTK_OBJECT(result->fit_item)); } g_ptr_array_free(results, TRUE); return NULL; } static tb_profile_t * profile_free(tb_profile_t * tb_profile) { /* sanity checks */ g_return_val_if_fail(tb_profile != NULL, NULL); g_return_val_if_fail(tb_profile->reference_count > 0, NULL); /* remove a reference count */ tb_profile->reference_count--; /* things to do if we've removed all reference's */ if (tb_profile->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_profile\n"); #endif if (tb_profile->study != NULL) { /* disconnect any signal handlers */ g_signal_handlers_disconnect_by_func(G_OBJECT(tb_profile->study), view_center_changed_cb, tb_profile); g_signal_handlers_disconnect_by_func(G_OBJECT(tb_profile->study), selections_changed_cb, tb_profile); g_signal_handlers_disconnect_by_func(G_OBJECT(AMITK_STUDY_LINE_PROFILE(tb_profile->study)), profile_changed_cb, tb_profile); amitk_object_unref(tb_profile->study); tb_profile->study = NULL; } if (tb_profile->preferences != NULL) { g_object_unref(tb_profile->preferences); tb_profile->preferences = NULL; } if (tb_profile->idle_handler_id != 0) { g_source_remove(tb_profile->idle_handler_id); tb_profile->idle_handler_id = 0; } if (tb_profile->results != NULL){ tb_profile->results = results_free(tb_profile->results); } g_free(tb_profile); tb_profile = NULL; } #ifdef AMIDE_DEBUG else { g_print("unrefering tb_profile\n"); } #endif return tb_profile; } static tb_profile_t * profile_init(void) { tb_profile_t * tb_profile; if ((tb_profile = g_try_new(tb_profile_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_profile_t")); return NULL; } tb_profile->reference_count = 1; tb_profile->study = NULL; tb_profile->preferences = NULL; tb_profile->dialog = NULL; tb_profile->idle_handler_id = 0; tb_profile->results = NULL; tb_profile->x_label[0] = NULL; tb_profile->x_label[1] = NULL; tb_profile->calc_gaussian_fit = TRUE; tb_profile->initial_x = -1.0; tb_profile->fix_x = FALSE; tb_profile->fix_dc_zero=FALSE; tb_profile->x_limit_item[0] = NULL; tb_profile->x_limit_item[1] = NULL; return tb_profile; } static gchar * results_as_string(tb_profile_t * tb_profile) { gchar * results; result_t * result; AmitkLineProfileDataElement * element; gint i,j; time_t current_time; /* intro information */ time(¤t_time); results = g_strdup_printf(_("# Profiles on Study: %s\tGenerated on: %s"), AMITK_OBJECT_NAME(tb_profile->study), ctime(¤t_time)); for (i=0; i < tb_profile->results->len; i++) { result = g_ptr_array_index(tb_profile->results, i); amitk_append_str(&results, _("#\n# Profile on: %s\n"), result->name); #ifdef AMIDE_LIBGSL_SUPPORT if (tb_profile->calc_gaussian_fit) { amitk_append_str(&results, _("# Gaussian Fit: b + p * e^(-0.5*(x-c)^2/s^2)\n")); amitk_append_str(&results,_("#\titerations used %d, status %s\n"), result->iterations, gsl_strerror(result->status)); if (tb_profile->fix_dc_zero) amitk_append_str(&results,"#\tb = 0 %s\n",_("(fixed)")); else amitk_append_str(&results,"#\tb = %.5g +/- %.5g\n",result->b_fit, result->b_err); amitk_append_str(&results,"#\tp = %.5g +/- %.5g\n",result->p_fit, result->p_err); if (tb_profile->fix_x) amitk_append_str(&results,"#\tc = %.5g mm %s\n",result->c_fit,_("(fixed)")); else amitk_append_str(&results,"#\tc = %.5g +/- %.5g mm\n",result->c_fit, result->c_err); amitk_append_str(&results,"#\ts = %.5g +/- %.5g\n",result->s_fit, result->s_err); amitk_append_str(&results,"#\tfwhm = %.5g +/- %.5g mm\n", SIGMA_TO_FWHM*(result->s_fit), SIGMA_TO_FWHM*(result->s_err)); amitk_append_str(&results,"#\tfwtm = %.5g +/- %.5g mm\n", SIGMA_TO_FWTM*(result->s_fit), SIGMA_TO_FWTM*(result->s_err)); amitk_append_str(&results,"#\n"); } #endif amitk_append_str(&results,_("# x\tvalue\n")); for (j=0; jline->len; j++) { element = g_ptr_array_index(result->line, j); amitk_append_str(&results,"%g\t%g\n", element->location, element->value); } } return results; } /* function to save the generated profile */ static void export_profiles(tb_profile_t * tb_profile) { GtkWidget * file_chooser; gchar * temp_string; GList * data_sets; GList * temp_data_sets; gchar * filename; /* sanity checks */ g_return_if_fail(tb_profile != NULL); data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(tb_profile->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_ANY, TRUE); g_return_if_fail(data_sets != NULL); /* the rest of this function runs the file selection dialog box */ file_chooser = gtk_file_chooser_dialog_new(_("Export Profile"), GTK_WINDOW(tb_profile->dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(tb_profile->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ filename = g_strdup_printf("%s_profile_{%s", AMITK_OBJECT_NAME(tb_profile->study), AMITK_OBJECT_NAME(data_sets->data)); temp_data_sets = data_sets->next; while (temp_data_sets != NULL) { temp_string = g_strdup_printf("%s+%s",filename,AMITK_OBJECT_NAME(temp_data_sets->data)); g_free(filename); filename = temp_string; temp_data_sets = temp_data_sets->next; } temp_string = g_strdup_printf("%s}.tsv",filename); g_free(filename); filename = temp_string; amitk_objects_unref(data_sets); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), filename); g_free(filename); /* run the save dialog */ if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy(file_chooser); if (filename != NULL) { /* allright, save the data */ save_profiles(filename, tb_profile); g_free(filename); } return; } static void save_profiles(const gchar * save_filename, tb_profile_t * tb_profile) { FILE * file_pointer; gchar * results; if ((file_pointer = fopen(save_filename, "w")) == NULL) { g_warning(_("couldn't open: %s for writing profiles"), save_filename); return; } results = results_as_string(tb_profile); fprintf(file_pointer, "%s", results); g_free(results); fclose(file_pointer); return; } #ifdef AMIDE_LIBGSL_SUPPORT static gboolean canvas_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { tb_profile_t * tb_profile = data; AmitkCanvasPoint canvas_cpoint; GnomeCanvas * canvas; gdouble x_point; gboolean find_new_initial = FALSE; AmitkLineProfileDataElement * element; gboolean initialized; gdouble peak_x=0.0; gdouble peak_y=0.0; int i,j; result_t * result; canvas = GNOME_CANVAS(widget); gnome_canvas_window_to_world(canvas, event->button.x, event->button.y, &canvas_cpoint.x, &canvas_cpoint.y); gnome_canvas_w2c_d(canvas, canvas_cpoint.x, canvas_cpoint.y, &canvas_cpoint.x, &canvas_cpoint.y); switch (event->type) { case GDK_BUTTON_RELEASE: x_point = ((canvas_cpoint.x-EDGE_SPACING)/tb_profile->scale_x)+tb_profile->min_x; switch (event->button.button) { case 1: if (x_point < tb_profile->x_limit[1]) tb_profile->x_limit[0] = x_point; find_new_initial = TRUE; break; case 3: if (x_point > tb_profile->x_limit[0]) tb_profile->x_limit[1] = x_point; find_new_initial = TRUE; break; case 2: default: tb_profile->initial_x = x_point; break; } /* find new peaks */ if (find_new_initial) { tb_profile->initial_x = -1.0; for (i=0; i < tb_profile->results->len; i++) { result = g_ptr_array_index(tb_profile->results, i); g_return_val_if_fail(result != NULL, FALSE); initialized = FALSE; for (j=0; jline->len; j++) { element = g_ptr_array_index(result->line, j); if ((element->location >= tb_profile->x_limit[0]) && (element->location <= tb_profile->x_limit[1])) { if ((!initialized) || (peak_y < element->value)) { peak_x = element->location; peak_y = element->value; initialized = TRUE; } } } if (initialized) result->peak_location = peak_x; } } /* redisplay */ if (tb_profile->calc_gaussian_fit) display_gaussian_fit(tb_profile); break; default: break; } return FALSE; } static void calc_gaussian_fit_cb(GtkWidget * widget, gpointer data) { tb_profile_t * tb_profile = data; tb_profile->calc_gaussian_fit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if (tb_profile->calc_gaussian_fit) display_gaussian_fit(tb_profile); else recalc_profiles(tb_profile); /* removes old gaussian fit */ return; } static void fix_x_cb(GtkWidget * widget, gpointer data) { tb_profile_t * tb_profile = data; tb_profile->fix_x = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if (tb_profile->calc_gaussian_fit) display_gaussian_fit(tb_profile); return; } static void fix_dc_zero_cb(GtkWidget * widget, gpointer data) { tb_profile_t * tb_profile = data; tb_profile->fix_dc_zero = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if (tb_profile->calc_gaussian_fit) display_gaussian_fit(tb_profile); return; } static double calc_gaussian(double s, double p, double c, double b, double loc) { double diff; diff = loc-c; return b + p * (exp(-0.5*diff*diff/(s*s))); } typedef struct params_t { GPtrArray * line; gboolean fix_x; gdouble x; gboolean fix_dc_zero; gdouble x_limit[2]; } params_t; static int gaussian_f(const gsl_vector * func_p, void * data, gsl_vector * f) { params_t * params = data; double b; double p; double c; double s; gint i; AmitkLineProfileDataElement * element; /* get the parameters */ i = 0; s = gsl_vector_get(func_p, i++); p = gsl_vector_get(func_p, i++); if (params->fix_x) c = params->x; else c = gsl_vector_get(func_p, i++); if (params->fix_dc_zero) b = 0.0; else b = gsl_vector_get(func_p, i++); for (i = 0; i < params->line->len; i++) { element = g_ptr_array_index(params->line, i); if ((element->location > params->x_limit[0]) && (element->location < params->x_limit[1])) gsl_vector_set(f, i, calc_gaussian(s,p,c,b,element->location) - element->value); else gsl_vector_set(f, i, 0.0); } return GSL_SUCCESS; } static int gaussian_df (const gsl_vector * func_p, void *data, gsl_matrix * J) { params_t * params = data; double p; double c; double s; gint i,j; AmitkLineProfileDataElement * element; double diff; double inner; /* get the parameters */ i = 0; s = gsl_vector_get(func_p, i++); p = gsl_vector_get(func_p, i++); if (params->fix_x) c = params->x; else c = gsl_vector_get(func_p, i++); for (i = 0; i < params->line->len; i++) { element = g_ptr_array_index(params->line, i); diff = element->location-c; inner = exp(-0.5*(diff)*(diff)/(s*s)); j = 0; if ((element->location > params->x_limit[0]) && (element->location < params->x_limit[1])) { gsl_matrix_set (J, i, j++, p*inner*diff*diff/(s*s*s)); gsl_matrix_set (J, i, j++, inner); if (!params->fix_x) gsl_matrix_set (J, i, j++, p*inner*diff/(s*s)); if (!params->fix_dc_zero) gsl_matrix_set (J, i, j++, 1); } else { gsl_matrix_set (J, i, j++, 0.0); gsl_matrix_set (J, i, j++, 0.0); if (!params->fix_x) gsl_matrix_set (J, i, j++, 0.0); if (!params->fix_dc_zero) gsl_matrix_set (J, i, j++, 0.0); } } return GSL_SUCCESS; } static int gaussian_fdf (const gsl_vector * func_p, void *params, gsl_vector * f, gsl_matrix * J) { gaussian_f (func_p, params, f); gaussian_df (func_p, params, J); return GSL_SUCCESS; } /* we're fitting the following function b + p * exp(-0.5 * ((x-c)/s)^2) */ static void fit_gaussian(tb_profile_t * tb_profile) { gint i,j; result_t * result; gsl_multifit_fdfsolver * solver; gsl_matrix *covar; gsl_multifit_function_fdf fdf; gsl_vector * init_p; gint iter; gint status; gint num_p; params_t params; gdouble initial_x; num_p = 2; if (!tb_profile->fix_x) num_p++; if (!tb_profile->fix_dc_zero) num_p++; covar = gsl_matrix_alloc (num_p, num_p); g_return_if_fail(covar != NULL); init_p = gsl_vector_alloc(num_p); fdf.f = &gaussian_f; fdf.df = &gaussian_df; fdf.fdf = &gaussian_fdf; fdf.p = num_p; /* fit each profile */ for (i=0; i < tb_profile->results->len; i++) { result = g_ptr_array_index(tb_profile->results, i); g_return_if_fail(result != NULL); /* figure out where we'd like to start along x*/ initial_x = (tb_profile->initial_x >= 0.0) ? tb_profile->initial_x : result->peak_location; /* initialize parameters */ j=0; gsl_vector_set(init_p, j++, 1.0); /* s - sigma argument, proportional to width */ gsl_vector_set(init_p, j++, result->max_y); /* peak val */ if (!tb_profile->fix_x) gsl_vector_set(init_p, j++, initial_x); /* x offset val */ if (!tb_profile->fix_dc_zero) gsl_vector_set(init_p, j++, result->min_y); /* b - DC val */ /* alloc the solver */ g_return_if_fail(result->line->len < num_p); solver = gsl_multifit_fdfsolver_alloc (gsl_multifit_fdfsolver_lmder,result->line->len, num_p); g_return_if_fail(solver != NULL); /* assign the data we're fitting */ params.line = result->line; params.fix_x = tb_profile->fix_x; params.x = initial_x; params.x_limit[0] = tb_profile->x_limit[0]; params.x_limit[1] = tb_profile->x_limit[1]; params.fix_dc_zero = tb_profile->fix_dc_zero; fdf.params = ¶ms; fdf.n = result->line->len; gsl_multifit_fdfsolver_set (solver, &fdf, init_p); /* and iterate */ iter = 0; do { iter++; status = gsl_multifit_fdfsolver_iterate (solver); if (status) break; status = gsl_multifit_test_delta (solver->dx, solver->x, 1e-4, 1e-4); } while ((status == GSL_CONTINUE) && (iter < 100)); #if GSL_MAJOR_VERSION > 1 { gsl_matrix *J = gsl_matrix_alloc (result->line->len, num_p);; gsl_multifit_fdfsolver_jac(solver, J); gsl_multifit_covar (J, 0.0, covar); gsl_matrix_free(J); } #else gsl_multifit_covar (solver->J, 0.0, covar); #endif j=0; result->s_fit = gsl_vector_get(solver->x, j++); result->p_fit = gsl_vector_get(solver->x, j++); if (tb_profile->fix_x) result->c_fit = initial_x; else result->c_fit = gsl_vector_get(solver->x, j++); if (tb_profile->fix_dc_zero) result->b_fit = 0.0; else result->b_fit = gsl_vector_get(solver->x, j++); j=0; result->s_err = sqrt(gsl_matrix_get(covar,j,j)); j++; result->p_err = sqrt(gsl_matrix_get(covar,j,j)); j++; if (tb_profile->fix_x) result->c_err = 0.0; else { result->c_err = sqrt(gsl_matrix_get(covar,j,j)); j++; } if (tb_profile->fix_dc_zero) result->b_err = 0.0; else { result->b_err = sqrt(gsl_matrix_get(covar,j,j)); j++; } result->iterations = iter; result->status = status; /* cleanup */ gsl_multifit_fdfsolver_free(solver); } gsl_matrix_free(covar); gsl_vector_free(init_p); return; } static void display_gaussian_fit(tb_profile_t * tb_profile) { gint i, j; GtkTextBuffer *buffer; GtkTextIter start_iter, end_iter; gchar * results_str; gdouble value; GnomeCanvasPoints * points; div_t x; guint color; result_t * result; double loc; /* perform gaussian fits */ fit_gaussian(tb_profile); /* make the x limit lines */ if (tb_profile->x_limit_item[0] != NULL) gtk_object_destroy(GTK_OBJECT(tb_profile->x_limit_item[0])); if (tb_profile->x_limit_item[1] != NULL) gtk_object_destroy(GTK_OBJECT(tb_profile->x_limit_item[1])); points = gnome_canvas_points_new(2); points->coords[0] = points->coords[2] = tb_profile->scale_x*(tb_profile->x_limit[0]-tb_profile->min_x)+EDGE_SPACING; points->coords[1] = EDGE_SPACING+CANVAS_HEIGHT/4.0; points->coords[3] = 3*CANVAS_HEIGHT/4.0+EDGE_SPACING; tb_profile->x_limit_item[0] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_line_get_type(), "points", points, "fill_color", "white", #ifndef AMIDE_LIBGNOMECANVAS_AA "line_style", GDK_LINE_ON_OFF_DASH, #endif "width_units", 1.0, NULL); gnome_canvas_points_unref(points); points = gnome_canvas_points_new(2); points->coords[0] = points->coords[2] = tb_profile->scale_x*(tb_profile->x_limit[1]-tb_profile->min_x)+EDGE_SPACING; points->coords[1] = EDGE_SPACING+CANVAS_HEIGHT/4.0; points->coords[3] = 3*CANVAS_HEIGHT/4.0+EDGE_SPACING; tb_profile->x_limit_item[1] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_line_get_type(), "points", points, "fill_color", "white", #ifndef AMIDE_LIBGNOMECANVAS_AA "line_style", GDK_LINE_ON_OFF_DASH, #endif "width_units", 1.0, NULL); gnome_canvas_points_unref(points); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tb_profile->text)); /* delete any text in the buffer */ gtk_text_buffer_get_start_iter(buffer, &start_iter); gtk_text_buffer_get_end_iter(buffer, &end_iter); gtk_text_buffer_delete(buffer, &start_iter, &end_iter); /* write out the gaussian equation */ gtk_text_buffer_set_text (buffer, _("fit = b + p * e^(-0.5*(x-c)^2/s^2)"), -1); for (i=0; i < tb_profile->results->len; i++) { result = g_ptr_array_index(tb_profile->results, i); points = gnome_canvas_points_new(CANVAS_WIDTH); for (j=0; jscale_x)+tb_profile->min_x; value = calc_gaussian(result->s_fit, result->p_fit, result->c_fit,result->b_fit, loc); points->coords[2*j+0] = (gdouble) j; points->coords[2*j+1] = CANVAS_HEIGHT-EDGE_SPACING-result->scale_y*(value-result->min_y); } /* figure out the color we'll use */ x = div(i, NUM_COLOR_ROTATIONS); if (tb_profile->results->len < 2) { color = 0xFFFFFFFF; } else { color = color_rotation[x.rem]; } /* make sure it's destroyed */ if (result->fit_item != NULL) gtk_object_destroy(GTK_OBJECT(result->fit_item)); /* and (re)create it */ result->fit_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", color, #ifndef AMIDE_LIBGNOMECANVAS_AA "line_style", GDK_LINE_ON_OFF_DASH, #endif "width_units", 1.0, NULL); gnome_canvas_points_unref(points); results_str = g_strdup_printf(_("\n\ngaussian fit on: %s\n" "iterations used %d, status %s\n" "b = %.5g +/- %.5g %s\n" "p = %.5g +/- %.5g\n" "c = %.5g +/- %.5g mm %s\n" "s = %.5g +/- %.5g\n" "fwhm = %.5g +/- %.5g mm\n" "fwtm = %.5g +/- %.5g mm"), result->name, result->iterations, gsl_strerror (result->status), result->b_fit, result->b_err, tb_profile->fix_dc_zero ? _("(fixed)"): "", result->p_fit, result->p_err, result->c_fit, result->c_err, tb_profile->fix_x ? _("(fixed)") : "", result->s_fit, result->s_err, SIGMA_TO_FWHM*(result->s_fit), SIGMA_TO_FWHM*(result->s_err), SIGMA_TO_FWTM*(result->s_fit), SIGMA_TO_FWTM*(result->s_err)); gtk_text_buffer_insert_at_cursor(buffer, results_str, -1); g_free(results_str); } return; } #endif static void recalc_profiles(tb_profile_t * tb_profile) { profile_update_entries(tb_profile); if (tb_profile->idle_handler_id == 0) tb_profile->idle_handler_id = g_idle_add_full(G_PRIORITY_HIGH_IDLE,update_while_idle, tb_profile, NULL); return; } static gboolean update_while_idle(gpointer data) { tb_profile_t * tb_profile = data; gboolean initialized=FALSE; GList * data_sets; GList * temp_data_sets; GPtrArray * one_line; gint i,j; AmitkLineProfileDataElement * element; GnomeCanvasPoints * points; result_t * result; div_t x; gchar * label; ui_common_place_cursor(UI_CURSOR_WAIT, tb_profile->canvas); data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(tb_profile->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_ANY, TRUE); /* discard the old results... this also erases them from canvas */ tb_profile->results = results_free(tb_profile->results); tb_profile->results = g_ptr_array_new(); /* recalc profiles */ tb_profile->max_x = tb_profile->min_x = 0.0; temp_data_sets = data_sets; while (temp_data_sets != NULL) { amitk_data_set_get_line_profile(AMITK_DATA_SET(temp_data_sets->data), AMITK_STUDY_VIEW_START_TIME(tb_profile->study), AMITK_STUDY_VIEW_DURATION(tb_profile->study), AMITK_LINE_PROFILE_START_POINT(AMITK_STUDY_LINE_PROFILE(tb_profile->study)), AMITK_LINE_PROFILE_END_POINT(AMITK_STUDY_LINE_PROFILE(tb_profile->study)), &one_line); if (one_line->len > 1) { /* need at least two points for a valid line */ result = g_malloc(sizeof(result_t)); g_return_val_if_fail(result != NULL, FALSE); result->name = g_strdup(AMITK_OBJECT_NAME(temp_data_sets->data)); result->line_item = NULL; result->y_label[0] = NULL; result->y_label[1] = NULL; result->legend = NULL; result->line = one_line; result->fit_item = NULL; /* get max/min y values */ /* get max/min values */ element = g_ptr_array_index(one_line, 0); result->max_y = result->min_y = element->value; result->peak_location = element->location; if (!initialized) { tb_profile->min_x = tb_profile->max_x = element->location; initialized = TRUE; } for (j=0; jlen; j++) { element = g_ptr_array_index(one_line, j); if (element->location < tb_profile->min_x) tb_profile->min_x = element->location; if (element->location > tb_profile->max_x) tb_profile->max_x = element->location; if (element->value < result->min_y) result->min_y = element->value; if (element->value > result->max_y) { result->max_y = element->value; result->peak_location = element->location; } } g_ptr_array_add(tb_profile->results, result); } else g_ptr_array_free(one_line, TRUE); temp_data_sets = temp_data_sets->next; } label = g_strdup_printf("%g", tb_profile->min_x); if (tb_profile->x_label[0] != NULL) { gnome_canvas_item_set(tb_profile->x_label[0], "text", label, NULL); } else { tb_profile->x_label[0] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_SOUTH_WEST, "text", label, "x", (gdouble) EDGE_SPACING+5.0, "y", (gdouble) CANVAS_HEIGHT-EDGE_SPACING, "fill_color", "white", "font_desc", amitk_fixed_font_desc, NULL); } g_free(label); label = g_strdup_printf("%g", tb_profile->max_x); if (tb_profile->x_label[1] != NULL) { gnome_canvas_item_set(tb_profile->x_label[1], "text", label, NULL); } else { tb_profile->x_label[1] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_SOUTH_EAST, "text", label, "x", (gdouble) CANVAS_WIDTH-EDGE_SPACING, "y", (gdouble) CANVAS_HEIGHT-EDGE_SPACING, "fill_color", "white", "font_desc", amitk_fixed_font_desc, NULL); } g_free(label); tb_profile->scale_x = (CANVAS_WIDTH-2*EDGE_SPACING)/(tb_profile->max_x-tb_profile->min_x); /* generate new lines */ for (i=0; i < tb_profile->results->len; i++) { result = g_ptr_array_index(tb_profile->results, i); points = gnome_canvas_points_new(result->line->len); result->scale_y = (CANVAS_HEIGHT-2*EDGE_SPACING)/(result->max_y-result->min_y); for (j=0; jline->len; j++) { element = g_ptr_array_index(result->line, j); points->coords[2*j+0] = tb_profile->scale_x*(element->location-tb_profile->min_x)+EDGE_SPACING; points->coords[2*j+1] = CANVAS_HEIGHT-EDGE_SPACING-result->scale_y*(element->value-result->min_y); } x = div(i, NUM_COLOR_ROTATIONS); result->line_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", color_rotation[x.rem], "width_units", 1.0, NULL); gnome_canvas_points_unref(points); label = g_strdup_printf("%g", result->min_y); result->y_label[0] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_SOUTH_WEST, "text", label, "x", (gdouble) EDGE_SPACING, "y", (gdouble) CANVAS_HEIGHT-EDGE_SPACING-TEXT_HEIGHT-(tb_profile->results->len-i-1)*TEXT_HEIGHT, "fill_color_rgba", color_rotation[x.rem], "font_desc", amitk_fixed_font_desc, NULL); g_free(label); label = g_strdup_printf("%g", result->max_y); result->y_label[1] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_NORTH_WEST, "text", label, "x", (gdouble) EDGE_SPACING, "y", (gdouble) EDGE_SPACING+i*TEXT_HEIGHT, "fill_color_rgba", color_rotation[x.rem], "font_desc", amitk_fixed_font_desc, NULL); g_free(label); result->legend = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_NORTH_EAST, "text", result->name, "x", (gdouble) CANVAS_WIDTH-EDGE_SPACING, "y", (gdouble) EDGE_SPACING+i*TEXT_HEIGHT, "fill_color_rgba", color_rotation[x.rem], "font_desc", amitk_fixed_font_desc, NULL); tb_profile->initial_x = -1.0; tb_profile->x_limit[0] = tb_profile->min_x; tb_profile->x_limit[1] = tb_profile->max_x; #ifdef AMIDE_LIBGSL_SUPPORT if (tb_profile->calc_gaussian_fit) display_gaussian_fit(tb_profile); #endif } /* and we're done */ ui_common_remove_wait_cursor(tb_profile->canvas); data_sets = amitk_objects_unref(data_sets); tb_profile->idle_handler_id=0; return FALSE; } static void response_cb (GtkDialog * dialog, gint response_id, gpointer data) { tb_profile_t * tb_profile = data; gint return_val; GtkClipboard * clipboard; gchar * results; switch(response_id) { case AMITK_RESPONSE_SAVE_AS: export_profiles(tb_profile); break; case AMITK_RESPONSE_COPY: results = results_as_string(tb_profile); /* fill in select/button2 clipboard (X11) */ clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); gtk_clipboard_set_text(clipboard, results, -1); /* fill in copy/paste clipboard (Win32 and Gnome) */ clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text(clipboard, results, -1); g_free(results); break; case GTK_RESPONSE_HELP: amide_call_help("profile-dialog"); break; case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } static void destroy_cb(GtkObject * object, gpointer data) { tb_profile_t * tb_profile = data; /* make the line profile invisible */ amitk_line_profile_set_visible(AMITK_STUDY_LINE_PROFILE(tb_profile->study), FALSE); /* free the associated data structure */ tb_profile = profile_free(tb_profile); } /* function called to destroy the dialog */ static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { return FALSE; } static void view_center_changed_cb(AmitkStudy * study, gpointer data) { tb_profile_t * tb_profile=data; recalc_profiles(tb_profile); return; } /* somewhat wasteful... as we update the profiles if any object changes selection, not just data sets... but this greatly simplifies bookkeeping */ static void selections_changed_cb(AmitkObject * object, gpointer data) { tb_profile_t * tb_profile=data; recalc_profiles(tb_profile); return; } static void profile_changed_cb(AmitkLineProfile * line_profile, gpointer data) { tb_profile_t * tb_profile=data; recalc_profiles(tb_profile); return; } static void profile_switch_view_cb(GtkWidget * widget, gpointer data) { tb_profile_t * tb_profile=data; AmitkView view; view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "view")); amitk_line_profile_set_view(AMITK_STUDY_LINE_PROFILE(tb_profile->study), view); return; } static void profile_angle_cb(GtkWidget * widget, gpointer data) { gdouble temp_val; tb_profile_t * tb_profile = data; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); temp_val *= M_PI/180.0; /* convert to radians */ amitk_line_profile_set_angle(AMITK_STUDY_LINE_PROFILE(tb_profile->study), temp_val); profile_update_entries(tb_profile); return; } static void profile_update_entries(tb_profile_t * tb_profile) { amide_real_t angle; g_signal_handlers_block_by_func(G_OBJECT(tb_profile->angle_spin), G_CALLBACK(profile_angle_cb), tb_profile); angle = AMITK_LINE_PROFILE_ANGLE(AMITK_STUDY_LINE_PROFILE(tb_profile->study)); angle *= 180.0/M_PI; gtk_spin_button_set_value(GTK_SPIN_BUTTON(tb_profile->angle_spin),angle); g_signal_handlers_unblock_by_func(G_OBJECT(tb_profile->angle_spin), G_CALLBACK(profile_angle_cb), tb_profile); return; } void tb_profile(AmitkStudy * study, AmitkPreferences * preferences, GtkWindow * parent) { GtkWidget * dialog; gchar * title; GtkWidget * table; gint table_row; tb_profile_t * tb_profile; AmitkView i_view; GtkWidget * radio_button[3]; GtkWidget * hbox; GtkWidget * label; #ifdef AMIDE_LIBGSL_SUPPORT GtkWidget * check_button; GdkColor color; #endif tb_profile = profile_init(); tb_profile->study = g_object_ref(study); tb_profile->preferences = g_object_ref(preferences); /* make the line profile visible */ amitk_line_profile_set_visible(AMITK_STUDY_LINE_PROFILE(tb_profile->study), TRUE); /* start setting up the widget we'll display the info from */ title = g_strdup_printf(_("%s Profile Tool: Study %s"), PACKAGE, AMITK_OBJECT_NAME(tb_profile->study)); dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(parent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_SAVE_AS, AMITK_RESPONSE_SAVE_AS, GTK_STOCK_COPY, AMITK_RESPONSE_COPY, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_free(title); gtk_window_set_resizable(GTK_WINDOW(dialog), TRUE); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_cb), tb_profile); g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(delete_event_cb), tb_profile); g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(destroy_cb), tb_profile); /* setup the callbacks for detecting if the line profile has changed */ g_signal_connect(G_OBJECT(tb_profile->study), "view_center_changed", G_CALLBACK(view_center_changed_cb), tb_profile); g_signal_connect(G_OBJECT(tb_profile->study), "object_child_selection_changed", G_CALLBACK(selections_changed_cb), tb_profile); g_signal_connect(G_OBJECT(AMITK_STUDY_LINE_PROFILE(tb_profile->study)), "line_profile_changed", G_CALLBACK(profile_changed_cb), tb_profile); /* make the widgets for this dialog box */ table = gtk_table_new(5,3,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); gtk_widget_show(table); /* which view do we want the profile on */ label = gtk_label_new(_("Line Profile on:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(table), hbox,1,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); /* the radio buttons */ for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) { if (i_view == 0) radio_button[i_view] = gtk_radio_button_new_with_label(NULL,amitk_view_get_name(i_view)); else radio_button[i_view] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button[0]), amitk_view_get_name(i_view)); gtk_box_pack_start(GTK_BOX(hbox), radio_button[i_view], FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button[i_view]), "view", GINT_TO_POINTER(i_view)); gtk_widget_show(radio_button[i_view]); } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[AMITK_LINE_PROFILE_VIEW(AMITK_STUDY_LINE_PROFILE(tb_profile->study))]), TRUE); for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) g_signal_connect(G_OBJECT(radio_button[i_view]), "clicked", G_CALLBACK(profile_switch_view_cb), tb_profile); table_row++; /* changing the angle */ label = gtk_label_new(_("Angle (degrees):")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); tb_profile->angle_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(tb_profile->angle_spin), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(tb_profile->angle_spin),3); g_signal_connect(G_OBJECT(tb_profile->angle_spin), "value_changed", G_CALLBACK(profile_angle_cb), tb_profile); gtk_table_attach(GTK_TABLE(table),tb_profile->angle_spin,1,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(tb_profile->angle_spin); table_row++; /* the canvas */ #ifdef AMIDE_LIBGNOMECANVAS_AA tb_profile->canvas = gnome_canvas_new_aa(); #else tb_profile->canvas = gnome_canvas_new(); #endif gtk_table_attach(GTK_TABLE(table), tb_profile->canvas, 0, 3, table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); #ifdef AMIDE_LIBGSL_SUPPORT g_signal_connect(G_OBJECT(tb_profile->canvas), "event", G_CALLBACK(canvas_event_cb), tb_profile); #endif gtk_widget_set_size_request(tb_profile->canvas, CANVAS_WIDTH+1, CANVAS_HEIGHT+1); gnome_canvas_set_scroll_region(GNOME_CANVAS(tb_profile->canvas), 0.0, 0.0, CANVAS_WIDTH, CANVAS_HEIGHT); gtk_widget_show(tb_profile->canvas); table_row++; /* draw a black background on the canvas */ gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(tb_profile->canvas)), gnome_canvas_rect_get_type(), "x1",0.0, "y1", 0.0, "x2", (gdouble) CANVAS_WIDTH, "y2", (gdouble) CANVAS_HEIGHT, "fill_color_rgba", 0x000000FF, NULL); /* the fit results */ #ifdef AMIDE_LIBGSL_SUPPORT check_button = gtk_check_button_new_with_label (_("calculate gaussian fit")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), tb_profile->calc_gaussian_fit); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(calc_gaussian_fit_cb), tb_profile); gtk_table_attach(GTK_TABLE(table), check_button,0,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(check_button); table_row++; check_button = gtk_check_button_new_with_label (_("fix x location (c)")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), tb_profile->fix_x); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(fix_x_cb), tb_profile); gtk_table_attach(GTK_TABLE(table), check_button,0,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(check_button); table_row++; check_button = gtk_check_button_new_with_label (_("fix dc value to zero (b)")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), tb_profile->fix_dc_zero); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(fix_dc_zero_cb), tb_profile); gtk_table_attach(GTK_TABLE(table), check_button,0,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(check_button); table_row++; tb_profile->text = gtk_text_view_new (); gtk_table_attach(GTK_TABLE(table), tb_profile->text, 0, 3, table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_modify_font (tb_profile->text, amitk_fixed_font_desc); gtk_text_view_set_editable(GTK_TEXT_VIEW(tb_profile->text), FALSE); gtk_widget_show(tb_profile->text); table_row++; /* set it to black */ gdk_color_parse ("black", &color); gtk_widget_modify_base(tb_profile->text, GTK_STATE_NORMAL, &color); gdk_color_parse ("white", &color); gtk_widget_modify_text (tb_profile->text, GTK_STATE_NORMAL, &color); #endif /* and show all our widgets */ gtk_widget_show(dialog); /* and make sure they have the right stuff in them */ recalc_profiles(tb_profile); return; } amide-1.0.6/amide-current/src/tb_profile.h000066400000000000000000000020411423227705100204210ustar00rootroot00000000000000/* tb_profile.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2003-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* includes always needed with this */ #include "amitk_study.h" /* external functions */ void tb_profile(AmitkStudy * study, AmitkPreferences * preferences, GtkWindow * parent); amide-1.0.6/amide-current/src/tb_roi_analysis.c000066400000000000000000001245501423227705100214620ustar00rootroot00000000000000/* tb_roi_analysis.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include #include "amide.h" #include "amide_gconf.h" #include "amitk_common.h" #include "analysis.h" #include "tb_roi_analysis.h" #include "ui_common.h" #define GCONF_AMIDE_ANALYSIS "ANALYSIS" #define ROI_STATISTICS_WIDTH 950 /* keep in sync with array below */ typedef enum { COLUMN_ROI_NAME, COLUMN_DATA_SET_NAME, COLUMN_FRAME, COLUMN_DURATION, COLUMN_TIME_MIDPT, COLUMN_GATE, COLUMN_GATE_TIME, /* COLUMN_TOTAL, */ COLUMN_MEDIAN, COLUMN_MEAN, COLUMN_VAR, COLUMN_STD_DEV, COLUMN_MIN, COLUMN_MAX, COLUMN_SIZE, COLUMN_FRAC_VOXELS, COLUMN_VOXELS, NUM_ANALYSIS_COLUMNS, } column_t; static gboolean column_use_my_renderer[NUM_ANALYSIS_COLUMNS] = { FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, /* TRUE, */ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, }; static gchar * analysis_titles[] = { N_("ROI"), N_("Data Set"), N_("Frame"), N_("Duration (s)"), N_("Midpt (s)"), N_("Gate"), N_("Gate Time (s)"), /* N_("Total"), */ N_("Median"), N_("Mean"), N_("Var"), N_("Std Dev"), N_("Min"), N_("Max"), N_("Size (mm^3)"), N_("Frac. Voxels"), N_("Voxels") }; typedef struct tb_roi_analysis_t { GtkWidget * dialog; AmitkPreferences * preferences; analysis_roi_t * roi_analyses; guint reference_count; } tb_roi_analysis_t; static void export_data(tb_roi_analysis_t * tb_roi_analysis, gboolean raw_values); static void export_analyses(const gchar * save_filename, analysis_roi_t * roi_analyses, gboolean raw_data); static gchar * analyses_as_string(analysis_roi_t * roi_analyses); static void response_cb (GtkDialog * dialog, gint response_id, gpointer data); static void destroy_cb(GtkObject * object, gpointer data); static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * delete_event, gpointer data); static void add_pages(GtkWidget * notebook, AmitkStudy * study, analysis_roi_t * roi_analyses); static void read_preferences(gboolean * all_data_sets, gboolean * all_rois, analysis_calculation_t * calculation_type, gboolean * accurate, gdouble * subfraction, gdouble * threshold_percentage, gdouble * threshold_value); static tb_roi_analysis_t * tb_roi_analysis_free(tb_roi_analysis_t * tb_roi_analysis); static tb_roi_analysis_t * tb_roi_analysis_init(void); /* function to save the generated roi statistics */ static void export_data(tb_roi_analysis_t * tb_roi_analysis, gboolean raw_data) { analysis_roi_t * temp_analyses = tb_roi_analysis->roi_analyses; GtkWidget * file_chooser; gchar * temp_string; gchar * filename = NULL; /* sanity checks */ g_return_if_fail(tb_roi_analysis->roi_analyses != NULL); file_chooser = gtk_file_chooser_dialog_new ((!raw_data) ? _("Export Statistics") : _("Export ROI Raw Data Values"), GTK_WINDOW(tb_roi_analysis->dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(tb_roi_analysis->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ filename = g_strdup_printf("%s_%s_{%s", AMITK_OBJECT_NAME(tb_roi_analysis->roi_analyses->study), raw_data ? _("roi_raw_data"): _("analysis"), AMITK_OBJECT_NAME(tb_roi_analysis->roi_analyses->roi)); temp_analyses= tb_roi_analysis->roi_analyses->next_roi_analysis; while (temp_analyses != NULL) { temp_string = g_strdup_printf("%s+%s",filename,AMITK_OBJECT_NAME(temp_analyses->roi)); g_free(filename); filename = temp_string; temp_analyses= temp_analyses->next_roi_analysis; } temp_string = g_strdup_printf("%s}.tsv",filename); g_free(filename); filename = temp_string; gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (file_chooser), filename); g_free(filename); if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); export_analyses(filename, tb_roi_analysis->roi_analyses, raw_data); /* allright, save the data */ g_free (filename); } gtk_widget_destroy (file_chooser); return; } static void export_analyses(const gchar * save_filename, analysis_roi_t * roi_analyses, gboolean raw_data) { FILE * file_pointer; time_t current_time; analysis_volume_t * volume_analyses; analysis_frame_t * frame_analyses; analysis_gate_t * gate_analyses; guint frame; guint gate; guint i; amide_real_t voxel_volume; gboolean title_printed; AmitkPoint location; analysis_element_t * element; /* sanity checks */ g_return_if_fail(save_filename != NULL); if ((file_pointer = fopen(save_filename, "w")) == NULL) { g_warning(_("couldn't open: %s for writing roi data"), save_filename); return; } /* intro information */ time(¤t_time); fprintf(file_pointer, _("# %s: ROI Analysis File - generated on %s"), PACKAGE, ctime(¤t_time)); fprintf(file_pointer, "#\n"); fprintf(file_pointer, _("# Study:\t%s\n"), AMITK_OBJECT_NAME(roi_analyses->study)); fprintf(file_pointer, "#\n"); while (roi_analyses != NULL) { fprintf(file_pointer, _("# ROI:\t%s\tType:\t%s"), AMITK_OBJECT_NAME(roi_analyses->roi), amitk_roi_type_get_name(AMITK_ROI_TYPE(roi_analyses->roi))); if (AMITK_ROI_TYPE_ISOCONTOUR(roi_analyses->roi)) { if (AMITK_ROI_ISOCONTOUR_RANGE(roi_analyses->roi) == AMITK_ROI_ISOCONTOUR_RANGE_ABOVE_MIN) fprintf(file_pointer, _("\tIsocontour Above Value:\t%g"), AMITK_ROI_ISOCONTOUR_MIN_VALUE(roi_analyses->roi)); else if (AMITK_ROI_ISOCONTOUR_RANGE(roi_analyses->roi) == AMITK_ROI_ISOCONTOUR_RANGE_BELOW_MAX) fprintf(file_pointer, _("\tIsocontour Below Value:\t%g"), AMITK_ROI_ISOCONTOUR_MAX_VALUE(roi_analyses->roi)); else /* AMITK_ROI_ISOCONTOUR_RANGE_BETWEEN_MIN_MAX */ fprintf(file_pointer, _("\tIsocontour Between Values:\t%g %g"), AMITK_ROI_ISOCONTOUR_MIN_VALUE(roi_analyses->roi), AMITK_ROI_ISOCONTOUR_MAX_VALUE(roi_analyses->roi)); } fprintf(file_pointer,"\n"); if (!raw_data) { switch(roi_analyses->calculation_type) { case ALL_VOXELS: fprintf(file_pointer, _("# Calculation done with all voxels in ROI\n")); break; case HIGHEST_FRACTION_VOXELS: fprintf(file_pointer, _("# Calculation done on %5.3f percentile of voxels in ROI\n"), roi_analyses->subfraction*100); break; case VOXELS_NEAR_MAX: fprintf(file_pointer, _("# Calculation done on voxels >= %5.3f percent of maximum value in ROI\n"), roi_analyses->threshold_percentage); break; case VOXELS_GREATER_THAN_VALUE: fprintf(file_pointer, _("# Calculation done on voxels >= %g in ROI\n"), roi_analyses->threshold_value); break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); } } title_printed = FALSE; volume_analyses = roi_analyses->volume_analyses; while (volume_analyses != NULL) { fprintf(file_pointer, _("# Data Set:\t%s\tScaling Factor:\t%g\n"), AMITK_OBJECT_NAME(volume_analyses->data_set), AMITK_DATA_SET_SCALE_FACTOR(volume_analyses->data_set)); switch(AMITK_DATA_SET_CONVERSION(volume_analyses->data_set)) { case AMITK_CONVERSION_PERCENT_ID_PER_CC: case AMITK_CONVERSION_SUV: fprintf(file_pointer, _("# Output Data Units: %s\n"), amitk_conversion_names[AMITK_DATA_SET_CONVERSION(volume_analyses->data_set)]); fprintf(file_pointer, _("# Injected Dose: %g [%s]\n"), amitk_dose_unit_convert_to(AMITK_DATA_SET_INJECTED_DOSE(volume_analyses->data_set), AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(volume_analyses->data_set)), amitk_dose_unit_names[AMITK_DATA_SET_DISPLAYED_DOSE_UNIT(volume_analyses->data_set)]); fprintf(file_pointer, _("# Cylinder Factor: %g [%s]\n"), amitk_cylinder_unit_convert_to(AMITK_DATA_SET_CYLINDER_FACTOR(volume_analyses->data_set), AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(volume_analyses->data_set)), amitk_cylinder_unit_names[AMITK_DATA_SET_DISPLAYED_CYLINDER_UNIT(volume_analyses->data_set)]); break; default: break; } switch(AMITK_DATA_SET_CONVERSION(volume_analyses->data_set)) { case AMITK_CONVERSION_SUV: fprintf(file_pointer, _("# Subject Weight: %g [%s]\n"), amitk_weight_unit_convert_to(AMITK_DATA_SET_SUBJECT_WEIGHT(volume_analyses->data_set), AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(volume_analyses->data_set)), amitk_weight_unit_names[AMITK_DATA_SET_DISPLAYED_WEIGHT_UNIT(volume_analyses->data_set)]); break; default: break; } if ((!raw_data) && (!title_printed)) { fprintf(file_pointer, "# %s", _(analysis_titles[COLUMN_FRAME])); for (i=COLUMN_FRAME+1;idata_set); frame_analyses = volume_analyses->frame_analyses; frame = 0; while (frame_analyses != NULL) { gate_analyses = frame_analyses->gate_analyses; gate = 0; while (gate_analyses != NULL) { if (!raw_data) { fprintf(file_pointer, " %5d", frame); fprintf(file_pointer, "\t% 12.3f", gate_analyses->duration); fprintf(file_pointer, "\t% 12.3f", gate_analyses->time_midpoint); fprintf(file_pointer, "\t% 12d", gate); fprintf(file_pointer, "\t% 12.3f", gate_analyses->gate_time); /* fprintf(file_pointer, "\t% 12g", gate_analyses->total); */ fprintf(file_pointer, "\t% 12g", gate_analyses->median); fprintf(file_pointer, "\t% 12g", gate_analyses->mean); fprintf(file_pointer, "\t% 12g", gate_analyses->var); fprintf(file_pointer, "\t% 12g", sqrt(gate_analyses->var)); fprintf(file_pointer, "\t% 12g", gate_analyses->min); fprintf(file_pointer, "\t% 12g", gate_analyses->max); fprintf(file_pointer, "\t% 12g", gate_analyses->fractional_voxels*voxel_volume); fprintf(file_pointer, "\t% 12.2f", gate_analyses->fractional_voxels); fprintf(file_pointer, "\t% 12d", gate_analyses->voxels); fprintf(file_pointer, "\n"); } else { /* raw data */ fprintf(file_pointer, "# Frame %d, Gate %d, Gate Time %5.3f\n", frame, gate,gate_analyses->gate_time); fprintf(file_pointer, "# Value\t Weight\t X (mm)\t Y (mm)\t Z (mm)\n"); for (i=0; i < gate_analyses->data_array->len; i++) { element = g_ptr_array_index(gate_analyses->data_array, i); VOXEL_TO_POINT(element->ds_voxel, AMITK_DATA_SET_VOXEL_SIZE(volume_analyses->data_set),location); location = amitk_space_s2b(AMITK_SPACE(volume_analyses->data_set), location); fprintf(file_pointer, "%12g\t%12g\t%12g\t%12g\t%12g\n", element->value, element->weight, location.x, location.y, location.z); } } gate_analyses = gate_analyses->next_gate_analysis; gate++; } frame_analyses = frame_analyses->next_frame_analysis; frame++; } volume_analyses = volume_analyses->next_volume_analysis; } roi_analyses = roi_analyses->next_roi_analysis; if (roi_analyses != NULL) fprintf(file_pointer, "#\n"); } fclose(file_pointer); return; } static gchar * analyses_as_string(analysis_roi_t * roi_analyses) { gchar * roi_stats; time_t current_time; analysis_volume_t * volume_analyses; analysis_frame_t * frame_analyses; analysis_gate_t * gate_analyses; guint frame; guint gate; guint i; amide_real_t voxel_volume; /* intro information */ time(¤t_time); roi_stats = g_strdup_printf(_("# Stats for Study: %s\tGenerated on: %s"), AMITK_OBJECT_NAME(roi_analyses->study), ctime(¤t_time)); /* print the titles */ amitk_append_str(&roi_stats,"# %-10s", _(analysis_titles[COLUMN_ROI_NAME])); amitk_append_str(&roi_stats,"\t%-12s", _(analysis_titles[COLUMN_DATA_SET_NAME])); for (i=COLUMN_DATA_SET_NAME+1;ivolume_analyses; while (volume_analyses != NULL) { voxel_volume = AMITK_DATA_SET_VOXEL_VOLUME(volume_analyses->data_set); frame_analyses = volume_analyses->frame_analyses; frame = 0; while (frame_analyses != NULL) { gate_analyses = frame_analyses->gate_analyses; gate = 0; while (gate_analyses != NULL) { amitk_append_str(&roi_stats, "%-12s\t%-12s", AMITK_OBJECT_NAME(roi_analyses->roi), AMITK_OBJECT_NAME(volume_analyses->data_set)); amitk_append_str(&roi_stats, "\t% 12d", frame); amitk_append_str(&roi_stats, "\t% 12.3f", gate_analyses->duration); amitk_append_str(&roi_stats, "\t% 12.3f", gate_analyses->time_midpoint); amitk_append_str(&roi_stats, "\t% 12d", gate); amitk_append_str(&roi_stats, "\t% 12.3f", gate_analyses->gate_time); /* amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->total); */ amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->median); amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->mean); amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->var); amitk_append_str(&roi_stats, "\t% 12g", sqrt(gate_analyses->var)); amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->min); amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->max); amitk_append_str(&roi_stats, "\t% 12g", gate_analyses->fractional_voxels*voxel_volume); amitk_append_str(&roi_stats, "\t% 12.2f", gate_analyses->fractional_voxels); amitk_append_str(&roi_stats, "\t% 12d\n", gate_analyses->voxels); gate_analyses = gate_analyses->next_gate_analysis; gate++; } frame_analyses = frame_analyses->next_frame_analysis; frame++; } volume_analyses = volume_analyses->next_volume_analysis; } roi_analyses = roi_analyses->next_roi_analysis; } return roi_stats; } static void response_cb (GtkDialog * dialog, gint response_id, gpointer data) { tb_roi_analysis_t * tb_roi_analysis = data; gint return_val; GtkClipboard * clipboard; gchar * roi_stats; switch(response_id) { case AMITK_RESPONSE_SAVE_AS: export_data(tb_roi_analysis, FALSE); break; case AMITK_RESPONSE_SAVE_RAW_AS: export_data(tb_roi_analysis, TRUE); break; case AMITK_RESPONSE_COPY: roi_stats = analyses_as_string(tb_roi_analysis->roi_analyses); /* fill in select/button2 clipboard (X11) */ clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); gtk_clipboard_set_text(clipboard, roi_stats, -1); /* fill in copy/paste clipboard (Win32 and Gnome) */ clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text(clipboard, roi_stats, -1); g_free(roi_stats); break; case GTK_RESPONSE_HELP: amide_call_help("roi-terms"); break; case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } /* function called to destroy the roi analysis dialog */ static void destroy_cb(GtkObject * object, gpointer data) { tb_roi_analysis_t * tb_roi_analysis = data; tb_roi_analysis = tb_roi_analysis_free(tb_roi_analysis); return; } static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { return FALSE; } /* create one page of our notebook */ static void add_pages(GtkWidget * notebook, AmitkStudy * study, analysis_roi_t * roi_analyses) { GtkWidget * table; GtkWidget * label; GtkWidget * entry; GtkWidget * list=NULL; GtkWidget * scrolled=NULL; GtkWidget * hbox; analysis_frame_t * frame_analyses; analysis_gate_t * gate_analyses; guint frame; guint gate; guint table_row=0; amide_real_t voxel_volume; GtkListStore * store=NULL; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkTreeIter iter; column_t i_column; gint width; analysis_volume_t * volume_analyses; analysis_roi_t * temp_roi_analyses; gboolean dynamic_data; gboolean gated_data; gboolean static_tree_created=FALSE; gboolean display; /* check if we have dynamic/gated data */ temp_roi_analyses = roi_analyses; dynamic_data = FALSE; gated_data=FALSE; while (temp_roi_analyses != NULL) { volume_analyses = temp_roi_analyses->volume_analyses; while (volume_analyses != NULL) { if (AMITK_DATA_SET_NUM_FRAMES(volume_analyses->data_set) > 1) dynamic_data = TRUE; if (AMITK_DATA_SET_NUM_GATES(volume_analyses->data_set) > 1) gated_data = TRUE; volume_analyses = volume_analyses->next_volume_analysis; } temp_roi_analyses = temp_roi_analyses->next_roi_analysis; } while (roi_analyses != NULL) { if ((dynamic_data) || (gated_data) || (!static_tree_created)) { if ((dynamic_data) || (gated_data)) label = gtk_label_new(AMITK_OBJECT_NAME(roi_analyses->roi)); else label = gtk_label_new(_("ROI Statistics")); table = gtk_table_new(5,3,FALSE); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(hbox), 0,5, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); table_row++; gtk_widget_show(hbox); if ((dynamic_data) || (gated_data)){ /* tell us the type */ label = gtk_label_new(_("type:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), amitk_roi_type_get_name(AMITK_ROI_TYPE(roi_analyses->roi))); gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE); gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5); } /* try to get a reasonable estimate for how wide the statistics box should be */ width = 0.9*gdk_screen_width(); if (width > ROI_STATISTICS_WIDTH) width = ROI_STATISTICS_WIDTH; /* the scroll widget which the list will go into */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,width,250); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* and throw the scrolled widget into the packing table */ gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(scrolled), 0,5,table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* and the list itself */ store = gtk_list_store_new(NUM_ANALYSIS_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, AMITK_TYPE_TIME, AMITK_TYPE_TIME, G_TYPE_INT, AMITK_TYPE_TIME, /* AMITK_TYPE_DATA, */ AMITK_TYPE_DATA, AMITK_TYPE_DATA, AMITK_TYPE_DATA, AMITK_TYPE_DATA, AMITK_TYPE_DATA, AMITK_TYPE_DATA, AMITK_TYPE_REAL, AMITK_TYPE_REAL, G_TYPE_INT); list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); for (i_column=0; i_columnvolume_analyses; while (volume_analyses != NULL) { frame_analyses = volume_analyses->frame_analyses; voxel_volume = AMITK_DATA_SET_VOXEL_VOLUME(volume_analyses->data_set); /* iterate over the frames */ /* note, use to also include: COLUMN_STD_ERR, sqrt(frame_analyses->var/frame_analyses->voxels) but I'm pretty sure this is not strictly corrected for a weighted standard error... And most people won't (and shouldn't) be using this value anyway, as it's not the experimental standard error. */ frame = 0; while (frame_analyses != NULL) { gate_analyses = frame_analyses->gate_analyses; gate = 0; while (gate_analyses != NULL) { gtk_list_store_append (store, &iter); /* Acquire an iterator */ gtk_list_store_set (store, &iter, COLUMN_ROI_NAME, AMITK_OBJECT_NAME(roi_analyses->roi), COLUMN_DATA_SET_NAME,AMITK_OBJECT_NAME(volume_analyses->data_set), COLUMN_FRAME, frame, COLUMN_DURATION, gate_analyses->duration, COLUMN_TIME_MIDPT, gate_analyses->time_midpoint, COLUMN_GATE, gate, COLUMN_GATE_TIME, gate_analyses->gate_time, /* COLUMN_TOTAL, gate_analyses->total, */ COLUMN_MEDIAN, gate_analyses->median, COLUMN_MEAN, gate_analyses->mean, COLUMN_VAR, gate_analyses->var, COLUMN_STD_DEV, sqrt(gate_analyses->var), COLUMN_MIN,gate_analyses->min, COLUMN_MAX,gate_analyses->max, COLUMN_SIZE,gate_analyses->fractional_voxels*voxel_volume, COLUMN_FRAC_VOXELS,gate_analyses->fractional_voxels, COLUMN_VOXELS, gate_analyses->voxels, -1); gate_analyses = gate_analyses->next_gate_analysis; gate++; } frame++; frame_analyses = frame_analyses->next_frame_analysis; } volume_analyses = volume_analyses->next_volume_analysis; } /* if we made the list on this iteration, place the widget*/ if ((dynamic_data) || (gated_data) || (!static_tree_created)) { selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); gtk_container_add(GTK_CONTAINER(scrolled),list); /* and put it in the scrolled widget */ static_tree_created = TRUE; } roi_analyses = roi_analyses->next_roi_analysis; } return; } static void read_preferences(gboolean * all_data_sets, gboolean * all_rois, analysis_calculation_t * calculation_type, gboolean * accurate, gdouble * subfraction, gdouble * threshold_percentage, gdouble * threshold_value) { *all_data_sets = amide_gconf_get_bool(GCONF_AMIDE_ANALYSIS,"CalculateAllDataSets"); *all_rois = amide_gconf_get_bool(GCONF_AMIDE_ANALYSIS,"CalculateAllRois"); *calculation_type = amide_gconf_get_int(GCONF_AMIDE_ANALYSIS,"CalculationType"); *accurate = amide_gconf_get_bool(GCONF_AMIDE_ANALYSIS,"Accurate"); *subfraction = amide_gconf_get_float(GCONF_AMIDE_ANALYSIS,"SubFraction"); *threshold_percentage = amide_gconf_get_float(GCONF_AMIDE_ANALYSIS,"ThresholdPercentage"); *threshold_value = amide_gconf_get_float(GCONF_AMIDE_ANALYSIS,"ThresholdValue"); return; } static tb_roi_analysis_t * tb_roi_analysis_free(tb_roi_analysis_t * tb_roi_analysis) { /* sanity checks */ g_return_val_if_fail(tb_roi_analysis != NULL, NULL); g_return_val_if_fail(tb_roi_analysis->reference_count > 0, NULL); /* remove a reference count */ tb_roi_analysis->reference_count--; /* things to do if we've removed all reference's */ if (tb_roi_analysis->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing tb_roi_analysis\n"); #endif if (tb_roi_analysis->preferences != NULL) { g_object_unref(tb_roi_analysis->preferences); tb_roi_analysis->preferences = NULL; } if (tb_roi_analysis->roi_analyses != NULL) { tb_roi_analysis->roi_analyses = analysis_roi_unref(tb_roi_analysis->roi_analyses); } g_free(tb_roi_analysis); tb_roi_analysis = NULL; } return tb_roi_analysis; } static tb_roi_analysis_t * tb_roi_analysis_init(void) { tb_roi_analysis_t * tb_roi_analysis; /* alloc space for the data structure for passing ui info */ if ((tb_roi_analysis = g_try_new(tb_roi_analysis_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for tb_roi_analysis_t")); return NULL; } tb_roi_analysis->reference_count = 1; tb_roi_analysis->dialog = NULL; tb_roi_analysis->preferences = NULL; tb_roi_analysis->roi_analyses = NULL; return tb_roi_analysis; } void tb_roi_analysis(AmitkStudy * study, AmitkPreferences * preferences, GtkWindow * parent) { tb_roi_analysis_t * tb_roi_analysis; GtkWidget * notebook; gchar * title; GList * rois; GList * data_sets; gboolean all_data_sets; gboolean all_rois; analysis_calculation_t calculation_type; gboolean accurate; gdouble subfraction; gdouble threshold_percentage; gdouble threshold_value; read_preferences(&all_data_sets, &all_rois, &calculation_type, &accurate, &subfraction, &threshold_percentage, &threshold_value); tb_roi_analysis = tb_roi_analysis_init(); tb_roi_analysis->preferences = g_object_ref(preferences); /* figure out which data sets we're dealing with */ if (all_data_sets) data_sets = amitk_object_get_children_of_type(AMITK_OBJECT(study), AMITK_OBJECT_TYPE_DATA_SET, TRUE); else data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_ANY, TRUE); if (data_sets == NULL) { g_warning(_("No Data Sets selected for calculating analyses")); return; } /* get the list of roi's we're going to be calculating over */ if (all_rois) rois = amitk_object_get_children_of_type(AMITK_OBJECT(study), AMITK_OBJECT_TYPE_ROI, TRUE); else rois = amitk_object_get_selected_children_of_type(AMITK_OBJECT(study), AMITK_OBJECT_TYPE_ROI, AMITK_SELECTION_ANY, TRUE); if (rois == NULL) { g_warning(_("No ROI's selected for calculating analyses")); amitk_objects_unref(data_sets); return; } /* calculate all our data */ tb_roi_analysis->roi_analyses = analysis_roi_init(study, rois, data_sets, calculation_type, accurate, subfraction, threshold_percentage, threshold_value); rois = amitk_objects_unref(rois); data_sets = amitk_objects_unref(data_sets); g_return_if_fail(tb_roi_analysis->roi_analyses != NULL); /* start setting up the widget we'll display the info from */ title = g_strdup_printf(_("%s Roi Analysis: Study %s"), PACKAGE, AMITK_OBJECT_NAME(study)); tb_roi_analysis->dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(parent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_SAVE_AS, AMITK_RESPONSE_SAVE_AS, GTK_STOCK_COPY, AMITK_RESPONSE_COPY, "Save Raw Values", AMITK_RESPONSE_SAVE_RAW_AS, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_free(title); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(tb_roi_analysis->dialog), "response", G_CALLBACK(response_cb), tb_roi_analysis); g_signal_connect(G_OBJECT(tb_roi_analysis->dialog), "delete_event", G_CALLBACK(delete_event_cb), tb_roi_analysis); g_signal_connect(G_OBJECT(tb_roi_analysis->dialog), "destroy", G_CALLBACK(destroy_cb), tb_roi_analysis); gtk_window_set_resizable(GTK_WINDOW(tb_roi_analysis->dialog), TRUE); /* make the widgets for this dialog box */ notebook = gtk_notebook_new(); gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE); gtk_container_set_border_width(GTK_CONTAINER(tb_roi_analysis->dialog), 10); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(tb_roi_analysis->dialog)->vbox), notebook); /* add the data pages */ add_pages(notebook, study, tb_roi_analysis->roi_analyses); /* and show all our widgets */ gtk_widget_show_all(tb_roi_analysis->dialog); return; } static void radio_buttons_cb(GtkWidget * widget, gpointer data); static void subfraction_precentage_cb(GtkWidget * widget, gpointer data); static void threshold_percentage_cb(GtkWidget * widget, gpointer data); static void threshold_value_cb(GtkWidget * widget, gpointer data); static void radio_buttons_cb(GtkWidget * widget, gpointer data) { gboolean all_data_sets; gboolean all_rois; all_data_sets = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "all_data_sets")); all_rois = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "all_rois")); amide_gconf_set_bool(GCONF_AMIDE_ANALYSIS,"CalculateAllDataSets",all_data_sets); amide_gconf_set_bool(GCONF_AMIDE_ANALYSIS,"CalculateAllRois",all_rois); return; } static void calculation_type_cb(GtkWidget * widget, gpointer data) { analysis_calculation_t calculation_type; GtkWidget * spin_buttons[3]; calculation_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "calculation_type")); spin_buttons[0] = g_object_get_data(G_OBJECT(widget), "spin_button_0"); spin_buttons[1] = g_object_get_data(G_OBJECT(widget), "spin_button_1"); spin_buttons[2] = g_object_get_data(G_OBJECT(widget), "spin_button_2"); gtk_widget_set_sensitive(spin_buttons[0], calculation_type == HIGHEST_FRACTION_VOXELS); gtk_widget_set_sensitive(spin_buttons[1], calculation_type == VOXELS_NEAR_MAX); gtk_widget_set_sensitive(spin_buttons[2], calculation_type == VOXELS_GREATER_THAN_VALUE); amide_gconf_set_int(GCONF_AMIDE_ANALYSIS,"CalculationType", calculation_type); } static void accurate_cb(GtkWidget * widget, gpointer data) { amide_gconf_set_bool(GCONF_AMIDE_ANALYSIS,"Accurate", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void subfraction_precentage_cb(GtkWidget * widget, gpointer data) { gdouble subfraction; subfraction = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget))/100.0; amide_gconf_set_float(GCONF_AMIDE_ANALYSIS,"SubFraction", subfraction); return; } static void threshold_percentage_cb(GtkWidget * widget, gpointer data) { gdouble threshold_percentage; threshold_percentage = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); amide_gconf_set_float(GCONF_AMIDE_ANALYSIS,"ThresholdPercentage", threshold_percentage); return; } static void threshold_value_cb(GtkWidget * widget, gpointer data) { gdouble threshold_value; threshold_value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); amide_gconf_set_float(GCONF_AMIDE_ANALYSIS,"ThresholdValue", threshold_value); return; } /* function to setup a dialog to allow us to choice options for rendering */ GtkWidget * tb_roi_analysis_init_dialog(GtkWindow * parent) { GtkWidget * tb_roi_init_dialog; gchar * temp_string; GtkWidget * table; GtkWidget * label; guint table_row; GtkWidget * radio_button[4]; GtkWidget * hseparator; GtkObject * adjustment; GtkWidget * spin_buttons[3]; GtkWidget * check_button; analysis_calculation_t i_calculation_type; gboolean all_data_sets; gboolean all_rois; analysis_calculation_t calculation_type; gboolean accurate; gdouble subfraction; gdouble threshold_percentage; gdouble threshold_value; read_preferences(&all_data_sets, &all_rois, &calculation_type, &accurate, &subfraction, &threshold_percentage, &threshold_value); temp_string = g_strdup_printf(_("%s: ROI Analysis Initialization Dialog"), PACKAGE); tb_roi_init_dialog = gtk_dialog_new_with_buttons (temp_string, parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_EXECUTE, AMITK_RESPONSE_EXECUTE, NULL); gtk_window_set_title(GTK_WINDOW(tb_roi_init_dialog), temp_string); g_free(temp_string); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(tb_roi_init_dialog), "response", G_CALLBACK(ui_common_init_dialog_response_cb), NULL); gtk_container_set_border_width(GTK_CONTAINER(tb_roi_init_dialog), 10); /* start making the widgets for this dialog box */ table = gtk_table_new(5,3,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(tb_roi_init_dialog)->vbox), table); label = gtk_label_new(_("Calculate:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("All ROIS:")); gtk_table_attach(GTK_TABLE(table), label, 1,2, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); label = gtk_label_new(_("Selected ROIS:")); gtk_table_attach(GTK_TABLE(table), label, 2,3, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("On All Data Sets:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); radio_button[0] = gtk_radio_button_new(NULL); gtk_table_attach(GTK_TABLE(table), radio_button[0], 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[0]), "all_data_sets", GINT_TO_POINTER(TRUE)); g_object_set_data(G_OBJECT(radio_button[0]), "all_rois", GINT_TO_POINTER(TRUE)); radio_button[1] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio_button[0])); gtk_table_attach(GTK_TABLE(table), radio_button[1], 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[1]), "all_data_sets", GINT_TO_POINTER(TRUE)); g_object_set_data(G_OBJECT(radio_button[1]), "all_rois", GINT_TO_POINTER(FALSE)); table_row++; label = gtk_label_new(_("On Selected Data Sets:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); radio_button[2] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio_button[0])); gtk_table_attach(GTK_TABLE(table), radio_button[2], 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[2]), "all_data_sets", GINT_TO_POINTER(FALSE)); g_object_set_data(G_OBJECT(radio_button[2]), "all_rois", GINT_TO_POINTER(TRUE)); radio_button[3] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio_button[0])); gtk_table_attach(GTK_TABLE(table), radio_button[3], 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[3]), "all_data_sets", GINT_TO_POINTER(FALSE)); g_object_set_data(G_OBJECT(radio_button[3]), "all_rois", GINT_TO_POINTER(FALSE)); table_row++; if (all_data_sets && all_rois) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[0]), TRUE); else if (all_data_sets && !all_rois) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[1]), TRUE); else if (!all_data_sets && all_rois) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[2]), TRUE); else /* !all_data_sets && !all_rois */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[3]), TRUE); g_signal_connect(G_OBJECT(radio_button[0]), "clicked", G_CALLBACK(radio_buttons_cb), NULL); g_signal_connect(G_OBJECT(radio_button[1]), "clicked", G_CALLBACK(radio_buttons_cb), NULL); g_signal_connect(G_OBJECT(radio_button[2]), "clicked", G_CALLBACK(radio_buttons_cb), NULL); g_signal_connect(G_OBJECT(radio_button[3]), "clicked", G_CALLBACK(radio_buttons_cb), NULL); /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0,3,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* do we want to calculate over a subfraction */ label = gtk_label_new(_("Calculate over all voxels (normal):")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); radio_button[0] = gtk_radio_button_new(NULL); gtk_table_attach(GTK_TABLE(table), radio_button[0], 1,2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[0]), "calculation_type", GINT_TO_POINTER(ALL_VOXELS)); table_row++; /* do we want to calculate over a subfraction */ label = gtk_label_new(_("Calculate over % highest voxels:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); radio_button[1] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio_button[0])); gtk_table_attach(GTK_TABLE(table), radio_button[1], 1,2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[1]), "calculation_type", GINT_TO_POINTER(HIGHEST_FRACTION_VOXELS)); adjustment = gtk_adjustment_new(100.0*subfraction, 0.0, 100.0,1.0, 1.0, 0.0); spin_buttons[0] = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), 1.0, 0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_buttons[0]),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_buttons[0]), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_buttons[0]), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_buttons[0]), GTK_UPDATE_ALWAYS); g_signal_connect(G_OBJECT(spin_buttons[0]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(spin_buttons[0]), "value_changed", G_CALLBACK(subfraction_precentage_cb), NULL); gtk_table_attach(GTK_TABLE(table), spin_buttons[0], 2,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_set_sensitive(spin_buttons[0], calculation_type == HIGHEST_FRACTION_VOXELS); table_row++; /* do we want to calculate over a percentage of max */ label = gtk_label_new(_("Calculate for voxels >= % of Max:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); radio_button[2] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio_button[0])); gtk_table_attach(GTK_TABLE(table), radio_button[2], 1,2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[2]), "calculation_type", GINT_TO_POINTER(VOXELS_NEAR_MAX)); adjustment = gtk_adjustment_new(threshold_percentage, 0.0, 100.0,1.0, 1.0, 0.0); spin_buttons[1] = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), 1.0, 0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_buttons[1]),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_buttons[1]), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_buttons[1]), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_buttons[1]), GTK_UPDATE_ALWAYS); g_signal_connect(G_OBJECT(spin_buttons[1]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(spin_buttons[1]), "value_changed", G_CALLBACK(threshold_percentage_cb), NULL); gtk_table_attach(GTK_TABLE(table), spin_buttons[1], 2,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_set_sensitive(spin_buttons[1], calculation_type == VOXELS_NEAR_MAX); table_row++; /* do we want to calculate over a percentage of max */ label = gtk_label_new(_("Calculate for voxels >= Value:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); radio_button[3] = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio_button[0])); gtk_table_attach(GTK_TABLE(table), radio_button[3], 1,2,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[3]), "calculation_type", GINT_TO_POINTER(VOXELS_GREATER_THAN_VALUE)); spin_buttons[2] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_buttons[2]), threshold_value); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_buttons[2]),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(spin_buttons[2]), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_buttons[2]), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_buttons[2]), GTK_UPDATE_ALWAYS); g_signal_connect(G_OBJECT(spin_buttons[2]), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(spin_buttons[2]), "value_changed", G_CALLBACK(threshold_value_cb), NULL); gtk_table_attach(GTK_TABLE(table), spin_buttons[2], 2,3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_set_sensitive(spin_buttons[2], calculation_type == VOXELS_GREATER_THAN_VALUE); table_row++; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[calculation_type]), TRUE); for (i_calculation_type=0; i_calculation_type < NUM_CALCULATION_TYPES; i_calculation_type++) { g_object_set_data(G_OBJECT(radio_button[i_calculation_type]), "spin_button_0", spin_buttons[0]); g_object_set_data(G_OBJECT(radio_button[i_calculation_type]), "spin_button_1", spin_buttons[1]); g_object_set_data(G_OBJECT(radio_button[i_calculation_type]), "spin_button_2", spin_buttons[2]); g_signal_connect(G_OBJECT(radio_button[i_calculation_type]), "clicked", G_CALLBACK(calculation_type_cb), NULL); } /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0,3,table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* do we want more accurate quantitation */ check_button = gtk_check_button_new_with_label(_("More Accurate Quantitation (Slow)")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), accurate); gtk_table_attach(GTK_TABLE(table), check_button, 0,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(accurate_cb), tb_roi_init_dialog); table_row++; /* and show all our widgets */ gtk_widget_show_all(tb_roi_init_dialog); return tb_roi_init_dialog; } amide-1.0.6/amide-current/src/tb_roi_analysis.h000066400000000000000000000023531423227705100214630ustar00rootroot00000000000000/* tb_roi_analysis_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __TB_ROI_ANALYSIS_DIALOG_H__ #define __TB_ROI_ANALYSIS_DIALOG_H__ /* header files always needed with this one */ #include "amitk_study.h" /* external functions */ void tb_roi_analysis(AmitkStudy * study, AmitkPreferences * preferences, GtkWindow * parent); GtkWidget * tb_roi_analysis_init_dialog(GtkWindow * parent); #endif /* __TB_ROI_ANALYSIS_DIALOG_H__ */ amide-1.0.6/amide-current/src/ui_common.c000066400000000000000000001025161423227705100202640ustar00rootroot00000000000000/* ui_common.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amide.h" #include "amide_gnome.h" #include "ui_common.h" #include "amitk_space.h" #include "amitk_color_table.h" #include "amitk_preferences.h" #include "amitk_threshold.h" #include "amitk_tree_view.h" #ifdef AMIDE_LIBGSL_SUPPORT #include #endif #ifdef AMIDE_LIBVOLPACK_SUPPORT #include #endif #ifdef AMIDE_LIBMDC_SUPPORT #include #endif #ifdef AMIDE_FFMPEG_SUPPORT #include #endif #ifdef AMIDE_LIBFAME_SUPPORT #include #endif #ifdef AMIDE_LIBDCMDATA_SUPPORT #include #endif #define AXIS_WIDTH 120 #define AXIS_HEADER 20 #define AXIS_MARGIN 10 #define ORTHOGONAL_AXIS_HEIGHT 100 #define LINEAR_AXIS_HEIGHT 140 #define AXIS_TEXT_MARGIN 10 #define AXIS_ARROW_LENGTH 8 #define AXIS_ARROW_EDGE 7 #define AXIS_ARROW_WIDTH 6 static void manual_cb(GtkAction *action, gpointer * caller); static void about_cb(GtkAction *action, gpointer * caller); /* our help menu... */ GtkActionEntry ui_common_help_menu_items[UI_COMMON_HELP_MENU_NUM] = { /* Help menu */ {"HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Open the AMIDE manual"), G_CALLBACK (manual_cb) }, {"HelpAbout", GTK_STOCK_ABOUT, NULL, NULL, N_("About AMIDE"), G_CALLBACK (about_cb) }, }; /* an array to hold the preloaded cursors */ GdkCursor * ui_common_cursor[NUM_CURSORS]; /* internal variables */ static gboolean ui_common_cursors_initialized = FALSE; static gchar * last_path_used=NULL; static ui_common_cursor_t current_cursor; #ifndef AMIDE_LIBGNOMECANVAS_AA static gchar * line_style_names[] = { N_("Solid"), N_("On/Off"), N_("Double Dash") }; #endif static void manual_cb(GtkAction *action, gpointer * caller) { amide_call_help(NULL); } /* the about dialog */ static void about_cb(GtkAction *action, gpointer * caller) { const gchar *authors[] = { "Andreas Loening ", NULL }; const gchar *translators = { "Spanish Manual Translation: Pablo Sau \n" "Chinese (Simplified) Interface Translation: wormwang@holdfastgroup.com\n" "Chinese (Traditional) Interface Translation: William Chao " }; gchar * comments; comments = g_strjoin("", _("AMIDE's a Medical Image Data Examiner\n"), "\n", _("Email bug reports to: "), PACKAGE_BUGREPORT,"\n", "\n", #if (AMIDE_LIBECAT_SUPPORT || AMIDE_LIBGSL_SUPPORT || AMIDE_LIBMDC_SUPPORT || AMIDE_LIBDCMDATA_SUPPORT || AMIDE_LIBVOLPACK_SUPPORT || AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) _("Compiled with support for the following libraries:\n"), #endif #ifdef AMIDE_LIBECAT_SUPPORT _("libecat: CTI File library by Merence Sibomona\n"), #endif #ifdef AMIDE_LIBGSL_SUPPORT _("libgsl: GNU Scientific Library by the GSL Team (version "),GSL_VERSION,")\n", #endif #ifdef AMIDE_LIBMDC_SUPPORT _("libmdc: Medical Imaging File library by Erik Nolf (version "),MDC_VERSION,")\n", #endif #ifdef AMIDE_LIBDCMDATA_SUPPORT _("libdcmdata: OFFIS DICOM Toolkit DCMTK (C) OFFIS e.V. (version "),dcmtk_version,")\n", #endif #ifdef AMIDE_LIBVOLPACK_SUPPORT _("libvolpack: Volume Rendering library by Philippe Lacroute (version "),VP_VERSION,")\n", #endif #ifdef AMIDE_FFMPEG_SUPPORT _("libavcodec: media encoding library by the FFMPEG Team (version "),AV_STRINGIFY(LIBAVCODEC_VERSION), ")\n", #endif #ifdef AMIDE_LIBFAME_SUPPORT _("libfame: Fast Assembly Mpeg Encoding library by the FAME Team (version "), LIBFAME_VERSION, ")\n", #endif NULL); gtk_show_about_dialog(NULL, "name", PACKAGE, "version", VERSION, "copyright", "Copyright (c) 2000-2017 Andreas Loening", "license", "GNU General Public License, Version 2", "authors", authors, "comments", comments, /* "documenters", documenters, */ /* "artists", artists, */ /* "logo", uses default window icon we've already set*/ "translator-credits", translators, /* "translator-credits, _("translator-credits"), */ /* this would mark the string for translation by the translator*/ "website", "http://amide.sourceforge.net", NULL); g_free(comments); return; } /* returns TRUE for OK */ gboolean ui_common_check_filename(const gchar * filename) { if ((strcmp(filename, ".") == 0) || (strcmp(filename, "..") == 0) || (strcmp(filename, "") == 0) || (strcmp(filename, "\\") == 0) || (strcmp(filename, "/") == 0)) { return FALSE; } else return TRUE; } void ui_common_set_last_path_used(const gchar * path) { if (last_path_used != NULL) g_free(last_path_used); last_path_used = g_strdup(path); return; } /* Returns a suggested path to save a file in. Returned path needs to be free'd */ gchar * ui_common_suggest_path(void) { gchar * dir_string; if (last_path_used != NULL) dir_string = g_path_get_dirname(last_path_used); else dir_string = g_strdup(".");; return dir_string; } /* function which brings up an about box */ void ui_common_about_cb(GtkWidget * button, gpointer data) { about_cb(NULL, NULL); } void ui_common_draw_view_axis(GnomeCanvas * canvas, gint row, gint column, AmitkView view, AmitkLayout layout, gint axis_width, gint axis_height) { const gchar * x_axis_label; gdouble x_axis_label_x_location; gdouble x_axis_label_y_location; GtkAnchorType x_axis_label_anchor; GnomeCanvasPoints * x_axis_line_points; const gchar * y_axis_label; gdouble y_axis_label_x_location; gdouble y_axis_label_y_location; GtkAnchorType y_axis_label_anchor; GnomeCanvasPoints * y_axis_line_points; x_axis_line_points = gnome_canvas_points_new(2); x_axis_line_points->coords[0] = column*axis_width + AXIS_MARGIN; /* x1 */ y_axis_line_points = gnome_canvas_points_new(2); y_axis_line_points->coords[0] = column*axis_width + AXIS_MARGIN; /* x1 */ switch(view) { case AMITK_VIEW_CORONAL: /* the x axis */ x_axis_line_points->coords[1] = row*axis_height + AXIS_HEADER; /* y1 */ x_axis_line_points->coords[2] = column*axis_width + axis_width-AXIS_MARGIN; /* x2 */ x_axis_line_points->coords[3] = row*axis_height + AXIS_HEADER; /* y2 */ /* the x label */ x_axis_label = amitk_axis_get_name(AMITK_AXIS_X); x_axis_label_x_location = column*axis_width + axis_width-AXIS_MARGIN-AXIS_TEXT_MARGIN; x_axis_label_y_location = row*axis_height + AXIS_HEADER+AXIS_TEXT_MARGIN; x_axis_label_anchor = GTK_ANCHOR_NORTH_EAST; /* the z axis */ y_axis_line_points->coords[1] = row*axis_height + AXIS_HEADER; /* y1 */ y_axis_line_points->coords[2] = column*axis_width + AXIS_MARGIN; /* x2 */ y_axis_line_points->coords[3] = row*axis_height + axis_height-AXIS_MARGIN; /* y2 */ /* the z label */ y_axis_label = amitk_axis_get_name(AMITK_AXIS_Z); y_axis_label_x_location = column*axis_width + AXIS_MARGIN+AXIS_TEXT_MARGIN; y_axis_label_y_location = row*axis_height + axis_height-AXIS_MARGIN-AXIS_TEXT_MARGIN; y_axis_label_anchor = GTK_ANCHOR_NORTH_WEST; break; case AMITK_VIEW_SAGITTAL: /* the y axis */ x_axis_line_points->coords[3] = row*axis_height + AXIS_HEADER; /* y2 */ if (layout == AMITK_LAYOUT_ORTHOGONAL) { x_axis_line_points->coords[1] = row*axis_height + axis_height-AXIS_MARGIN; /* y1 */ x_axis_line_points->coords[2] = column*axis_width + AXIS_MARGIN; /* x2 */ } else { /* AMITK_LAYOUT_LINEAR */ x_axis_line_points->coords[1] = row*axis_height + AXIS_HEADER; /* y1 */ x_axis_line_points->coords[2] = column*axis_width + axis_width-AXIS_MARGIN; /* x2 */ } /* the y label */ x_axis_label = amitk_axis_get_name(AMITK_AXIS_Y); x_axis_label_y_location = row*axis_height + AXIS_HEADER+AXIS_TEXT_MARGIN; if (layout == AMITK_LAYOUT_ORTHOGONAL) { x_axis_label_x_location = column*axis_width + AXIS_MARGIN+AXIS_TEXT_MARGIN; x_axis_label_anchor = GTK_ANCHOR_NORTH_WEST; } else {/* AMITK_LAYOUT_LINEAR */ x_axis_label_x_location = column*axis_width + axis_width-AXIS_MARGIN-AXIS_TEXT_MARGIN; x_axis_label_anchor = GTK_ANCHOR_NORTH_EAST; } /* the z axis */ y_axis_line_points->coords[3] = row*axis_height + axis_height-AXIS_MARGIN; /* y2 */ if (layout == AMITK_LAYOUT_ORTHOGONAL) { y_axis_line_points->coords[1] = row*axis_height + axis_height-AXIS_MARGIN; /* y1 */ y_axis_line_points->coords[2] = column*axis_width + axis_width-AXIS_MARGIN; /* x2 */ } else { /* AMITK_LAYOUT_LINEAR */ y_axis_line_points->coords[1] = row*axis_height + AXIS_HEADER; /* y1 */ y_axis_line_points->coords[2] = column*axis_width + AXIS_MARGIN; /* x2 */ } /* the z label */ y_axis_label = amitk_axis_get_name(AMITK_AXIS_Z); y_axis_label_y_location = row*axis_height + axis_height-AXIS_MARGIN-AXIS_TEXT_MARGIN; if (layout == AMITK_LAYOUT_ORTHOGONAL) { y_axis_label_x_location = column*axis_width + axis_width-AXIS_MARGIN-AXIS_TEXT_MARGIN; y_axis_label_anchor = GTK_ANCHOR_SOUTH_EAST; } else { y_axis_label_x_location = column*axis_width + AXIS_MARGIN+AXIS_TEXT_MARGIN; y_axis_label_anchor = GTK_ANCHOR_NORTH_WEST; } break; case AMITK_VIEW_TRANSVERSE: default: /* the x axis */ x_axis_line_points->coords[1] = row*axis_height + axis_height-AXIS_MARGIN; /* y1 */ x_axis_line_points->coords[2] = column*axis_width + axis_width-AXIS_MARGIN; /* x2 */ x_axis_line_points->coords[3] = row*axis_height + axis_height-AXIS_MARGIN; /* y2 */ /* the x label */ x_axis_label = amitk_axis_get_name(AMITK_AXIS_X); x_axis_label_x_location = column*axis_width + axis_width-AXIS_MARGIN-AXIS_TEXT_MARGIN; x_axis_label_y_location = row*axis_height + axis_height-AXIS_MARGIN-AXIS_TEXT_MARGIN; x_axis_label_anchor = GTK_ANCHOR_SOUTH_EAST; /* the y axis */ y_axis_line_points->coords[1] = row*axis_height + axis_height-AXIS_MARGIN; /* y1 */ y_axis_line_points->coords[2] = column*axis_width + AXIS_MARGIN; /* x2 */ y_axis_line_points->coords[3] = row*axis_height + AXIS_HEADER; /* y2 */ /* the y label */ y_axis_label = amitk_axis_get_name(AMITK_AXIS_Y); y_axis_label_x_location = column*axis_width + AXIS_MARGIN+AXIS_TEXT_MARGIN; y_axis_label_y_location = row*axis_height + AXIS_HEADER+AXIS_TEXT_MARGIN; y_axis_label_anchor = GTK_ANCHOR_NORTH_WEST; break; } /* the view label */ gnome_canvas_item_new(gnome_canvas_root(canvas), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_NORTH, "text", amitk_view_get_name(view), "x", (gdouble) (column+0.5)*axis_width, "y", (gdouble) (row+0.5)*axis_height, "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); /* the x axis */ gnome_canvas_item_new(gnome_canvas_root(canvas), gnome_canvas_line_get_type(), "points", x_axis_line_points, "fill_color", "black", "width_pixels", 3, "last_arrowhead", TRUE, "arrow_shape_a", (gdouble) AXIS_ARROW_LENGTH, "arrow_shape_b", (gdouble) AXIS_ARROW_EDGE, "arrow_shape_c", (gdouble) AXIS_ARROW_WIDTH, NULL); /* the x label */ gnome_canvas_item_new(gnome_canvas_root(canvas), gnome_canvas_text_get_type(), "anchor", x_axis_label_anchor,"text", x_axis_label, "x", x_axis_label_x_location, "y", x_axis_label_y_location, "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); /* the y axis */ gnome_canvas_item_new(gnome_canvas_root(canvas), gnome_canvas_line_get_type(), "points", y_axis_line_points, "fill_color", "black", "width_pixels", 3, "last_arrowhead", TRUE, "arrow_shape_a", (gdouble) AXIS_ARROW_LENGTH, "arrow_shape_b", (gdouble) AXIS_ARROW_EDGE, "arrow_shape_c", (gdouble) AXIS_ARROW_WIDTH, NULL); gnome_canvas_points_unref(x_axis_line_points); gnome_canvas_points_unref(y_axis_line_points); /* the y label */ gnome_canvas_item_new(gnome_canvas_root(canvas),gnome_canvas_text_get_type(), "anchor", y_axis_label_anchor, "text", y_axis_label, "x", y_axis_label_x_location,"y", y_axis_label_y_location, "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); return; } void ui_common_update_sample_roi_item(GnomeCanvasItem * roi_item, gint roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA gdouble transparency #else GdkLineStyle line_style #endif ) { rgba_t outline_color; rgba_t fill_color; outline_color = amitk_color_table_outline_color(AMITK_COLOR_TABLE_NIH, TRUE); fill_color = outline_color; #ifdef AMIDE_LIBGNOMECANVAS_AA fill_color.a *= transparency; #endif gnome_canvas_item_set(roi_item, "width_pixels", roi_width, "fill_color_rgba", amitk_color_table_rgba_to_uint32(fill_color), #ifdef AMIDE_LIBGNOMECANVAS_AA "outline_color_rgba", amitk_color_table_rgba_to_uint32(outline_color), #else "line_style", line_style, #endif NULL); return; } void ui_common_study_preferences_widgets(GtkWidget * packing_table, gint table_row, GtkWidget ** proi_width_spin, GnomeCanvasItem ** proi_item, #ifdef AMIDE_LIBGNOMECANVAS_AA GtkWidget ** proi_transparency_spin, #else GtkWidget ** pline_style_menu, GtkWidget ** pfill_roi_button, #endif GtkWidget ** playout_button1, GtkWidget ** playout_button2, GtkWidget ** ppanel_layout_button1, GtkWidget ** ppanel_layout_button2, GtkWidget ** ppanel_layout_button3, GtkWidget ** pmaintain_size_button, GtkWidget ** ptarget_size_spin) { GtkWidget * label; GtkObject * adjustment; GtkWidget * roi_canvas; GnomeCanvasPoints * roi_line_points; GtkWidget * image; GtkWidget * hseparator; #ifndef AMIDE_LIBGNOMECANVAS_AA GdkLineStyle i_line_style; #endif /* widgets to change the roi's size */ label = gtk_label_new(_("ROI Width (pixels)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); adjustment = gtk_adjustment_new(AMITK_PREFERENCES_MIN_ROI_WIDTH, AMITK_PREFERENCES_MIN_ROI_WIDTH, AMITK_PREFERENCES_MAX_ROI_WIDTH,1.0, 1.0, 0.0); *proi_width_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), 1.0, 0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(*proi_width_spin),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(*proi_width_spin), TRUE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(*proi_width_spin), TRUE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(*proi_width_spin), GTK_UPDATE_ALWAYS); gtk_table_attach(GTK_TABLE(packing_table), *proi_width_spin, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(*proi_width_spin); /* a little canvas indicator thingie to show the user who the new preferences will look */ #ifdef AMIDE_LIBGNOMECANVAS_AA roi_canvas = gnome_canvas_new_aa(); #else roi_canvas = gnome_canvas_new(); #endif gtk_widget_set_size_request(roi_canvas, 100, 100); gnome_canvas_set_scroll_region(GNOME_CANVAS(roi_canvas), 0.0, 0.0, 100.0, 100.0); gtk_table_attach(GTK_TABLE(packing_table), roi_canvas, 2,3,table_row,table_row+2, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(roi_canvas); /* the box */ roi_line_points = gnome_canvas_points_new(5); roi_line_points->coords[0] = 25.0; /* x1 */ roi_line_points->coords[1] = 25.0; /* y1 */ roi_line_points->coords[2] = 75.0; /* x2 */ roi_line_points->coords[3] = 25.0; /* y2 */ roi_line_points->coords[4] = 75.0; /* x3 */ roi_line_points->coords[5] = 75.0; /* y3 */ roi_line_points->coords[6] = 25.0; /* x4 */ roi_line_points->coords[7] = 75.0; /* y4 */ roi_line_points->coords[8] = 25.0; /* x4 */ roi_line_points->coords[9] = 25.0; /* y4 */ *proi_item = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(roi_canvas)), #ifdef AMIDE_LIBGNOMECANVAS_AA gnome_canvas_polygon_get_type(), #else gnome_canvas_line_get_type(), #endif "points", roi_line_points, NULL); gnome_canvas_points_unref(roi_line_points); table_row++; #ifdef AMIDE_LIBGNOMECANVAS_AA /* widget to change the transparency level */ /* only works for anti-aliased canvases */ /* widgets to change the roi's size */ label = gtk_label_new(_("ROI Transparency")); gtk_table_attach(GTK_TABLE(packing_table), label, 0, 1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); *proi_transparency_spin = gtk_spin_button_new_with_range(0.0,1.0,AMITK_PREFERENCES_DEFAULT_CANVAS_ROI_TRANSPARENCY); gtk_spin_button_set_increments(GTK_SPIN_BUTTON(*proi_transparency_spin),0.1,0.1); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(*proi_transparency_spin),FALSE); gtk_table_attach(GTK_TABLE(packing_table), *proi_transparency_spin, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(*proi_transparency_spin); table_row++; #else /* widgets to change the roi's line style */ /* Anti-aliased canvas doesn't yet support this */ /* also need to remove #ifndef for relevant lines in amitk_canvas_object.c and other locations */ label = gtk_label_new(_("ROI Line Style:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); *pline_style_menu = gtk_combo_box_new_text(); for (i_line_style=0; i_line_style<=GDK_LINE_DOUBLE_DASH; i_line_style++) gtk_combo_box_append_text(GTK_COMBO_BOX(*pline_style_menu), line_style_names[i_line_style]); gtk_widget_set_size_request (*pline_style_menu, 125, -1); gtk_table_attach(GTK_TABLE(packing_table), *pline_style_menu, 1,2, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(*pline_style_menu); table_row++; /* do we want to fill in isocontour roi's */ label = gtk_label_new(_("Draw Isocontours/Freehands Filled:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); *pfill_roi_button = gtk_check_button_new(); gtk_table_attach(GTK_TABLE(packing_table), *pfill_roi_button, 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(*pfill_roi_button); table_row++; #endif hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; gtk_widget_show(hseparator); label = gtk_label_new(_("Canvas Layout:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); /* the radio buttons */ *playout_button1 = gtk_radio_button_new(NULL); image = gtk_image_new_from_stock("amide_icon_layout_linear",GTK_ICON_SIZE_DIALOG); gtk_button_set_image(GTK_BUTTON(*playout_button1), image); gtk_table_attach(GTK_TABLE(packing_table), *playout_button1, 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(*playout_button1), "layout", GINT_TO_POINTER(AMITK_LAYOUT_LINEAR)); gtk_widget_show(*playout_button1); *playout_button2 = gtk_radio_button_new(NULL); gtk_radio_button_set_group(GTK_RADIO_BUTTON(*playout_button2), gtk_radio_button_get_group(GTK_RADIO_BUTTON(*playout_button1))); image = gtk_image_new_from_stock("amide_icon_layout_orthogonal",GTK_ICON_SIZE_DIALOG); gtk_button_set_image(GTK_BUTTON(*playout_button2), image); gtk_table_attach(GTK_TABLE(packing_table), *playout_button2, 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(*playout_button2), "layout", GINT_TO_POINTER(AMITK_LAYOUT_ORTHOGONAL)); gtk_widget_show(*playout_button2); table_row++; label = gtk_label_new(_("Multiple Canvases Layout:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); /* the radio buttons */ *ppanel_layout_button1 = gtk_radio_button_new(NULL); image = gtk_image_new_from_stock("amide_icon_panels_mixed", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_button_set_image(GTK_BUTTON(*ppanel_layout_button1), image); gtk_table_attach(GTK_TABLE(packing_table), *ppanel_layout_button1, 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(*ppanel_layout_button1), "panel_layout", GINT_TO_POINTER(AMITK_PANEL_LAYOUT_MIXED)); gtk_widget_show(*ppanel_layout_button1); *ppanel_layout_button2 = gtk_radio_button_new(NULL); gtk_radio_button_set_group(GTK_RADIO_BUTTON(*ppanel_layout_button2), gtk_radio_button_get_group(GTK_RADIO_BUTTON(*ppanel_layout_button1))); image = gtk_image_new_from_stock("amide_icon_panels_linear_x", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_button_set_image(GTK_BUTTON(*ppanel_layout_button2), image); gtk_table_attach(GTK_TABLE(packing_table), *ppanel_layout_button2, 2,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(*ppanel_layout_button2), "panel_layout", GINT_TO_POINTER(AMITK_PANEL_LAYOUT_LINEAR_X)); gtk_widget_show(*ppanel_layout_button2); *ppanel_layout_button3 = gtk_radio_button_new(NULL); gtk_radio_button_set_group(GTK_RADIO_BUTTON(*ppanel_layout_button3), gtk_radio_button_get_group(GTK_RADIO_BUTTON(*ppanel_layout_button1))); image = gtk_image_new_from_stock("amide_icon_panels_linear_y", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_button_set_image(GTK_BUTTON(*ppanel_layout_button3), image); gtk_table_attach(GTK_TABLE(packing_table), *ppanel_layout_button3, 3,4, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(*ppanel_layout_button3), "panel_layout", GINT_TO_POINTER(AMITK_PANEL_LAYOUT_LINEAR_Y)); gtk_widget_show(*ppanel_layout_button3); table_row++; /* do we want the size of the canvas to not resize */ label = gtk_label_new(_("Maintain view size constant:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); *pmaintain_size_button = gtk_check_button_new(); gtk_table_attach(GTK_TABLE(packing_table), *pmaintain_size_button, 1,2, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(*pmaintain_size_button); table_row++; /* widgets to change the amount of empty space in the center of the target */ label = gtk_label_new(_("Target Empty Area (pixels)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); adjustment = gtk_adjustment_new(AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA, AMITK_PREFERENCES_MIN_TARGET_EMPTY_AREA, AMITK_PREFERENCES_MAX_TARGET_EMPTY_AREA, 1.0, 1.0, 0.0); *ptarget_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment), 1.0, 0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(*ptarget_size_spin),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(*ptarget_size_spin), TRUE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(*ptarget_size_spin), TRUE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(*ptarget_size_spin), GTK_UPDATE_ALWAYS); gtk_table_attach(GTK_TABLE(packing_table), *ptarget_size_spin, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(*ptarget_size_spin); return; } GtkWidget * ui_common_create_view_axis_indicator(AmitkLayout layout) { GtkWidget * axis_indicator; AmitkView i_view; #ifdef AMIDE_LIBGNOMECANVAS_AA axis_indicator = gnome_canvas_new_aa(); #else axis_indicator = gnome_canvas_new(); #endif switch(layout) { case AMITK_LAYOUT_ORTHOGONAL: gtk_widget_set_size_request(axis_indicator, 2.0*AXIS_WIDTH, 2.0*ORTHOGONAL_AXIS_HEIGHT); gnome_canvas_set_scroll_region(GNOME_CANVAS(axis_indicator), 0.0, 0.0, 2.0*AXIS_WIDTH, 2.0*ORTHOGONAL_AXIS_HEIGHT); ui_common_draw_view_axis(GNOME_CANVAS(axis_indicator), 0, 0, AMITK_VIEW_TRANSVERSE, layout, AXIS_WIDTH, ORTHOGONAL_AXIS_HEIGHT); ui_common_draw_view_axis(GNOME_CANVAS(axis_indicator), 1, 0, AMITK_VIEW_CORONAL, layout, AXIS_WIDTH, ORTHOGONAL_AXIS_HEIGHT); ui_common_draw_view_axis(GNOME_CANVAS(axis_indicator), 0, 1, AMITK_VIEW_SAGITTAL, layout, AXIS_WIDTH, ORTHOGONAL_AXIS_HEIGHT); break; case AMITK_LAYOUT_LINEAR: default: gtk_widget_set_size_request(axis_indicator, 3.0*AXIS_WIDTH, LINEAR_AXIS_HEIGHT); gnome_canvas_set_scroll_region(GNOME_CANVAS(axis_indicator), 0.0, 0.0, 3.0*AXIS_WIDTH, LINEAR_AXIS_HEIGHT); for (i_view=0;i_view< AMITK_VIEW_NUM;i_view++) ui_common_draw_view_axis(GNOME_CANVAS(axis_indicator), 0, i_view, i_view, layout, AXIS_WIDTH, LINEAR_AXIS_HEIGHT); break; } return GTK_WIDGET(axis_indicator); } /* This data is in X bitmap format, and can be created with the 'bitmap' utility. */ #define small_dot_width 3 #define small_dot_height 3 static gchar small_dot_bits[] = {0x00, 0x02, 0x00}; /* load in the cursors */ static void ui_common_cursor_init(void) { GdkPixmap *source, *mask; GdkColor fg = { 0, 0, 0, 0 }; /* black. */ GdkColor bg = { 0, 0, 0, 0 }; /* black */ GdkCursor * small_dot; source = gdk_bitmap_create_from_data(NULL, small_dot_bits, small_dot_width, small_dot_height); mask = gdk_bitmap_create_from_data(NULL, small_dot_bits, small_dot_width, small_dot_height); small_dot = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 2,2); g_object_unref (source); g_object_unref (mask); /* load in the cursors */ ui_common_cursor[UI_CURSOR_DEFAULT] = NULL; ui_common_cursor[UI_CURSOR_ROI_MODE] = gdk_cursor_new(GDK_DRAFT_SMALL); ui_common_cursor[UI_CURSOR_ROI_RESIZE] = small_dot; /* was GDK_SIZING */ ui_common_cursor[UI_CURSOR_ROI_ROTATE] = small_dot; /* was GDK_EXCHANGE */ ui_common_cursor[UI_CURSOR_ROI_DRAW] = gdk_cursor_new(GDK_PENCIL); ui_common_cursor[UI_CURSOR_OBJECT_SHIFT] = small_dot; /* was GDK_FLEUR */ ui_common_cursor[UI_CURSOR_ROI_ISOCONTOUR] = gdk_cursor_new(GDK_DRAFT_SMALL); ui_common_cursor[UI_CURSOR_ROI_ERASE] = gdk_cursor_new(GDK_DRAFT_SMALL); ui_common_cursor[UI_CURSOR_DATA_SET_MODE] = gdk_cursor_new(GDK_CROSSHAIR); ui_common_cursor[UI_CURSOR_FIDUCIAL_MARK_MODE] = gdk_cursor_new(GDK_DRAFT_SMALL); ui_common_cursor[UI_CURSOR_RENDERING_ROTATE_XY] = gdk_cursor_new(GDK_FLEUR); ui_common_cursor[UI_CURSOR_RENDERING_ROTATE_Z] = gdk_cursor_new(GDK_EXCHANGE); ui_common_cursor[UI_CURSOR_WAIT] = gdk_cursor_new(GDK_WATCH); ui_common_cursors_initialized = TRUE; return; } /* replaces the current cursor with the specified cursor */ void ui_common_place_cursor_no_wait(ui_common_cursor_t which_cursor, GtkWidget * widget) { GdkCursor * cursor; /* make sure we have cursors */ if (!ui_common_cursors_initialized) ui_common_cursor_init(); /* sanity checks */ if (widget == NULL) return; if (!GTK_WIDGET_REALIZED(widget)) return; if (which_cursor != UI_CURSOR_WAIT) current_cursor = which_cursor; cursor = ui_common_cursor[which_cursor]; gdk_window_set_cursor(gtk_widget_get_parent_window(widget), cursor); return; } void ui_common_remove_wait_cursor(GtkWidget * widget) { ui_common_place_cursor_no_wait(current_cursor, widget); } /* replaces the current cursor with the specified cursor */ void ui_common_place_cursor(ui_common_cursor_t which_cursor, GtkWidget * widget) { /* call the actual function */ ui_common_place_cursor_no_wait(which_cursor, widget); /* do any events pending, this allows the cursor to get displayed */ while (gtk_events_pending()) gtk_main_iteration(); return; } static void entry_activate(GtkEntry * entry, gpointer data) { GtkWidget * dialog = data; gchar ** return_str_ptr; return_str_ptr = g_object_get_data(G_OBJECT(dialog), "return_str_ptr"); if(*return_str_ptr != NULL) g_free(*return_str_ptr); *return_str_ptr= g_strdup(gtk_entry_get_text(entry)); gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, strlen(*return_str_ptr)); return; } static void init_response_cb (GtkDialog * dialog, gint response_id, gpointer data) { gint return_val; switch(response_id) { case GTK_RESPONSE_OK: case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } /* a simple request dialog */ GtkWidget * ui_common_entry_dialog(GtkWindow * parent, gchar * prompt, gchar **return_str_ptr) { GtkWidget * dialog; GtkWidget * table; guint table_row; GtkWidget * entry; GtkWidget * label; GtkWidget * image; dialog = gtk_dialog_new_with_buttons (_("Request Dialog"), parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); g_object_set_data(G_OBJECT(dialog), "return_str_ptr", return_str_ptr); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(init_response_cb), NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK,FALSE); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); table = gtk_table_new(3,2,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,GTK_ICON_SIZE_DIALOG); gtk_table_attach(GTK_TABLE(table), image, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); label = gtk_label_new(prompt); gtk_table_attach(GTK_TABLE(table), label, 1,2, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); table_row++; entry = gtk_entry_new(); gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); gtk_table_attach(GTK_TABLE(table), entry, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(entry_activate), dialog); table_row++; gtk_widget_show_all(dialog); return dialog; } void ui_common_init_dialog_response_cb (GtkDialog * dialog, gint response_id, gpointer data) { gint return_val; switch(response_id) { case AMITK_RESPONSE_EXECUTE: case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } GList * ui_common_init_dialog_selected_objects(GtkWidget * dialog) { GList * objects; AmitkTreeView * tree_view; tree_view = g_object_get_data(G_OBJECT(dialog), "tree_view"); objects = amitk_tree_view_get_multiple_selection_objects(tree_view); return objects; } void ui_common_toolbar_insert_widget(GtkWidget * toolbar, GtkWidget * widget, const gchar * tooltip, gint position) { GtkToolItem * toolbar_item; toolbar_item = gtk_tool_item_new(); gtk_container_add(GTK_CONTAINER(toolbar_item), widget); if (tooltip != NULL) gtk_tool_item_set_tooltip_text(toolbar_item,tooltip); gtk_tool_item_set_homogeneous(toolbar_item, FALSE); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolbar_item, position); return; } void ui_common_toolbar_append_widget(GtkWidget * toolbar, GtkWidget * widget, const gchar * tooltip) { ui_common_toolbar_insert_widget(toolbar, widget, tooltip, -1); return; } void ui_common_toolbar_append_separator(GtkWidget * toolbar) { GtkToolItem * toolbar_item; toolbar_item = gtk_separator_tool_item_new(); gtk_tool_item_set_homogeneous(toolbar_item, FALSE); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolbar_item, -1); return; } /* internal variables */ static GList * windows = NULL; /* keep track of open windows */ void amide_register_window(gpointer * widget) { g_return_if_fail(widget != NULL); windows = g_list_append(windows, widget); return; } /* keep track of open windows */ void amide_unregister_window(gpointer * widget) { g_return_if_fail(widget != NULL); windows = g_list_remove(windows, widget); if (windows == NULL) gtk_main_quit(); return; } /* this should cleanly exit the program */ void amide_unregister_all_windows(void) { gboolean return_val; gint number_to_leave=0; while (g_list_nth(windows, number_to_leave) != NULL) { /* this works, because each delete event should call amide_unregister_window */ g_signal_emit_by_name(G_OBJECT(windows->data), "delete_event", NULL, &return_val); if (return_val == TRUE) number_to_leave++; } return; } void amide_call_help(const gchar * link_id) { #ifndef OLD_WIN32_HACKS GError *error=NULL; amide_gnome_help_display(PACKAGE, link_id, &error); if (error != NULL) { g_warning("couldn't open help file, error: %s", error->message); g_error_free(error); } #else g_warning("Help is unavailable in the Windows version. Please see the help documentation online at http://amide.sf.net, or in the AMIDE install folder"); #endif return; } amide-1.0.6/amide-current/src/ui_common.h000066400000000000000000000100621423227705100202630ustar00rootroot00000000000000/* ui_common.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* header files that are always needed with this file */ #include #include #include "amitk_point.h" #define HELP_MENU_UI_DESCRIPTION " " typedef enum { UI_CURSOR_DEFAULT, UI_CURSOR_ROI_MODE, UI_CURSOR_ROI_RESIZE, UI_CURSOR_ROI_ROTATE, UI_CURSOR_OBJECT_SHIFT, UI_CURSOR_ROI_ISOCONTOUR, UI_CURSOR_ROI_ERASE, UI_CURSOR_ROI_DRAW, UI_CURSOR_DATA_SET_MODE, UI_CURSOR_FIDUCIAL_MARK_MODE, UI_CURSOR_RENDERING_ROTATE_XY, UI_CURSOR_RENDERING_ROTATE_Z, UI_CURSOR_WAIT, NUM_CURSORS } ui_common_cursor_t; typedef enum { UI_COMMON_HELP_MENU_CONTENTS, UI_COMMON_HELP_MENU_ABOUT, UI_COMMON_HELP_MENU_NUM } ui_common_help_menu_t; /* external functions */ gboolean ui_common_check_filename(const gchar * filename); void ui_common_set_last_path_used(const gchar * last_path_used); gchar * ui_common_suggest_path(void); void ui_common_entry_name_cb(gchar * entry_string, gpointer data); void ui_common_about_cb(GtkWidget * button, gpointer data); void ui_common_draw_view_axis(GnomeCanvas * canvas, gint row, gint column, AmitkView view, AmitkLayout layout, gint axis_width, gint axis_height); void ui_common_update_sample_roi_item(GnomeCanvasItem * roi_item, gint roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA gdouble transparency #else GdkLineStyle line_style #endif ); void ui_common_study_preferences_widgets(GtkWidget * packing_table, gint table_row, GtkWidget ** proi_width_spin, GnomeCanvasItem ** proi_item, #ifdef AMIDE_LIBGNOMECANVAS_AA GtkWidget ** proi_transparency_spin, #else GtkWidget ** pline_style_menu, GtkWidget ** fill_roi_button, #endif GtkWidget ** playout_button1, GtkWidget ** playout_button2, GtkWidget ** ppanel_layout_button1, GtkWidget ** ppanel_layout_button2, GtkWidget ** ppanel_layout_button3, GtkWidget ** pmaintain_size_button, GtkWidget ** ptarget_size_spin); GtkWidget * ui_common_create_view_axis_indicator(AmitkLayout layout); void ui_common_place_cursor_no_wait(ui_common_cursor_t which_cursor, GtkWidget * widget); void ui_common_remove_wait_cursor(GtkWidget * widget); void ui_common_place_cursor(ui_common_cursor_t which_cursor, GtkWidget * widget); GtkWidget * ui_common_entry_dialog(GtkWindow * parent, gchar * prompt, gchar **return_str_ptr); void ui_common_init_dialog_response_cb (GtkDialog * dialog, gint response_id, gpointer data); GList * ui_common_init_dialog_selected_objects(GtkWidget * dialog); void ui_common_toolbar_insert_widget(GtkWidget * toolbar, GtkWidget * widget, const gchar * tooltip, gint position); void ui_common_toolbar_append_widget(GtkWidget * toolbar, GtkWidget * widget, const gchar * tooltip); void ui_common_toolbar_append_separator(GtkWidget * toolbar); void amide_call_help(const gchar * link_id); void amide_register_window(gpointer * widget); void amide_unregister_window(gpointer * widget); void amide_unregister_all_windows(void); /* external variables */ extern GtkActionEntry ui_common_help_menu_items[UI_COMMON_HELP_MENU_NUM]; extern GdkCursor * ui_common_cursor[NUM_CURSORS]; amide-1.0.6/amide-current/src/ui_gate_dialog.c000066400000000000000000000400101423227705100212210ustar00rootroot00000000000000/* ui_gate_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2004-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "amitk_common.h" #include "ui_gate_dialog.h" typedef enum { COLUMN_GATE, COLUMN_GATE_TIME, NUM_COLUMNS } column_type_t; static gboolean column_use_my_renderer[NUM_COLUMNS] = { FALSE, TRUE }; enum { ENTRY_START, ENTRY_END, NUM_ENTRIES }; static gchar * column_names[] = { N_("Gate #"), N_("Gate Time (s)") }; typedef struct ui_gate_dialog_t { AmitkDataSet * ds; GtkWidget * tree_view; GtkWidget * start_spin; GtkWidget * end_spin; GtkWidget * autoplay_check_button; guint idle_handler_id; gboolean valid; gint start_gate; gint end_gate; } ui_gate_dialog_t; static void selection_for_each_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); static void autoplay_cb(GtkWidget * widget, gpointer data); static gboolean autoplay_update_while_idle(gpointer data); static void selection_changed_cb (GtkTreeSelection *selection, gpointer data); static gboolean delete_event_cb(GtkWidget* dialog, GdkEvent * event, gpointer data); static void change_spin_cb(GtkSpinButton * spin_button, gpointer data); static void update_model(GtkListStore * store, GtkTreeSelection *selection, AmitkDataSet * ds); static void update_selections(GtkTreeModel * model, GtkTreeSelection *selection, GtkWidget * dialog, ui_gate_dialog_t * gd); static void update_entries(GtkWidget * dialog); static void data_set_gate_changed_cb(AmitkDataSet * ds, gpointer dialog); static void remove_data_set(GtkWidget * dialog); static void selection_for_each_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gint i_gate; ui_gate_dialog_t * gd = data; gtk_tree_model_get(model, iter, COLUMN_GATE, &i_gate, -1); if (!gd->valid) { gd->start_gate = i_gate; gd->end_gate = i_gate; gd->valid = TRUE; } else { if (i_gate < gd->start_gate) gd->start_gate = i_gate; else if (i_gate > gd->end_gate) gd->end_gate = i_gate; } return; } static void autoplay_cb(GtkWidget * widget, gpointer data) { ui_gate_dialog_t * gd=data; guint interval; gboolean autoplay; autoplay = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gd->autoplay_check_button)); if (gd->ds == NULL) { autoplay = FALSE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gd->autoplay_check_button), FALSE); } if (autoplay) { interval = 1000.0 / AMITK_DATA_SET_NUM_GATES(gd->ds); /* try to cycle through in 1000 ms */ if (interval < 200) interval= 200; /* set 200 ms as lowest repetition rate) */ if (gd->idle_handler_id == 0) gd->idle_handler_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE,interval,autoplay_update_while_idle, gd, NULL); } else { if (gd->idle_handler_id != 0) { g_source_remove(gd->idle_handler_id); gd->idle_handler_id=0; } } return; } static gboolean autoplay_update_while_idle(gpointer data) { ui_gate_dialog_t * gd=data; if (gd->ds == NULL) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gd->autoplay_check_button), FALSE); return FALSE; } gd->start_gate = 1 + AMITK_DATA_SET_VIEW_START_GATE(gd->ds); if (gd->start_gate >= AMITK_DATA_SET_NUM_GATES(gd->ds)) gd->start_gate = 0; gd->end_gate = gd->start_gate; amitk_data_set_set_view_start_gate(gd->ds, gd->start_gate); amitk_data_set_set_view_end_gate(gd->ds, gd->end_gate); return TRUE; } /* reset out start and duration based on what just got selected */ static void selection_changed_cb (GtkTreeSelection *selection, gpointer data) { GtkWidget * dialog = data; ui_gate_dialog_t * gd; gd = g_object_get_data(G_OBJECT(dialog), "gd"); if (gd->ds == NULL) return; /* run the following function on each selected row */ gd->valid = FALSE; gtk_tree_selection_selected_foreach(selection, selection_for_each_func, gd); amitk_data_set_set_view_start_gate(gd->ds, gd->start_gate); amitk_data_set_set_view_end_gate(gd->ds, gd->end_gate); return; } /* function called to destroy the gate dialog */ static gboolean delete_event_cb(GtkWidget* dialog, GdkEvent * event, gpointer data) { ui_gate_dialog_t * gd = data; GtkTreeSelection *selection; /* explicitly disconnect signals, sometimes GTK throws some of these on delete (after unref'ing study */ g_signal_handlers_disconnect_by_func(G_OBJECT(gd->start_spin), G_CALLBACK(change_spin_cb), dialog); g_signal_handlers_disconnect_by_func(G_OBJECT(gd->end_spin), G_CALLBACK(change_spin_cb), dialog); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gd->tree_view)); g_signal_handlers_disconnect_by_func(G_OBJECT(selection), G_CALLBACK(selection_changed_cb), dialog); /* trash collection */ if (gd->idle_handler_id != 0) { g_source_remove(gd->idle_handler_id); gd->idle_handler_id=0; } remove_data_set(dialog); g_free(gd); return FALSE; } /* function called when a numerical spin button has been changed */ static void change_spin_cb(GtkSpinButton * spin_button, gpointer data) { gint temp_val; gint which_widget; GtkWidget * dialog = data; ui_gate_dialog_t * gd; // GtkTreeSelection *selection; // GtkTreeModel * model; which_widget = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "type")); gd = g_object_get_data(G_OBJECT(dialog), "gd"); if (gd->ds == NULL) return; temp_val = gtk_spin_button_get_value_as_int(spin_button); switch(which_widget) { case ENTRY_START: amitk_data_set_set_view_start_gate(gd->ds, temp_val); break; case ENTRY_END: amitk_data_set_set_view_end_gate(gd->ds, temp_val); break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } // model = gtk_tree_view_get_model(GTK_TREE_VIEW(gd->tree_view)); // selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(gd->tree_view)); // update_selections(model, selection, dialog, gd); update_entries(dialog); return; } static void update_model(GtkListStore * store, GtkTreeSelection *selection, AmitkDataSet * ds) { GtkTreeIter iter; guint i_gate; gtk_list_store_clear(store); /* make sure the list is clear */ if (ds == NULL) return; /* start generating our list of options */ for (i_gate=0; i_gate < AMITK_DATA_SET_NUM_GATES(ds); i_gate++) { /* setup the corresponding list entry */ gtk_list_store_append (store, &iter); /* Acquire an iterator */ gtk_list_store_set(store, &iter, COLUMN_GATE, i_gate, COLUMN_GATE_TIME, amitk_data_set_get_gate_time(ds,i_gate), -1); } return; } static void update_selections(GtkTreeModel * model, GtkTreeSelection *selection, GtkWidget * dialog, ui_gate_dialog_t * gd) { GtkTreeIter iter; gint iter_gate; gboolean select; if (gd->ds == NULL) return; /* Block signals to this list widget. I need to do this, as I'll be selecting rows, causing the emission of "changed" signals */ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(selection_changed_cb), dialog); if (gtk_tree_model_get_iter_first(model, &iter)) { do { gtk_tree_model_get(model, &iter, COLUMN_GATE, &iter_gate,-1); /* figure out if this row is suppose to be selected */ select = FALSE; if (AMITK_DATA_SET_VIEW_START_GATE(gd->ds) > AMITK_DATA_SET_VIEW_END_GATE(gd->ds)) { if ((iter_gate >= AMITK_DATA_SET_VIEW_START_GATE(gd->ds)) || (iter_gate <= AMITK_DATA_SET_VIEW_END_GATE(gd->ds))) select = TRUE; } else { if ((iter_gate >= AMITK_DATA_SET_VIEW_START_GATE(gd->ds)) && (iter_gate <= AMITK_DATA_SET_VIEW_END_GATE(gd->ds))) select = TRUE; } if (select) gtk_tree_selection_select_iter(selection, &iter); else gtk_tree_selection_unselect_iter(selection, &iter); } while(gtk_tree_model_iter_next(model, &iter)); } /* done updating the list, we can reconnect signals now */ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(selection_changed_cb), dialog); return; } static void update_entries(GtkWidget * dialog) { ui_gate_dialog_t * gd; gint value; gd = g_object_get_data(G_OBJECT(dialog), "gd"); g_signal_handlers_block_by_func(G_OBJECT(gd->start_spin), G_CALLBACK(change_spin_cb), dialog); value = (gd->ds != NULL) ? AMITK_DATA_SET_VIEW_START_GATE(gd->ds) : 0; gtk_spin_button_set_value(GTK_SPIN_BUTTON(gd->start_spin), value); g_signal_handlers_unblock_by_func(G_OBJECT(gd->start_spin), G_CALLBACK(change_spin_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(gd->end_spin), G_CALLBACK(change_spin_cb), dialog); value = (gd->ds != NULL) ? AMITK_DATA_SET_VIEW_END_GATE(gd->ds) : 0; gtk_spin_button_set_value(GTK_SPIN_BUTTON(gd->end_spin), value); g_signal_handlers_unblock_by_func(G_OBJECT(gd->end_spin), G_CALLBACK(change_spin_cb), dialog); return; } static void data_set_gate_changed_cb(AmitkDataSet * ds, gpointer data) { GtkWidget * dialog = data; ui_gate_dialog_t * gd; GtkTreeSelection *selection; GtkTreeModel * model; gd = g_object_get_data(G_OBJECT(dialog), "gd"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(gd->tree_view)); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(gd->tree_view)); update_selections(model, selection, dialog, gd); update_entries(dialog); } static void remove_data_set(GtkWidget * dialog) { ui_gate_dialog_t * gd; gd = g_object_get_data(G_OBJECT(dialog), "gd"); if (gd->ds == NULL) return; g_signal_handlers_disconnect_by_func(G_OBJECT(gd->ds), G_CALLBACK(data_set_gate_changed_cb), dialog); amitk_object_unref(gd->ds); gd->ds = NULL; return; } void ui_gate_dialog_set_active_data_set(GtkWidget * dialog, AmitkDataSet * ds) { ui_gate_dialog_t * gd; GtkTreeSelection *selection; GtkTreeModel * model; g_return_if_fail(dialog != NULL); gd = g_object_get_data(G_OBJECT(dialog), "gd"); remove_data_set(dialog); if (ds != NULL) if (AMITK_IS_DATA_SET(ds)) { gd->ds = amitk_object_ref(ds); g_signal_connect(G_OBJECT(ds), "view_gates_changed", G_CALLBACK(data_set_gate_changed_cb), dialog); } model = gtk_tree_view_get_model(GTK_TREE_VIEW(gd->tree_view)); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(gd->tree_view)); update_model(GTK_LIST_STORE(model), selection,gd->ds); update_selections(model, selection, dialog, gd); update_entries(dialog); return; } /* create the gate selection dialog */ GtkWidget * ui_gate_dialog_create(AmitkDataSet * ds, GtkWindow * parent) { GtkWidget * dialog; gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * label; GtkWidget * scrolled; guint table_row = 0; ui_gate_dialog_t * gd; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkWidget * hseparator; column_type_t i_column; temp_string = g_strdup_printf(_("%s: Gate Dialog"),PACKAGE); dialog = gtk_dialog_new_with_buttons(temp_string, parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, NULL); g_free(temp_string); gtk_window_set_resizable(GTK_WINDOW(dialog), TRUE); gd = g_try_new(ui_gate_dialog_t, 1); g_return_val_if_fail(gd != NULL, NULL); gd->ds = NULL; gd->ds = amitk_object_ref(ds); gd->idle_handler_id=0; g_object_set_data(G_OBJECT(dialog), "gd", gd); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(delete_event_cb), gd); /* start making the widgets for this dialog box */ packing_table = gtk_table_new(5,4,FALSE); table_row=0; gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), packing_table); label = gtk_label_new(_("Start Gate")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gd->start_spin = gtk_spin_button_new_with_range(0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(gd->start_spin), TRUE); g_object_set_data(G_OBJECT(gd->start_spin), "type", GINT_TO_POINTER(ENTRY_START)); g_signal_connect(G_OBJECT(gd->start_spin), "value_changed", G_CALLBACK(change_spin_cb), dialog); g_signal_connect(G_OBJECT(gd->start_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), gd->start_spin,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("End Gate")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gd->end_spin = gtk_spin_button_new_with_range(0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(gd->end_spin), TRUE); g_object_set_data(G_OBJECT(gd->end_spin), "type", GINT_TO_POINTER(ENTRY_END)); g_signal_connect(G_OBJECT(gd->end_spin), "value_changed", G_CALLBACK(change_spin_cb), dialog); g_signal_connect(G_OBJECT(gd->end_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), gd->end_spin,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* the scroll widget which the list will go into */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,350,200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_table_attach(GTK_TABLE(packing_table), scrolled, 0,2, table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* and the list itself */ store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, AMITK_TYPE_TIME); gd->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); for (i_column=0; i_columntree_view), column); } selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gd->tree_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (selection_changed_cb), dialog); gtk_container_add(GTK_CONTAINER(scrolled),gd->tree_view); /* check button for autoplay */ gd->autoplay_check_button = gtk_check_button_new_with_label (_("Auto play")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gd->autoplay_check_button), FALSE); g_signal_connect(G_OBJECT(gd->autoplay_check_button), "toggled", G_CALLBACK(autoplay_cb),gd); gtk_table_attach(GTK_TABLE(packing_table), gd->autoplay_check_button,0,2,table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* fill in the list/update entries */ ui_gate_dialog_set_active_data_set(dialog, ds); /* and show all our widgets */ gtk_widget_show_all(dialog); return dialog; } amide-1.0.6/amide-current/src/ui_gate_dialog.h000066400000000000000000000021451423227705100212350ustar00rootroot00000000000000/* ui_gate_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2004-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* header files always needed with this */ #include "amitk_data_set.h" /* external functions */ void ui_gate_dialog_set_active_data_set(GtkWidget * dialog, AmitkDataSet * ds); GtkWidget * ui_gate_dialog_create(AmitkDataSet * ds, GtkWindow * parent); amide-1.0.6/amide-current/src/ui_preferences_dialog.c000066400000000000000000000524241423227705100226160ustar00rootroot00000000000000/* ui_preferences_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide.h" #include "ui_study.h" #include "ui_preferences_dialog.h" #include "amitk_canvas.h" #include "amitk_color_table_menu.h" #include "amitk_threshold.h" #include "amitk_window_edit.h" #include "ui_common.h" static gchar * study_preference_text = N_("These preferences are used only for new studies. \n" "Use the study modification dialog to change these \n" "parameters for the current study."); static gchar * data_set_preference_text = N_("These preferences are used only for new data sets. \n" "Use the data set modification dialog to change these \n" "parameters for the current data set."); static void update_roi_sample_item(ui_study_t * ui_study); static void roi_width_cb(GtkWidget * widget, gpointer data); #ifdef AMIDE_LIBGNOMECANVAS_AA static void roi_transparency_cb(GtkWidget * widget, gpointer data); #else static void line_style_cb(GtkWidget * widget, gpointer data); static void fill_roi_cb(GtkWidget * widget, gpointer data); #endif static void layout_cb(GtkWidget * widget, gpointer data); static void panel_layout_cb(GtkWidget * widget, gpointer data); static void maintain_size_cb(GtkWidget * widget, gpointer data); static void target_empty_area_cb(GtkWidget * widget, gpointer data); static void threshold_style_cb(GtkWidget * widget, gpointer data); static void warnings_to_console_cb(GtkWidget * widget, gpointer data); static void save_on_exit_cb(GtkWidget * widget, gpointer data); static void which_default_directory_cb(GtkWidget * widget, gpointer data); static void default_directory_cb(GtkWidget * fc, gpointer data); static void response_cb (GtkDialog * dialog, gint response_id, gpointer data); static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer preferences); /* function called to update the roi sampe item */ static void update_roi_sample_item(ui_study_t * ui_study) { GnomeCanvasItem * roi_item; roi_item = g_object_get_data(G_OBJECT(ui_study->preferences->dialog), "roi_item"); ui_common_update_sample_roi_item(roi_item, AMITK_PREFERENCES_CANVAS_ROI_WIDTH(ui_study->preferences), #ifdef AMIDE_LIBGNOMECANVAS_AA AMITK_PREFERENCES_CANVAS_ROI_TRANSPARENCY(ui_study->preferences) #else AMITK_PREFERENCES_CANVAS_LINE_STYLE(ui_study->preferences) #endif ); return; } /* function called when the roi width has been changed */ static void roi_width_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; gint new_roi_width; g_return_if_fail(ui_study->study != NULL); new_roi_width = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); amitk_preferences_set_canvas_roi_width(ui_study->preferences, new_roi_width); update_roi_sample_item(ui_study); return; } #ifdef AMIDE_LIBGNOMECANVAS_AA /* function to change the roi internal transparency */ static void roi_transparency_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study=data; gdouble new_transparency; g_return_if_fail(ui_study->study != NULL); new_transparency = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); amitk_preferences_set_canvas_roi_transparency(ui_study->preferences, new_transparency); update_roi_sample_item(ui_study); return; } #else /* function to change the line style */ static void line_style_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study=data; GdkLineStyle new_line_style; GnomeCanvasItem * roi_item; g_return_if_fail(ui_study->study != NULL); /* figure out which menu item called me */ new_line_style = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); amitk_preferences_set_canvas_line_style(ui_study->preferences, new_line_style); update_roi_sample_item(ui_study); return; } static void fill_roi_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_canvas_fill_roi(ui_study->preferences, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } #endif /* function called to change the layout */ static void layout_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_canvas_layout(ui_study->preferences, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "layout"))); return; } /* function called to change the panel layout */ static void panel_layout_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_panel_layout(ui_study->preferences, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "panel_layout"))); return; } static void maintain_size_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_canvas_maintain_size(ui_study->preferences, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } /* function called when the roi width has been changed */ static void target_empty_area_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_canvas_target_empty_area(ui_study->preferences, gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget))); return; } static void threshold_style_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_threshold_style(ui_study->preferences, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "threshold_style"))); return; } static void warnings_to_console_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_warnings_to_console(ui_study->preferences, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void save_on_exit_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_prompt_for_save_on_exit(ui_study->preferences, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void which_default_directory_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; amitk_preferences_set_which_default_directory(ui_study->preferences, gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } static void default_directory_cb(GtkWidget * fc, gpointer data) { ui_study_t * ui_study = data; gchar * str; str = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); amitk_preferences_set_default_directory(ui_study->preferences, str); g_free(str); return; } /* changing the color table of a rendering context */ static void color_table_cb(GtkWidget * widget, gpointer data) { ui_study_t * ui_study=data; AmitkModality modality; AmitkColorTable color_table; modality = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "modality")); color_table = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); amitk_preferences_set_color_table(ui_study->preferences, modality, color_table); return; } static void response_cb (GtkDialog * dialog, gint response_id, gpointer data) { gint return_val; switch(response_id) { case GTK_RESPONSE_HELP: amide_call_help("preferences-dialog"); break; case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } /* function called to destroy the preferences dialog */ gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { AmitkPreferences * preferences = data; amitk_preferences_set_dialog(preferences, NULL); return FALSE; } /* function that sets up the preferences dialog */ void ui_preferences_dialog_create(ui_study_t * ui_study) { GtkWidget * dialog; gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * label; GtkWidget * check_button; GtkWidget * notebook; guint table_row; GtkWidget * maintain_size_button; GtkWidget * roi_width_spin; GtkWidget * target_size_spin; #ifdef AMIDE_LIBGNOMECANVAS_AA GtkWidget * roi_transparency_spin; #else GtkWidget * line_style_menu; GtkWidget * fill_roi_button; #endif GtkWidget * layout_button1; GtkWidget * layout_button2; GtkWidget * panel_layout_button1; GtkWidget * panel_layout_button2; GtkWidget * panel_layout_button3; GtkWidget * hseparator; GtkWidget * menu; GtkWidget * windows_widget; GtkWidget * scrolled; GtkWidget * entry; AmitkModality i_modality; AmitkWhichDefaultDirectory i_which_default_directory; GnomeCanvasItem * roi_item; AmitkThresholdStyle i_threshold_style; GtkWidget * style_buttons[AMITK_THRESHOLD_STYLE_NUM]; GtkWidget * hbox; /* sanity checks */ g_return_if_fail(ui_study != NULL); g_return_if_fail(ui_study->preferences != NULL); /* only have one preference dialog */ if (AMITK_PREFERENCES_DIALOG(ui_study->preferences) != NULL) { g_warning("A Preferences Dialog is already open"); return; } temp_string = g_strdup_printf(_("%s: Preferences Dialog"), PACKAGE); dialog = gtk_dialog_new_with_buttons (temp_string, ui_study->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); gtk_window_set_title(GTK_WINDOW(dialog), temp_string); g_free(temp_string); amitk_preferences_set_dialog(ui_study->preferences, dialog); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_cb), ui_study); g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(delete_event_cb), ui_study->preferences); notebook = gtk_notebook_new(); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), notebook); /* --------------------------- ROI/Canvas page --------------------------- */ /* start making the widgets for this dialog box */ packing_table = gtk_table_new(4,5,FALSE); label = gtk_label_new(_("ROI/View Preferences")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); /* warn that these preferences are only for new stuff */ label = gtk_label_new(study_preference_text); gtk_table_attach(GTK_TABLE(packing_table), label, 0,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); table_row++; hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; ui_common_study_preferences_widgets(packing_table, table_row, &roi_width_spin, &roi_item, #ifdef AMIDE_LIBGNOMECANVAS_AA &roi_transparency_spin, #else &line_style_menu, &fill_roi_button, #endif &layout_button1, &layout_button2, &panel_layout_button1,&panel_layout_button2,&panel_layout_button3, &maintain_size_button, &target_size_spin); gtk_spin_button_set_value(GTK_SPIN_BUTTON(roi_width_spin), AMITK_PREFERENCES_CANVAS_ROI_WIDTH(ui_study->preferences)); g_signal_connect(G_OBJECT(roi_width_spin), "value_changed", G_CALLBACK(roi_width_cb), ui_study); /* update the sample roi display */ g_object_set_data(G_OBJECT(dialog), "roi_item", roi_item); update_roi_sample_item(ui_study); #ifdef AMIDE_LIBGNOMECANVAS_AA gtk_spin_button_set_value(GTK_SPIN_BUTTON(roi_transparency_spin), AMITK_PREFERENCES_CANVAS_ROI_TRANSPARENCY(ui_study->preferences)); g_signal_connect(G_OBJECT(roi_transparency_spin), "value_changed", G_CALLBACK(roi_transparency_cb), ui_study); #else gtk_combo_box_set_active(GTK_COMBO_BOX(line_style_menu), AMITK_PREFERENCES_CANVAS_LINE_STYLE(ui_study->preferences)); g_signal_connect(G_OBJECT(line_style_menu), "changed", G_CALLBACK(line_style_cb), ui_study); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fill_roi_button), AMITK_PREFERENCES_CANVAS_FILL_ROI(ui_study->preferences)); g_signal_connect(G_OBJECT(fill_roi_button), "toggled", G_CALLBACK(fill_roi_cb), ui_study); #endif gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(layout_button1), (AMITK_PREFERENCES_CANVAS_LAYOUT(ui_study->preferences) == AMITK_LAYOUT_LINEAR)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(layout_button2), (AMITK_PREFERENCES_CANVAS_LAYOUT(ui_study->preferences) == AMITK_LAYOUT_ORTHOGONAL)); g_signal_connect(G_OBJECT(layout_button1), "clicked", G_CALLBACK(layout_cb), ui_study); g_signal_connect(G_OBJECT(layout_button2), "clicked", G_CALLBACK(layout_cb), ui_study); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel_layout_button1), (AMITK_PREFERENCES_PANEL_LAYOUT(ui_study->preferences) == AMITK_PANEL_LAYOUT_MIXED)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel_layout_button2), (AMITK_PREFERENCES_PANEL_LAYOUT(ui_study->preferences) == AMITK_PANEL_LAYOUT_LINEAR_X)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel_layout_button3), (AMITK_PREFERENCES_PANEL_LAYOUT(ui_study->preferences) == AMITK_PANEL_LAYOUT_LINEAR_Y)); g_signal_connect(G_OBJECT(panel_layout_button1), "clicked", G_CALLBACK(panel_layout_cb), ui_study); g_signal_connect(G_OBJECT(panel_layout_button2), "clicked", G_CALLBACK(panel_layout_cb), ui_study); g_signal_connect(G_OBJECT(panel_layout_button3), "clicked", G_CALLBACK(panel_layout_cb), ui_study); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(maintain_size_button), AMITK_PREFERENCES_CANVAS_MAINTAIN_SIZE(ui_study->preferences)); g_signal_connect(G_OBJECT(maintain_size_button), "toggled", G_CALLBACK(maintain_size_cb), ui_study); gtk_spin_button_set_value(GTK_SPIN_BUTTON(target_size_spin), AMITK_PREFERENCES_CANVAS_TARGET_EMPTY_AREA(ui_study->preferences)); g_signal_connect(G_OBJECT(target_size_spin), "value_changed", G_CALLBACK(target_empty_area_cb), ui_study); gtk_widget_show_all(packing_table); /* ---------------------- Threshold Windows ---------------------- */ packing_table = gtk_table_new(4,2,FALSE); label = gtk_label_new(_("Thresholding")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); /* warn that these preferences are only for new stuff */ label = gtk_label_new(data_set_preference_text); gtk_table_attach(GTK_TABLE(packing_table), label, 0,3, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); table_row++; hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 3, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hseparator); table_row++; /* threshold type selection */ label = gtk_label_new(_("Threshold Style")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); hbox = gtk_hbox_new(FALSE, 0); amitk_threshold_style_widgets(style_buttons, hbox); gtk_table_attach(GTK_TABLE(packing_table), hbox, 1,2, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(style_buttons[AMITK_PREFERENCES_THRESHOLD_STYLE(ui_study->preferences)]), TRUE); for (i_threshold_style = 0; i_threshold_style < AMITK_THRESHOLD_STYLE_NUM; i_threshold_style++) g_signal_connect(G_OBJECT(style_buttons[i_threshold_style]), "clicked", G_CALLBACK(threshold_style_cb), ui_study); gtk_widget_show(hbox); table_row++; /* draw the window widgets */ scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); windows_widget = amitk_window_edit_new(NULL, ui_study->preferences); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), windows_widget); gtk_widget_show(windows_widget); gtk_table_attach(GTK_TABLE(packing_table), scrolled, 0,2, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, GTK_FILL|GTK_EXPAND, X_PADDING, Y_PADDING); gtk_widget_show(scrolled); gtk_widget_show(packing_table); /* ---------------------- Default color tables ---------------------- */ packing_table = gtk_table_new(4,2,FALSE); label = gtk_label_new(_("Default Color Tables")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); for (i_modality=0; i_modality < AMITK_MODALITY_NUM; i_modality++) { /* color table selector */ temp_string = g_strdup_printf(_("default %s color table:"), amitk_modality_get_name(i_modality)); label = gtk_label_new(temp_string); g_free(temp_string); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); menu = amitk_color_table_menu_new(); gtk_table_attach(GTK_TABLE(packing_table), menu, 1,2, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_combo_box_set_active(GTK_COMBO_BOX(menu), AMITK_PREFERENCES_COLOR_TABLE(ui_study->preferences, i_modality)); g_object_set_data(G_OBJECT(menu), "modality", GINT_TO_POINTER(i_modality)); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(color_table_cb), ui_study); gtk_widget_show(menu); table_row++; } gtk_widget_show_all(packing_table); /* --------------------------- Miscellaneous stuff --------------------------- */ /* start making the widgets for this dialog box */ packing_table = gtk_table_new(4,5,FALSE); label = gtk_label_new(_("Miscellaneous")); table_row=0; gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); label = gtk_label_new(_("Send Warning Messages to Console:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); check_button = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), AMITK_PREFERENCES_WARNINGS_TO_CONSOLE(ui_study->preferences)); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(warnings_to_console_cb), ui_study); gtk_table_attach(GTK_TABLE(packing_table), check_button, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Prompt for \"Save Changes\" on Exit:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); check_button = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), AMITK_PREFERENCES_PROMPT_FOR_SAVE_ON_EXIT(ui_study->preferences)); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(save_on_exit_cb), ui_study); gtk_table_attach(GTK_TABLE(packing_table), check_button, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Which Default Directory:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_which_default_directory=0; i_which_default_directory < AMITK_WHICH_DEFAULT_DIRECTORY_NUM; i_which_default_directory++) gtk_combo_box_append_text(GTK_COMBO_BOX(menu), amitk_which_default_directory_names[i_which_default_directory]); gtk_combo_box_set_active(GTK_COMBO_BOX(menu), AMITK_PREFERENCES_WHICH_DEFAULT_DIRECTORY(ui_study->preferences)); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(which_default_directory_cb), ui_study); gtk_table_attach(GTK_TABLE(packing_table), menu, 1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Specified Directory:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); entry = gtk_file_chooser_button_new(_("Default Directory:"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); amitk_preferences_set_file_chooser_directory(ui_study->preferences, entry); /* set the default directory if applicable */ g_signal_connect(G_OBJECT(entry), "current-folder-changed", G_CALLBACK(default_directory_cb), ui_study); gtk_table_attach(GTK_TABLE(packing_table), entry, 1,2, table_row, table_row+1, GTK_FILL|GTK_EXPAND, 0, X_PADDING, Y_PADDING); /* make sure what's being shown in the above widget is consistent with what we have, this only comes up if we've never set a default directory before */ if (AMITK_PREFERENCES_DEFAULT_DIRECTORY(ui_study->preferences) == NULL) default_directory_cb(entry, ui_study); table_row++; gtk_widget_show_all(packing_table); /* and show all our widgets */ gtk_widget_show(notebook); gtk_widget_show(dialog); return; } amide-1.0.6/amide-current/src/ui_preferences_dialog.h000066400000000000000000000017141423227705100226170ustar00rootroot00000000000000/* ui_preferences_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* external functions */ void ui_preferences_dialog_create(ui_study_t * ui_study); amide-1.0.6/amide-current/src/ui_render.c000066400000000000000000001146231423227705100202550ustar00rootroot00000000000000/* ui_render.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBVOLPACK_SUPPORT #include #include "amide_gconf.h" #include "image.h" #include "ui_common.h" #include "ui_render.h" #include "ui_render_dialog.h" #include "ui_render_movie.h" #include "amitk_dial.h" #include "amitk_progress_dialog.h" #include "amitk_tree_view.h" #include "amitk_common.h" #define UPDATE_NONE 0 #define UPDATE_RENDERING 0x1 static gboolean canvas_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void stereoscopic_cb(GtkRadioAction * action, GtkRadioAction * current, gpointer data); static void change_zoom_cb(GtkWidget * widget, gpointer data); static void rotate_cb(GtkAdjustment * adjustment, gpointer data); static void reset_axis_pressed_cb(GtkWidget * widget, gpointer data); static void export_cb(GtkAction * action, gpointer data); static void parameters_cb(GtkAction * action, gpointer data); static void transfer_function_cb(GtkAction * action, gpointer data); #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) static void movie_cb(GtkAction * action, gpointer data); #endif static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void close_cb(GtkAction * action, gpointer data); static void read_render_preferences(gboolean * strip_highs, gboolean * optimize_renderings, gboolean * initially_no_gradient_opacity); static ui_render_t * ui_render_init(GtkWindow * window, GtkWidget *window_vbox, AmitkStudy * study, GList * selected_objects, AmitkPreferences * preferences); static ui_render_t * ui_render_free(ui_render_t * ui_render); /* function called when the canvas is hit */ /* function called when an event occurs on the image canvas, notes: -events for non-new roi's are handled by ui_study_rois_cb_roi_event */ static gboolean canvas_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_render_t * ui_render = data; GnomeCanvas * canvas; AmitkPoint temp_point; AmitkCanvasPoint temp_cpoint1, temp_cpoint2; AmitkCanvasPoint canvas_cpoint, diff_cpoint; GnomeCanvasPoints * line_points; guint i, j,k; rgba_t color; gdouble dim; static AmitkPoint prev_theta; static AmitkPoint theta; static AmitkCanvasPoint initial_cpoint, center_cpoint; static gboolean dragging = FALSE; static GnomeCanvasItem * rotation_box[8]; static AmitkPoint box_point[8]; canvas = GNOME_CANVAS(widget); /* get the location of the event, and convert it to the canvas coordinates */ gnome_canvas_window_to_world(canvas, event->button.x, event->button.y, &canvas_cpoint.x, &canvas_cpoint.y); gnome_canvas_w2c_d(canvas, canvas_cpoint.x, canvas_cpoint.y, &canvas_cpoint.x, &canvas_cpoint.y); dim = MIN(ui_render->pixbuf_width, ui_render->pixbuf_height); temp_point.x = temp_point.y = temp_point.z = -dim/2.0; amitk_space_set_offset(ui_render->box_space, temp_point); // amitk_space_set_axes(ui_render->box_space, base_axes, AMITK_SPACE_OFFSET(ui_render->box_space)); amitk_space_set_axes(ui_render->box_space, base_axes, AMITK_SPACE_OFFSET(ui_render->box_space)); /* switch on the event which called this */ switch (event->type) { case GDK_ENTER_NOTIFY: ui_common_place_cursor(UI_CURSOR_DATA_SET_MODE, GTK_WIDGET(canvas)); break; case GDK_LEAVE_NOTIFY: ui_common_place_cursor(UI_CURSOR_DEFAULT, GTK_WIDGET(canvas)); break; case GDK_BUTTON_PRESS: if ((event->button.button == 1) || (event->button.button == 2)) { dragging = TRUE; initial_cpoint = canvas_cpoint; center_cpoint.x = center_cpoint.y = dim/2.0; prev_theta = zero_point; /* figure out the eight vertices */ for (i=0; i<8; i++) { box_point[i].x = (i & 0x1) ? BOX_OFFSET * dim : (1-BOX_OFFSET) * dim; box_point[i].y = (i & 0x2) ? BOX_OFFSET * dim : (1-BOX_OFFSET) * dim; box_point[i].z = (i & 0x4) ? BOX_OFFSET * dim : (1-BOX_OFFSET) * dim; } /* draw the 8 lines we use to represent out cube */ for (i=0; i<8; i++) { line_points = gnome_canvas_points_new(2); if ((i < 4) && (i & 0x1)){ /* i < 4, evens */ j = (i & 0x2) ? i -2 : i -1; k = (i & 0x2) ? i : i +1; } else if (i < 4) { /* i < 4, odds */ j = i; k = j+1; } else { /* i > 4 */ j = i; k = j-4; } line_points->coords[0] = box_point[j].x; /* x1 */ line_points->coords[1] = box_point[j].y; /* y1 */ line_points->coords[2] = box_point[k].x; /* x2 */ line_points->coords[3] = box_point[k].y; /* y2 */ color = amitk_color_table_outline_color(ui_render->renderings->rendering->color_table, TRUE); rotation_box[i] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(ui_render->canvas)), gnome_canvas_line_get_type(), "points", line_points, "fill_color_rgba", amitk_color_table_rgba_to_uint32(color), "width_units", 1.0, NULL); gnome_canvas_points_unref(line_points); } /* translate the 8 vertices back to the base frame */ for (i=0; i<8; i++) box_point[i] = amitk_space_s2b(ui_render->box_space, box_point[i]); if (event->button.button == 1) gnome_canvas_item_grab(GNOME_CANVAS_ITEM(rotation_box[0]), GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ui_common_cursor[UI_CURSOR_RENDERING_ROTATE_XY], event->button.time); else /* button 2 */ gnome_canvas_item_grab(GNOME_CANVAS_ITEM(rotation_box[0]), GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ui_common_cursor[UI_CURSOR_RENDERING_ROTATE_Z], event->button.time); } break; case GDK_MOTION_NOTIFY: if (dragging && (event->motion.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK))) { if (event->motion.state & GDK_BUTTON1_MASK) { diff_cpoint = canvas_point_sub(initial_cpoint, canvas_cpoint); theta.y = M_PI * diff_cpoint.x / dim; theta.x = M_PI * -diff_cpoint.y / dim; /* rotate the axis */ amitk_space_rotate_on_vector(ui_render->box_space, amitk_space_get_axis(ui_render->box_space, AMITK_AXIS_X), theta.x, zero_point); amitk_space_rotate_on_vector(ui_render->box_space, amitk_space_get_axis(ui_render->box_space, AMITK_AXIS_Y), theta.y, zero_point); renderings_set_rotation(ui_render->renderings, AMITK_AXIS_Y, prev_theta.y); renderings_set_rotation(ui_render->renderings, AMITK_AXIS_X, -prev_theta.x); renderings_set_rotation(ui_render->renderings, AMITK_AXIS_X, theta.x); renderings_set_rotation(ui_render->renderings, AMITK_AXIS_Y, -theta.y); } else {/* button 2 */ temp_cpoint1 = canvas_point_sub(initial_cpoint,center_cpoint); temp_cpoint2 = canvas_point_sub(canvas_cpoint,center_cpoint); /* figure out theta.z */ theta.z = acos(canvas_point_dot_product(temp_cpoint1, temp_cpoint2) / (canvas_point_mag(temp_cpoint1) * canvas_point_mag(temp_cpoint2))); /* correct for the fact that acos is always positive by using the cross product */ if ((temp_cpoint1.x*temp_cpoint2.y-temp_cpoint1.y*temp_cpoint2.x) < 0.0) theta.z = -theta.z; amitk_space_rotate_on_vector(ui_render->box_space, amitk_space_get_axis(ui_render->box_space, AMITK_AXIS_Z), -theta.z, zero_point); renderings_set_rotation(ui_render->renderings, AMITK_AXIS_Z, -prev_theta.z); renderings_set_rotation(ui_render->renderings, AMITK_AXIS_Z, theta.z); } /* recalculate the offset */ temp_point.x = temp_point.y = temp_point.z = -dim/2.0; amitk_space_set_offset(ui_render->box_space, zero_point); amitk_space_set_offset(ui_render->box_space, amitk_space_s2b(ui_render->box_space, temp_point)); /* translate the 8 vertices */ for (i=0; i<8; i++) box_point[i] = amitk_space_b2s(ui_render->box_space, box_point[i]); /* draw the 8 lines we use to represent out cube */ for (i=0; i<8; i++) { line_points = gnome_canvas_points_new(2); if ((i < 4) && (i & 0x1)){ /* i < 4, evens */ j = (i & 0x2) ? i -2 : i -1; k = (i & 0x2) ? i : i +1; } else if (i < 4) { /* i < 4, odds */ j = i; k = j+1; } else { /* i > 4 */ j = i; k = j-4; } line_points->coords[0] = box_point[j].x; /* x1 */ line_points->coords[1] = box_point[j].y; /* y1 */ line_points->coords[2] = box_point[k].x; /* x2 */ line_points->coords[3] = box_point[k].y; /* y2 */ gnome_canvas_item_set(rotation_box[i], "points", line_points, NULL); gnome_canvas_points_unref(line_points); } /* translate the 8 vertices back to the base frame */ for (i=0; i<8; i++) box_point[i] = amitk_space_s2b(ui_render->box_space, box_point[i]); if (ui_render->update_without_release) ui_render_add_update(ui_render); prev_theta = theta; } break; case GDK_BUTTON_RELEASE: if (dragging) { gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(rotation_box[0]), event->button.time); dragging = FALSE; /* get rid of the frame */ for (i=0; i<8; i++) gtk_object_destroy(GTK_OBJECT(rotation_box[i])); /* render now if appropriate*/ if (!ui_render->update_without_release) ui_render_add_update(ui_render); } break; default: break; } return FALSE; } /* function to switch into stereoscopic rendering mode */ static void stereoscopic_cb(GtkRadioAction * action, GtkRadioAction * current, gpointer data) { ui_render_t * ui_render = data; ui_render->stereoscopic = gtk_radio_action_get_current_value((GTK_RADIO_ACTION(current))); ui_render_add_update(ui_render); return; } /* function to change the zoom */ static void change_zoom_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gdouble temp_val; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (temp_val < 0.1) return; if (temp_val > 10) /* 10x zoom seems like quite a bit... */ return; /* set the zoom */ if (!REAL_EQUAL(ui_render->zoom, temp_val)) { ui_render->zoom = temp_val; renderings_set_zoom(ui_render->renderings, ui_render->zoom); /* do updating */ ui_render_add_update(ui_render); } return; } /* function called when one of the rotate widgets has been hit */ static void rotate_cb(GtkAdjustment * adjustment, gpointer data) { ui_render_t * ui_render = data; AmitkAxis i_axis; gdouble rot; /* figure out which rotate widget called me */ i_axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adjustment),"axis")); rot = (adjustment->value/180.0)*M_PI; /* get rotation in radians */ /* update the rotation values */ renderings_set_rotation(ui_render->renderings, i_axis, rot); /* render now if appropriate*/ ui_render_add_update(ui_render); /* return adjustment back to normal */ adjustment->value = 0.0; gtk_adjustment_changed(adjustment); return; } /* function called to snap the axis back to the default */ static void reset_axis_pressed_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; /* reset the rotations */ renderings_reset_rotation(ui_render->renderings); ui_render_add_update(ui_render); return; } /* function to save a rendering as an external data format */ static void export_cb(GtkAction * action, gpointer data) { ui_render_t * ui_render = data; renderings_t * temp_renderings; GtkWidget * file_chooser; gchar * data_set_names = NULL; gchar * filename; static guint save_image_num = 0; GdkPixbuf * pixbuf; g_return_if_fail(ui_render->pixbuf != NULL); file_chooser = gtk_file_chooser_dialog_new(_("Export File"), GTK_WINDOW(ui_render->window), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(ui_render->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ temp_renderings = ui_render->renderings; data_set_names = g_strdup(temp_renderings->rendering->name); temp_renderings = temp_renderings->next; while (temp_renderings != NULL) { filename = g_strdup_printf("%s+%s",data_set_names, temp_renderings->rendering->name); g_free(data_set_names); data_set_names = filename; temp_renderings = temp_renderings->next; } filename = g_strdup_printf("Rendering%s{%s}_%d.jpg", ui_render->stereoscopic ? "_stereo_" : "_", data_set_names,save_image_num++); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (file_chooser), filename); g_free(data_set_names); g_free(filename); /* run the dialog */ if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy (file_chooser); /* save out the image if we have a filename */ if (filename != NULL) { pixbuf = ui_render_get_pixbuf(ui_render); if (pixbuf != NULL) { if (gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", "100", NULL) == FALSE) g_warning(_("Failure Saving File: %s"), filename); g_object_unref(pixbuf); } else { g_warning(_("Canvas failed to return a valid image\n")); } g_free(filename); } return; } /* function called when the button to pop up a rendering parameters modification dialog is hit */ static void parameters_cb(GtkAction * action, gpointer data) { ui_render_t * ui_render = data; ui_render_dialog_create_parameters(ui_render); return; } /* function called when the button to pop up a transfer function dialog is hit */ static void transfer_function_cb(GtkAction * action, gpointer data) { ui_render_t * ui_render = data; ui_render_dialog_create_transfer_function(ui_render); return; } #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) /* function called when the button to pop up a movie generation dialog */ static void movie_cb(GtkAction * action, gpointer data) { ui_render_t * ui_render = data; ui_render->movie = ui_render_movie_dialog_create(ui_render); return; } #endif /* function to run for a delete_event */ static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_render_t * ui_render = data; GtkWindow * window = ui_render->window; ui_render = ui_render_free(ui_render); /* free the associated data structure */ amide_unregister_window((gpointer) window); /* tell amide this window is no longer */ return FALSE; } /* function ran when closing the rendering window */ static void close_cb(GtkAction* widget, gpointer data) { ui_render_t * ui_render = data; GtkWindow * window = ui_render->window; gboolean return_val; /* run the delete event function */ g_signal_emit_by_name(G_OBJECT(window), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(window)); return; } static const GtkActionEntry normal_items[] = { /* Toplevel */ { "FileMenu", NULL, N_("_File") }, { "EditMenu", NULL, N_("_Edit") }, { "HelpMenu", NULL, N_("_Help") }, /* File menu */ { "ExportRendering", NULL, N_("_Export Rendering"), NULL, N_("Export the rendered image"), G_CALLBACK(export_cb)}, #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) { "CreateMovie", NULL, N_("_Create Movie"), NULL, N_("Create a movie out of a sequence of renderings"), G_CALLBACK(movie_cb)}, #endif { "Close", GTK_STOCK_CLOSE, NULL, "W", N_("Close the rendering dialog"), G_CALLBACK (close_cb)}, /* Edit menu */ { "Parameters", NULL, N_("_Rendering Parameters"), NULL, N_("Adjust parameters pertinent to the rendered image"), G_CALLBACK(parameters_cb)}, /* Toolbar items */ { "TransferFunctions", "amide_icon_transfer_function", N_("X-fer"), NULL, N_("Opacity and density transfer functions"), G_CALLBACK(transfer_function_cb)} }; static const GtkRadioActionEntry stereoscopic_radio_entries[] = { { "MonoscopicRendering", "amide_icon_view_mode_single", N_("Mono"), NULL, N_("Monoscopic rendering"), 0}, { "StereoscopicRendering", "amide_icon_view_mode_linked_2way", N_("Stereo"), NULL, N_("Stereoscopic rendering"), 1}, }; static const char *ui_description = "" " " " " " " " " " " " " " " " " " " " " HELP_MENU_UI_DESCRIPTION " " " " " " " " " " " " /* " " */ /* " " */ " " ""; /* function to setup the menus and toolbars for the rendering ui */ static void menus_toolbar_create(ui_render_t * ui_render) { GtkWidget *menubar; GtkWidget *toolbar; GtkActionGroup *action_group; GtkUIManager *ui_manager; GtkAccelGroup *accel_group; GtkWidget * label; GtkWidget * spin_button; GError * error; /* sanity check */ g_assert(ui_render !=NULL); /* create an action group with all the menu actions */ action_group = gtk_action_group_new ("MenuActions"); gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions(action_group, normal_items, G_N_ELEMENTS(normal_items),ui_render); gtk_action_group_add_actions(action_group, ui_common_help_menu_items, G_N_ELEMENTS(ui_common_help_menu_items),ui_render); gtk_action_group_add_radio_actions(action_group, stereoscopic_radio_entries, G_N_ELEMENTS (stereoscopic_radio_entries), 0, G_CALLBACK(stereoscopic_cb), ui_render); /* create the ui manager, and add the actions and accel's */ ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); accel_group = gtk_ui_manager_get_accel_group (ui_manager); gtk_window_add_accel_group (ui_render->window, accel_group); /* create the actual menu/toolbar ui */ error = NULL; if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &error)) { g_warning ("%s: building menus failed in %s: %s", PACKAGE, __FILE__, error->message); g_error_free (error); return; } /* pack in the menu and toolbar */ menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu"); gtk_box_pack_start (GTK_BOX (ui_render->window_vbox), menubar, FALSE, FALSE, 0); toolbar = gtk_ui_manager_get_widget (ui_manager, "/ToolBar"); gtk_box_pack_start (GTK_BOX (ui_render->window_vbox), toolbar, FALSE, FALSE, 0); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); /* a separator for clarity */ ui_common_toolbar_append_separator(toolbar); /* add the zoom widget to our toolbar */ label = gtk_label_new(_("zoom:")); ui_common_toolbar_append_widget(toolbar, label, NULL); spin_button = gtk_spin_button_new_with_range(0.1, 10.0, 0.2); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin_button),FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), ui_render->zoom); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin_button), GTK_UPDATE_ALWAYS); gtk_widget_set_size_request (spin_button, 60, -1); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(change_zoom_cb), ui_render); g_signal_connect(G_OBJECT(spin_button), "button_press_event", G_CALLBACK(amitk_spin_button_discard_double_or_triple_click), NULL); ui_common_toolbar_append_widget(toolbar, spin_button,_("specify how much to magnify the rendering")); return; } /* destroy a ui_render data structure */ static ui_render_t * ui_render_free(ui_render_t * ui_render) { gboolean return_val; if (ui_render == NULL) return ui_render; /* sanity checks */ g_return_val_if_fail(ui_render->reference_count > 0, NULL); ui_render->reference_count--; /* things to do if we've removed all reference's */ if (ui_render->reference_count == 0) { ui_render->renderings = renderings_unref(ui_render->renderings); #ifdef AMIDE_DEBUG g_print("freeing ui_render\n"); #endif if (ui_render->preferences != NULL) { g_object_unref(ui_render->preferences); ui_render->preferences = NULL; } if (ui_render->idle_handler_id != 0) { g_source_remove(ui_render->idle_handler_id); ui_render->idle_handler_id = 0; } if (ui_render->pixbuf != NULL) { g_object_unref(ui_render->pixbuf); ui_render->pixbuf = NULL; } if (ui_render->box_space != NULL) { g_object_unref(ui_render->box_space); ui_render->box_space = NULL; } if (ui_render->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(ui_render->progress_dialog), "delete_event", NULL, &return_val); ui_render->progress_dialog = NULL; } g_free(ui_render); ui_render = NULL; } return ui_render; } static void read_render_preferences(gboolean * strip_highs, gboolean * optimize_renderings, gboolean * initially_no_gradient_opacity) { *strip_highs = amide_gconf_get_bool(GCONF_AMIDE_RENDERING,"StripHighs"); *optimize_renderings = amide_gconf_get_bool(GCONF_AMIDE_RENDERING,"OptimizeRendering"); *initially_no_gradient_opacity = amide_gconf_get_bool(GCONF_AMIDE_RENDERING,"InitiallyNoGradientOpacity"); return; } /* allocate and initialize a ui_render data structure */ static ui_render_t * ui_render_init(GtkWindow * window, GtkWidget * window_vbox, AmitkStudy * study, GList * selected_objects, AmitkPreferences * preferences) { ui_render_t * ui_render; gboolean strip_highs; gboolean optimize_rendering; gboolean initially_no_gradient_opacity; read_render_preferences(&strip_highs, &optimize_rendering, &initially_no_gradient_opacity); /* alloc space for the data structure for passing ui info */ if ((ui_render = g_try_new(ui_render_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for ui_render_t")); return NULL; } ui_render->reference_count = 1; /* set any needed parameters */ ui_render->window = window; ui_render->window_vbox = window_vbox; ui_render->parameter_dialog = NULL; ui_render->transfer_function_dialog = NULL; ui_render->preferences = g_object_ref(preferences); #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) ui_render->movie = NULL; #endif ui_render->stereoscopic = FALSE; ui_render->renderings = NULL; ui_render->pixbuf = NULL; ui_render->pixbuf_width = 128; ui_render->pixbuf_height = 128; ui_render->canvas_image = NULL; ui_render->canvas_time_label = NULL; ui_render->time_label_on = FALSE; ui_render->quality = RENDERING_DEFAULT_QUALITY; ui_render->depth_cueing = RENDERING_DEFAULT_DEPTH_CUEING; ui_render->front_factor = RENDERING_DEFAULT_FRONT_FACTOR; ui_render->density = RENDERING_DEFAULT_DENSITY; ui_render->zoom = RENDERING_DEFAULT_ZOOM; ui_render->start = AMITK_STUDY_VIEW_START_TIME(study); ui_render->duration = AMITK_STUDY_VIEW_DURATION(study); ui_render->fov = AMITK_STUDY_FOV(study); ui_render->view_center = AMITK_STUDY_VIEW_CENTER(study); ui_render->box_space = amitk_space_new(); ui_render->progress_dialog = amitk_progress_dialog_new(ui_render->window); ui_render->disable_progress_dialog=FALSE; ui_render->next_update= UPDATE_NONE; ui_render->idle_handler_id = 0; ui_render->rendered_successfully=FALSE; /* load in saved render preferences */ ui_render->update_without_release = amide_gconf_get_bool(GCONF_AMIDE_RENDERING,"UpdateWithoutRelease"); ui_render->stereo_eye_width = amide_gconf_get_int(GCONF_AMIDE_RENDERING,"EyeWidth"); if (ui_render->stereo_eye_width == 0) /* if no config file, put in sane value */ ui_render->stereo_eye_width = 50*gdk_screen_width()/gdk_screen_width_mm(); /* in pixels */ ui_render->stereo_eye_angle = amide_gconf_get_float(GCONF_AMIDE_RENDERING,"EyeAngle"); if ((ui_render->stereo_eye_angle <= 0.1) || (ui_render->stereo_eye_angle > 45.0)) ui_render->stereo_eye_angle = 5.0; /* degrees */ /* initialize the rendering contexts */ ui_render->renderings = renderings_init(selected_objects, ui_render->start, ui_render->duration, strip_highs, optimize_rendering, initially_no_gradient_opacity, ui_render->fov, ui_render->view_center, ui_render->disable_progress_dialog ? NULL : amitk_progress_dialog_update, ui_render->disable_progress_dialog ? NULL : ui_render->progress_dialog); return ui_render; } GdkPixbuf * ui_render_get_pixbuf(ui_render_t * ui_render) { GdkPixbuf * pixbuf; pixbuf = amitk_get_pixbuf_from_canvas(GNOME_CANVAS(ui_render->canvas), 0.0,0.0, ui_render->pixbuf_width, ui_render->pixbuf_height); return pixbuf; } void ui_render_add_update(ui_render_t * ui_render) { ui_render->next_update = ui_render->next_update | UPDATE_RENDERING; if (ui_render->idle_handler_id == 0) { ui_common_place_cursor_no_wait(UI_CURSOR_WAIT, ui_render->canvas); ui_render->idle_handler_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,ui_render_update_immediate, ui_render, NULL); } return; } /* render our objects and place into the canvases */ gboolean ui_render_update_immediate(gpointer data) { ui_render_t * ui_render = data; amide_intpoint_t size_dim; AmideEye eyes; gboolean return_val=TRUE; amide_time_t midpt_time; gint hours, minutes, seconds; gchar * time_str; rgba_t color; g_return_val_if_fail(ui_render != NULL, FALSE); g_return_val_if_fail(ui_render->renderings != NULL, FALSE); ui_render->rendered_successfully=FALSE; if (!renderings_reload_objects(ui_render->renderings, ui_render->start, ui_render->duration, ui_render->disable_progress_dialog ? NULL : amitk_progress_dialog_update, ui_render->disable_progress_dialog ? NULL : ui_render->progress_dialog )) { return_val=FALSE; goto function_end; } /* -------- render our objects ------------ */ if (ui_render->stereoscopic) eyes = AMIDE_EYE_NUM; else eyes = 1; if (ui_render->pixbuf != NULL) { g_object_unref(ui_render->pixbuf); ui_render->pixbuf = NULL; } /* base the dimensions on the first rendering context in the list.... */ size_dim = ceil(ui_render->zoom*POINT_MAX(ui_render->renderings->rendering->dim)); ui_render->pixbuf = image_from_renderings(ui_render->renderings, size_dim, size_dim, eyes, ui_render->stereo_eye_angle, ui_render->stereo_eye_width); /* put up the image */ if (ui_render->canvas_image != NULL) gnome_canvas_item_set(ui_render->canvas_image, "pixbuf", ui_render->pixbuf, NULL); else /* time to make a new image */ ui_render->canvas_image = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(ui_render->canvas)), gnome_canvas_pixbuf_get_type(), "pixbuf", ui_render->pixbuf, "x", (double) 0.0, "y", (double) 0.0, NULL); /* get the height and width */ ui_render->pixbuf_width = gdk_pixbuf_get_width(ui_render->pixbuf); ui_render->pixbuf_height = gdk_pixbuf_get_height(ui_render->pixbuf); /* put up the timer */ if (ui_render->time_label_on) { midpt_time = ui_render->start+ui_render->duration/2.0; hours = floor(midpt_time/3600); midpt_time -= hours*3600; minutes = floor(midpt_time/60); midpt_time -= minutes*60; seconds = midpt_time; time_str = g_strdup_printf("%d:%.2d:%.2d",hours,minutes,seconds); color = amitk_color_table_outline_color(ui_render->renderings->rendering->color_table, FALSE); if (ui_render->canvas_time_label != NULL) gnome_canvas_item_set(ui_render->canvas_time_label, "text", time_str, "fill_color_rgba", color, NULL); else ui_render->canvas_time_label = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(ui_render->canvas)), gnome_canvas_text_get_type(), "anchor", GTK_ANCHOR_SOUTH_WEST, "text", time_str, "x", 4.0, "y", ui_render->pixbuf_height-2.0, "fill_color_rgba", color, "font_desc", amitk_fixed_font_desc, NULL); g_free(time_str); } else { if (ui_render->canvas_time_label != NULL) { gtk_object_destroy(GTK_OBJECT(ui_render->canvas_time_label)); ui_render->canvas_time_label = NULL; } } /* reset the min size of the widget */ gnome_canvas_set_scroll_region(GNOME_CANVAS(ui_render->canvas), 0.0, 0.0, ui_render->pixbuf_width, ui_render->pixbuf_height); gtk_widget_set_size_request(ui_render->canvas, ui_render->pixbuf_width, ui_render->pixbuf_height); ui_render->rendered_successfully = TRUE; return_val = FALSE; function_end: ui_common_remove_wait_cursor(ui_render->canvas); ui_render->next_update = UPDATE_NONE; ui_render->idle_handler_id=0; return return_val; } /* function that sets up the rendering dialog */ void ui_render_create(AmitkStudy * study, GList * selected_objects, AmitkPreferences * preferences) { GtkWidget * packing_table; GtkWidget * button; GtkAdjustment * adjustment; GtkWidget * scale; GtkWidget * vbox; GtkWidget * hbox; GtkWidget * dial; GtkWidget * label; ui_render_t * ui_render; GtkWindow * window; GtkWidget * window_vbox; gboolean return_val; /* sanity checks */ g_return_if_fail(AMITK_IS_STUDY(study)); /* setup the window with a vbox container in it */ window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_window_set_title(window, _("Rendering Window")); gtk_window_set_resizable(window, FALSE); window_vbox = gtk_vbox_new(FALSE,0); gtk_container_add (GTK_CONTAINER (window), window_vbox); ui_render = ui_render_init(window, window_vbox, study, selected_objects, preferences); /* check we actually have something */ if (ui_render->renderings == NULL) { /* run the delete event function */ g_signal_emit_by_name(G_OBJECT(window), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(window)); return; } /* setup the callbacks for the window */ g_signal_connect(G_OBJECT(ui_render->window), "delete_event", G_CALLBACK(delete_event_cb), ui_render); /* setup the menus and toolbar */ menus_toolbar_create(ui_render); /* make the widgets for this dialog box */ packing_table = gtk_table_new(3,3,FALSE); gtk_box_pack_start (GTK_BOX (ui_render->window_vbox), packing_table, TRUE,TRUE, 0); /* setup the main canvas */ #ifdef AMIDE_LIBGNOMECANVAS_AA ui_render->canvas = gnome_canvas_new_aa(); #else ui_render->canvas = gnome_canvas_new(); #endif gtk_table_attach(GTK_TABLE(packing_table), ui_render->canvas, 1,2,1,2, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(ui_render->canvas), "event", G_CALLBACK(canvas_event_cb), ui_render); ui_render_update_immediate(ui_render); /* fill in the canvas */ /* create the x, y, and z rotation dials */ hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(packing_table), hbox, 1,3,0,1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -90.0, 90.0, 1.0, 1.0, 1.0)); scale = gtk_hscale_new(adjustment); gtk_range_set_update_policy (GTK_RANGE(scale), GTK_UPDATE_DISCONTINUOUS); g_object_set_data(G_OBJECT(adjustment), "axis", GINT_TO_POINTER(AMITK_AXIS_Y)); gtk_box_pack_start(GTK_BOX(hbox), scale, TRUE, TRUE, 0); g_signal_connect (G_OBJECT(adjustment), "value_changed", G_CALLBACK(rotate_cb), ui_render); label = gtk_label_new(_("y")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); /* create the z dial */ hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(packing_table), hbox, 3,4,0,1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); label = gtk_label_new(_("z")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -180.0, 180.0, 1.0, 1.0, 1.0)); dial = amitk_dial_new(adjustment); gtk_widget_set_size_request(dial,50,50); amitk_dial_set_update_policy (AMITK_DIAL(dial), GTK_UPDATE_DISCONTINUOUS); g_object_set_data(G_OBJECT(adjustment), "axis", GINT_TO_POINTER(AMITK_AXIS_Z)); gtk_box_pack_start(GTK_BOX(hbox), dial, FALSE, FALSE, 0); g_signal_connect (G_OBJECT(adjustment), "value_changed", G_CALLBACK(rotate_cb), ui_render); /* the x slider */ vbox = gtk_vbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(packing_table), vbox, 3,4,1,2, X_PACKING_OPTIONS , Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); label = gtk_label_new(_("x")); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -90.0, 90.0, 1.0, 1.0, 1.0)); scale = gtk_vscale_new(adjustment); gtk_range_set_update_policy (GTK_RANGE(scale), GTK_UPDATE_DISCONTINUOUS); g_object_set_data(G_OBJECT(adjustment), "axis", GINT_TO_POINTER(AMITK_AXIS_X)); gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(adjustment), "value_changed", G_CALLBACK(rotate_cb), ui_render); /* button to reset the axis */ button = gtk_button_new_with_label(_("Reset Axis")); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(reset_axis_pressed_cb), ui_render); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); /* and show all our widgets */ gtk_widget_show_all(GTK_WIDGET(ui_render->window)); amide_register_window((gpointer) ui_render->window); return; } static void init_strip_highs_cb(GtkWidget * widget, gpointer data); static void init_optimize_rendering_cb(GtkWidget * widget, gpointer data); static void init_no_gradient_opacity_cb(GtkWidget * widget, gpointer data); static void init_strip_highs_cb(GtkWidget * widget, gpointer data) { amide_gconf_set_bool(GCONF_AMIDE_RENDERING,"StripHighs", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void init_optimize_rendering_cb(GtkWidget * widget, gpointer data) { amide_gconf_set_bool(GCONF_AMIDE_RENDERING,"OptimizeRendering", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } static void init_no_gradient_opacity_cb(GtkWidget * widget, gpointer data) { amide_gconf_set_bool(GCONF_AMIDE_RENDERING,"InitiallyNoGradientOpacity", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); return; } /* function to setup a dialog to allow us to choose options for rendering */ GtkWidget * ui_render_init_dialog_create(AmitkStudy * study, GtkWindow * parent) { GtkWidget * dialog; gchar * temp_string; GtkWidget * table; GtkWidget * check_button; guint table_row; GtkWidget * tree_view; GtkWidget * scrolled; gboolean strip_highs; gboolean optimize_rendering; gboolean initially_no_gradient_opacity; read_render_preferences(&strip_highs, &optimize_rendering, &initially_no_gradient_opacity); temp_string = g_strdup_printf(_("%s: Rendering Initialization Dialog"), PACKAGE); dialog = gtk_dialog_new_with_buttons (temp_string, parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_EXECUTE, AMITK_RESPONSE_EXECUTE, NULL); gtk_window_set_title(GTK_WINDOW(dialog), temp_string); g_free(temp_string); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(ui_common_init_dialog_response_cb), NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); /* start making the widgets for this dialog box */ table = gtk_table_new(5,2,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); tree_view = amitk_tree_view_new(AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION,NULL, NULL); g_object_set_data(G_OBJECT(dialog), "tree_view", tree_view); amitk_tree_view_set_study(AMITK_TREE_VIEW(tree_view), study); amitk_tree_view_expand_object(AMITK_TREE_VIEW(tree_view), AMITK_OBJECT(study)); /* make a scrolled area for the tree */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,250,250); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), tree_view); gtk_table_attach(GTK_TABLE(table), scrolled, 0,2, table_row, table_row+1,GTK_FILL, GTK_FILL | GTK_EXPAND, X_PADDING, Y_PADDING); table_row++; /* do we want to strip values */ check_button = gtk_check_button_new_with_label(_("Set values greater than max. threshold to zero?")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), strip_highs); gtk_table_attach(GTK_TABLE(table), check_button, 0,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(init_strip_highs_cb), dialog); table_row++; /* do we want to converse memory */ check_button = gtk_check_button_new_with_label(_("Accelerate Rendering? Increases memory use ~3x")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),optimize_rendering); gtk_table_attach(GTK_TABLE(table), check_button, 0,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(init_optimize_rendering_cb), dialog); table_row++; /* do we want the initial opacities to be only density dependent */ check_button = gtk_check_button_new_with_label(_("Initial opacity functions only density dependent?")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button),initially_no_gradient_opacity); gtk_table_attach(GTK_TABLE(table), check_button, 0,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(init_no_gradient_opacity_cb), dialog); table_row++; /* and show all our widgets */ gtk_widget_show_all(dialog); return dialog; } #endif amide-1.0.6/amide-current/src/ui_render.h000066400000000000000000000053301423227705100202540ustar00rootroot00000000000000/* ui_render.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBVOLPACK_SUPPORT #ifndef __UI_RENDER_H__ #define __UI_RENDER_H__ /* header files that are always needed with this file */ #include #include "render.h" #include "amitk_study.h" #define GCONF_AMIDE_RENDERING "RENDERING" /* defines */ #define UI_RENDER_BLANK_WIDTH 200 #define UI_RENDER_BLANK_HEIGHT 200 #define BOX_OFFSET 0.2 /* ui_render data structures */ typedef struct ui_render_t { GtkWindow * window; GtkWidget * window_vbox; GtkWidget * parameter_dialog; GtkWidget * transfer_function_dialog; AmitkPreferences * preferences; #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) gpointer movie; /* pointer to type ui_render_movie_t */ #endif amide_time_t start; amide_time_t duration; amide_real_t fov; AmitkPoint view_center; GtkWidget * canvas; GnomeCanvasItem * canvas_image; GnomeCanvasItem * canvas_time_label; gboolean time_label_on; gint pixbuf_width, pixbuf_height; GdkPixbuf * pixbuf; renderings_t * renderings; gboolean update_without_release; gboolean stereoscopic; gdouble stereo_eye_angle; gint stereo_eye_width; /* pixels */ rendering_quality_t quality; gboolean depth_cueing; gdouble front_factor; gdouble density; gdouble zoom; AmitkSpace * box_space; guint next_update; guint idle_handler_id; gboolean rendered_successfully; GtkWidget * progress_dialog; gboolean disable_progress_dialog; guint reference_count; } ui_render_t; /* external functions */ GdkPixbuf * ui_render_get_pixbuf(ui_render_t * ui_render); void ui_render_add_update(ui_render_t * ui_render); gboolean ui_render_update_immediate(gpointer ui_render); void ui_render_create(AmitkStudy * study, GList * selected_objects, AmitkPreferences * preferences); GtkWidget * ui_render_init_dialog_create(AmitkStudy * study, GtkWindow * parent); #endif /* __UI_RENDER_H__ */ #endif /* AMIDE_LIBVOLPACK_SUPPORT */ amide-1.0.6/amide-current/src/ui_render_dialog.c000066400000000000000000000611401423227705100215670ustar00rootroot00000000000000/* ui_render_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBVOLPACK_SUPPORT #include "amide.h" #include "amide_gconf.h" #include "ui_common.h" #include "ui_render_dialog.h" #include "amitk_color_table_menu.h" #define GAMMA_CURVE_WIDTH -1 /* sets automatically */ #define GAMMA_CURVE_HEIGHT 100 static void change_quality_cb(GtkWidget * widget, gpointer data); static void change_pixel_type_cb(GtkWidget * widget, gpointer data); static void change_density_cb(GtkWidget * widget, gpointer data); static void change_eye_angle_cb(GtkWidget * widget, gpointer data); static void change_eye_width_cb(GtkWidget * widget, gpointer data); static void depth_cueing_toggle_cb(GtkWidget * widget, gpointer data); static void change_front_factor_cb(GtkWidget * widget, gpointer data); static void color_table_cb(GtkWidget * widget, gpointer data); static void change_opacity_cb(GtkWidget * widget, gpointer data); static void p_response_cb (GtkDialog * dialog, gint response_id, gpointer data); static void tf_response_cb (GtkDialog * dialog, gint response_id, gpointer data); static gboolean p_delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static gboolean tf_delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void setup_curve(GtkWidget * gamma_curve, gpointer data, classification_t type); /* function to change the rendering quality */ static void change_quality_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; rendering_quality_t new_quality; new_quality = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if (ui_render->quality != new_quality) { ui_render->quality = new_quality; /* apply the new quality */ renderings_set_quality(ui_render->renderings, ui_render->quality); /* do updating */ ui_render_add_update(ui_render); } return; } /* function to change the return pixel type */ static void change_pixel_type_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render; rendering_t * rendering = data; pixel_type_t new_type; ui_render = g_object_get_data(G_OBJECT(widget), "ui_render"); new_type = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if (rendering->pixel_type != new_type) { rendering->pixel_type = new_type; /* apply the new quality */ rendering_set_image(rendering, rendering->pixel_type, ui_render->zoom); /* do updating */ ui_render_add_update(ui_render); } return; } /* function to switch between click & drag versus click, drag, release */ static void update_without_release_toggle_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gboolean update_without_release; update_without_release = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if (ui_render->update_without_release != update_without_release) { ui_render->update_without_release = update_without_release; /* save user preferences */ amide_gconf_set_bool(GCONF_AMIDE_RENDERING,"UpdateWithoutRelease", ui_render->update_without_release); } return; } /* function to change the stereo eye angle */ static void change_eye_angle_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gdouble temp_val; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (temp_val > 90) /* 90 degrees seems like quite a bit... */ return; if (!REAL_EQUAL(ui_render->stereo_eye_angle, temp_val)) { ui_render->stereo_eye_angle = temp_val; /* save user preferences */ amide_gconf_set_float(GCONF_AMIDE_RENDERING,"EyeAngle", ui_render->stereo_eye_angle); /* do updating */ ui_render_add_update(ui_render); } return; } /* function to change the distance between stereo image pairs */ static void change_eye_width_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gdouble temp_val; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); temp_val = temp_val*gdk_screen_width()/gdk_screen_width_mm(); if (temp_val < 0) /* weird mutants? */ return; if (temp_val > 1000) /* just plain wrong? */ return; if (!REAL_EQUAL(ui_render->stereo_eye_width, temp_val)) { ui_render->stereo_eye_width = temp_val; /* save user preferences */ amide_gconf_set_int(GCONF_AMIDE_RENDERING,"EyeWidth", ui_render->stereo_eye_width); /* do updating */ ui_render_add_update(ui_render); } return; } /* function to enable/disable depth cueing */ static void depth_cueing_toggle_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gboolean depth_cueing; depth_cueing = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if (ui_render->depth_cueing != depth_cueing) { ui_render->depth_cueing = depth_cueing; /* apply the new quality */ renderings_set_depth_cueing(ui_render->renderings, ui_render->depth_cueing); ui_render_add_update(ui_render); } return; } /* function to change the front factor on depth cueing */ static void change_front_factor_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gdouble temp_val; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (!REAL_EQUAL(ui_render->front_factor, temp_val)) { /* set the front factor */ ui_render->front_factor = temp_val; renderings_set_depth_cueing_parameters(ui_render->renderings, ui_render->front_factor, ui_render->density); ui_render_add_update(ui_render); } return; } /* function to change the density parameter on depth cueing */ static void change_density_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render = data; gdouble temp_val; temp_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); if (!REAL_EQUAL(ui_render->density, temp_val)) { ui_render->density = temp_val; /* set the density */ renderings_set_depth_cueing_parameters(ui_render->renderings, ui_render->front_factor, ui_render->density); ui_render_add_update(ui_render); } return; } /* changing the color table of a rendering context */ static void color_table_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render ; rendering_t * rendering = data; AmitkColorTable i_color_table; ui_render = g_object_get_data(G_OBJECT(widget), "ui_render"); i_color_table = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); if (rendering->color_table != i_color_table) { /* set the color table */ rendering->color_table = i_color_table; ui_render_add_update(ui_render); } return; } /* function called to change the opacity density or gradient for classification */ static void change_opacity_cb(GtkWidget * widget, gpointer data) { ui_render_t * ui_render; GtkWidget * gamma_curve[2]; gint i; guint num_points; rendering_t * rendering=data; curve_type_t curve_type; classification_t i_classification; g_return_if_fail(rendering!=NULL); /* get some pointers */ gamma_curve[DENSITY_CLASSIFICATION] = g_object_get_data(G_OBJECT(widget), "gamma_curve_density"); gamma_curve[GRADIENT_CLASSIFICATION] = g_object_get_data(G_OBJECT(widget), "gamma_curve_gradient"); ui_render = g_object_get_data(G_OBJECT(widget), "ui_render"); for (i_classification = 0; i_classification < NUM_CLASSIFICATIONS; i_classification++) { /* figure out the curve type */ switch (GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve)->curve_type) { case GTK_CURVE_TYPE_SPLINE: curve_type = CURVE_SPLINE; num_points = GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve)->num_ctlpoints; break; case GTK_CURVE_TYPE_LINEAR: default: curve_type = CURVE_LINEAR; num_points = GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve)->num_ctlpoints; break; } /* set the ramp table to what's in the curve widget */ gtk_curve_get_vector(GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve), (i_classification == DENSITY_CLASSIFICATION) ? RENDERING_DENSITY_MAX:RENDERING_GRADIENT_MAX, (i_classification == DENSITY_CLASSIFICATION) ? rendering->density_ramp : rendering->gradient_ramp); /* store the control points on the widget for later use */ g_free(rendering->ramp_x[i_classification]); /* free the old stuff */ g_free(rendering->ramp_y[i_classification]); /* free the old stuff */ rendering->num_points[i_classification] = num_points; rendering->curve_type[i_classification] = curve_type; /* allocate some new memory */ if ((rendering->ramp_x[i_classification] = g_try_new(gint,rendering->num_points[i_classification])) == NULL) { g_warning(_("couldn't allocate memory space for ramp x")); return; } if ((rendering->ramp_y[i_classification] = g_try_new(gfloat,rendering->num_points[i_classification])) == NULL) { g_warning(_("couldn't allocate memory space for ramp y")); return; } /* copy the new ctrl points */ for (i=0;inum_points[i_classification];i++) { rendering->ramp_x[i_classification][i] = GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve)->ctlpoint[i][0]; rendering->ramp_y[i_classification][i] = GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve)->ctlpoint[i][1]; } rendering->need_reclassify = TRUE; rendering->need_rerender = TRUE; } ui_render_add_update(ui_render); return; } static void p_response_cb (GtkDialog * dialog, gint response_id, gpointer data) { gint return_val; switch(response_id) { case GTK_RESPONSE_HELP: amide_call_help("rendering-dialog"); break; case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } static void tf_response_cb (GtkDialog * dialog, gint response_id, gpointer data) { gint return_val; switch(response_id) { case GTK_RESPONSE_HELP: amide_call_help("transfer-function-dialog"); break; case GTK_RESPONSE_CLOSE: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; default: break; } return; } static gboolean p_delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_render_t * ui_render = data; ui_render->parameter_dialog = NULL; return FALSE; } static gboolean tf_delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_render_t * ui_render = data; ui_render->transfer_function_dialog = NULL; return FALSE; } /* function to set what's in the density or gradient opacity curves when it gets realized */ static void setup_curve(GtkWidget * gamma_curve, gpointer data, classification_t type) { GtkWidget * curve; rendering_t * rendering = data; gfloat (*curve_ctrl_points)[2]; guint i; curve = GTK_GAMMA_CURVE(gamma_curve)->curve; /* allocate some memory for the curve we're passing to the curve widget */ if ((curve_ctrl_points = g_try_malloc(rendering->num_points[type]*sizeof(gfloat)*2)) == NULL) { g_warning(_("Failed to Allocate Memory for Ramp")); return; } /* copy rampx and rampy into the curve array */ for (i=0; i< rendering->num_points[type]; i++) { curve_ctrl_points[i][0]=rendering->ramp_x[type][i]; curve_ctrl_points[i][1]=rendering->ramp_y[type][i]; } GTK_CURVE(curve)->num_ctlpoints = rendering->num_points[type]; g_free(GTK_CURVE(curve)->ctlpoint); GTK_CURVE(curve)->ctlpoint = curve_ctrl_points; /* doing some hackish stuff to get this to work as I'd like it (i.e. saving state) */ switch (rendering->curve_type[type]) { case CURVE_SPLINE: GTK_CURVE(curve)->curve_type = GTK_CURVE_TYPE_SPLINE; GTK_TOGGLE_BUTTON(GTK_GAMMA_CURVE(gamma_curve)->button[0])->active=TRUE; break; case CURVE_LINEAR: default: GTK_CURVE(curve)->curve_type = GTK_CURVE_TYPE_LINEAR; GTK_TOGGLE_BUTTON(GTK_GAMMA_CURVE(gamma_curve)->button[1])->active=TRUE; break; } return; } /* function that sets up the rendering options dialog */ void ui_render_dialog_create_parameters(ui_render_t * ui_render) { GtkWidget * dialog; gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * label; GtkWidget * menu; GtkWidget * check_button; GtkWidget * spin_button; GtkWidget * hseparator; rendering_quality_t i_quality; guint table_row = 0; if (ui_render->parameter_dialog != NULL) return; temp_string = g_strdup_printf(_("%s: Rendering Parameters Dialog"),PACKAGE); dialog = gtk_dialog_new_with_buttons (temp_string, ui_render->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_free(temp_string); ui_render->parameter_dialog = dialog; /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(p_response_cb), ui_render); g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(p_delete_event_cb), ui_render); /* start making the widgets for this dialog box */ packing_table = gtk_table_new(4,2,FALSE); table_row=0; gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), packing_table); /* widgets to change the quality versus speed of rendering */ label = gtk_label_new(_("Speed versus Quality")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_quality=0; i_qualityquality); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(change_quality_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), menu, 1,2, table_row,table_row+1, GTK_EXPAND | GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* allow rendering to be click and drag */ check_button = gtk_check_button_new_with_label (_("update without button release")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), ui_render->update_without_release); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(update_without_release_toggle_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), check_button, 0,2, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,0,2, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* widget for the stereo eye angle */ label = gtk_label_new(_("Stereo Angle")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(-90.0, 90.0, 0.2); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), ui_render->stereo_eye_angle); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(change_eye_angle_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* widget for the stereo eye width */ label = gtk_label_new(_("Eye Width (mm)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), gdk_screen_width_mm()*ui_render->stereo_eye_width/ ((gdouble) gdk_screen_width())); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(change_eye_width_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,0,2, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* the depth cueing enabling button */ check_button = gtk_check_button_new_with_label (_("enable/disable depth cueing")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_button), ui_render->depth_cueing); g_signal_connect(G_OBJECT(check_button), "toggled", G_CALLBACK(depth_cueing_toggle_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), check_button, 0,2, table_row,table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Front Factor")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 0.2); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), ui_render->front_factor); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(change_front_factor_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("Density")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); spin_button = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 0.2); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin_button), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button), ui_render->density); g_signal_connect(G_OBJECT(spin_button), "value_changed", G_CALLBACK(change_density_cb), ui_render); gtk_table_attach(GTK_TABLE(packing_table), spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* and show all our widgets */ gtk_widget_show_all(dialog); return; } /* function that sets up the rendering options dialog */ void ui_render_dialog_create_transfer_function(ui_render_t * ui_render) { GtkWidget * dialog; gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * label; GtkWidget * menu; GtkWidget * gamma_curve[2]; GtkWidget * button; GtkWidget * notebook; classification_t i_classification; GtkWidget * hseparator; pixel_type_t i_pixel_type; guint table_row = 0; renderings_t * temp_list; if (ui_render->transfer_function_dialog != NULL) return; temp_string = g_strdup_printf(_("%s: Transfer Function Dialog"),PACKAGE); dialog = gtk_dialog_new_with_buttons (temp_string, ui_render->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_free(temp_string); ui_render->transfer_function_dialog = dialog; /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(tf_response_cb), ui_render); g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(tf_delete_event_cb), ui_render); notebook = gtk_notebook_new(); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), notebook); temp_list = ui_render->renderings; while (temp_list != NULL) { packing_table = gtk_table_new(4,3,FALSE); table_row=0; label = gtk_label_new(temp_list->rendering->name); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), packing_table, label); /* widgets to change the returned pixel type of the rendering */ label = gtk_label_new(_("Return Type")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); menu = gtk_combo_box_new_text(); for (i_pixel_type=0; i_pixel_typerendering->pixel_type); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(change_pixel_type_cb), temp_list->rendering); gtk_table_attach(GTK_TABLE(packing_table), menu, 1,2, table_row,table_row+1, GTK_EXPAND | GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* color table selector */ label = gtk_label_new(_("color table:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(label); menu = amitk_color_table_menu_new(); g_object_set_data(G_OBJECT(menu), "ui_render", ui_render); gtk_table_attach(GTK_TABLE(packing_table), menu, 1,2, table_row,table_row+1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_combo_box_set_active(GTK_COMBO_BOX(menu),temp_list->rendering->color_table); g_signal_connect(G_OBJECT(menu), "changed", G_CALLBACK(color_table_cb), temp_list->rendering); gtk_widget_show(menu); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator,0,2, table_row, table_row+1, GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* widgets for changing the density and gradient classification parameters */ for (i_classification = 0; i_classification < NUM_CLASSIFICATIONS; i_classification++) { if (i_classification == DENSITY_CLASSIFICATION) label = gtk_label_new(_("Density\nDependent\nOpacity")); else /* gradient classification*/ label = gtk_label_new(_("Gradient\nDependent\nOpacity")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); gamma_curve[i_classification] = gtk_gamma_curve_new(); gtk_widget_set_size_request(gamma_curve[i_classification], GAMMA_CURVE_WIDTH, GAMMA_CURVE_HEIGHT); gtk_curve_set_range(GTK_CURVE(GTK_GAMMA_CURVE(gamma_curve[i_classification])->curve), 0.0, (i_classification == DENSITY_CLASSIFICATION) ? RENDERING_DENSITY_MAX: RENDERING_GRADIENT_MAX, 0.0, 1.0); setup_curve(gamma_curve[i_classification], temp_list->rendering, i_classification); /* disable the gamma button and free drawing button */ gtk_widget_destroy(GTK_GAMMA_CURVE(gamma_curve[i_classification])->button[3]); gtk_widget_destroy(GTK_GAMMA_CURVE(gamma_curve[i_classification])->button[2]); /* and attach */ gtk_table_attach(GTK_TABLE(packing_table), gamma_curve[i_classification], 1,3, table_row, table_row+1, GTK_EXPAND | GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); table_row++; } /* GTK no longer has a way to detect automatically when the GtkCurve has been changed, user will now have to explicitly change */ button = gtk_button_new_with_label(_("Apply Curve Changes")); g_object_set_data(G_OBJECT(button), "gamma_curve_density", gamma_curve[DENSITY_CLASSIFICATION]); g_object_set_data(G_OBJECT(button), "gamma_curve_gradient", gamma_curve[GRADIENT_CLASSIFICATION]); g_object_set_data(G_OBJECT(button), "ui_render", ui_render); /* and attach */ gtk_table_attach(GTK_TABLE(packing_table), button, 1,3, table_row, table_row+1, GTK_EXPAND | GTK_FILL, GTK_FILL, X_PADDING, Y_PADDING); gtk_widget_show(button); table_row++; g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(change_opacity_cb), temp_list->rendering); temp_list=temp_list->next; } /* and show all our widgets */ gtk_widget_show_all(dialog); return; } #endif amide-1.0.6/amide-current/src/ui_render_dialog.h000066400000000000000000000022161423227705100215730ustar00rootroot00000000000000/* ui_render_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBVOLPACK_SUPPORT /* header files that are always needed with this file */ #include "ui_render.h" /* external functions */ void ui_render_dialog_create_parameters(ui_render_t * ui_render); void ui_render_dialog_create_transfer_function(ui_render_t * ui_render); #endif amide-1.0.6/amide-current/src/ui_render_movie.c000066400000000000000000001001631423227705100214460ustar00rootroot00000000000000/* ui_render_movie_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #ifdef AMIDE_LIBVOLPACK_SUPPORT #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) #include "amide.h" #include #include #include "ui_common.h" #include "ui_render_movie.h" #include "amitk_type_builtins.h" #include "amitk_progress_dialog.h" #include "mpeg_encode.h" #define MOVIE_DEFAULT_DURATION 10.0 typedef enum { NOT_DYNAMIC, OVER_TIME, OVER_FRAMES, OVER_FRAMES_SMOOTHED, OVER_GATES, DYNAMIC_TYPES } dynamic_t; /* data structures */ typedef struct ui_render_movie_t { ui_render_t * ui_render; /* a pointer back to the main rendering ui */ amide_time_t start_time; amide_time_t end_time; amide_time_t duration; /* movie duration */ guint start_frame; guint end_frame; gdouble rotation[AMITK_AXIS_NUM]; dynamic_t type; gboolean in_generation; gboolean quit_generation; GtkWidget * dialog; GtkWidget * progress_dialog; GtkWidget * start_time_label; GtkWidget * end_time_label; GtkWidget * start_frame_label; GtkWidget * end_frame_label; GtkWidget * start_time_spin_button; GtkWidget * end_time_spin_button; GtkWidget * start_frame_spin_button; GtkWidget * end_frame_spin_button; GtkWidget * duration_spin_button; GtkWidget * time_on_image_label; GtkWidget * time_on_image_button; GtkWidget * dynamic_type; GtkWidget * axis_spin_button[AMITK_AXIS_NUM]; guint reference_count; } ui_render_movie_t; static void change_frames_cb(GtkWidget * widget, gpointer data); static void change_rotation_cb(GtkWidget * widget, gpointer data); static void dynamic_type_cb(GtkWidget * widget, gpointer data); static void change_start_time_cb(GtkWidget * widget, gpointer data); static void change_start_frame_cb(GtkWidget * widget, gpointer data); static void change_end_time_cb(GtkWidget * widget, gpointer data); static void change_end_frame_cb(GtkWidget * widget, gpointer data); static void time_label_on_cb(GtkWidget * widget, gpointer data); static void response_cb (GtkDialog * dialog, gint response_id, gpointer data); static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void dialog_set_sensitive(ui_render_movie_t * ui_render_movie, gboolean sensitive); static ui_render_movie_t * movie_unref(ui_render_movie_t * ui_render_movie); static ui_render_movie_t * movie_init(void); static void movie_generate(ui_render_movie_t * ui_render_movie, char * output_file_name); /* function to change the number of frames in the movie */ static void change_frames_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; ui_render_movie->duration = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } /* function to change the number of rotations on an axis */ static void change_rotation_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; AmitkAxis i_axis; /* figure out which axis this is for */ i_axis = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_entry")); /* set the rotation */ ui_render_movie->rotation[i_axis] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static void dynamic_type_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; dynamic_t type; type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "dynamic_type")); if (type != ui_render_movie->type) { ui_render_movie->type = type; if (type == OVER_TIME) { gtk_widget_show(ui_render_movie->start_time_label); gtk_widget_show(ui_render_movie->start_time_spin_button); gtk_widget_show(ui_render_movie->end_time_label); gtk_widget_show(ui_render_movie->end_time_spin_button); } if ((type == OVER_FRAMES) || (type == OVER_FRAMES_SMOOTHED)) { gtk_widget_show(ui_render_movie->start_frame_label); gtk_widget_show(ui_render_movie->start_frame_spin_button); gtk_widget_show(ui_render_movie->end_frame_label); gtk_widget_show(ui_render_movie->end_frame_spin_button); } if ((type == NOT_DYNAMIC) || (type == OVER_GATES)) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui_render_movie->time_on_image_button), FALSE); gtk_widget_hide(ui_render_movie->time_on_image_label); gtk_widget_hide(ui_render_movie->time_on_image_button); } else { gtk_widget_show(ui_render_movie->time_on_image_label); gtk_widget_show(ui_render_movie->time_on_image_button); } if ((type != OVER_FRAMES) && (type != OVER_FRAMES_SMOOTHED)) { gtk_widget_hide(ui_render_movie->start_frame_label); gtk_widget_hide(ui_render_movie->start_frame_spin_button); gtk_widget_hide(ui_render_movie->end_frame_label); gtk_widget_hide(ui_render_movie->end_frame_spin_button); } if (type != OVER_TIME) { gtk_widget_hide(ui_render_movie->start_time_label); gtk_widget_hide(ui_render_movie->start_time_spin_button); gtk_widget_hide(ui_render_movie->end_time_label); gtk_widget_hide(ui_render_movie->end_time_spin_button); } } return; } /* function to change the start time */ static void change_start_time_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; ui_render_movie->start_time = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } /* function to change the start frame */ static void change_start_frame_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; gint temp_val; temp_val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); if (temp_val >= 0) ui_render_movie->start_frame = temp_val; return; } /* function to change the end time */ static void change_end_time_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; ui_render_movie->end_time = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } /* function to change the end frame */ static void change_end_frame_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; ui_render_movie->end_frame = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); return; } static void time_label_on_cb(GtkWidget * widget, gpointer data) { ui_render_movie_t * ui_render_movie = data; ui_render_movie->ui_render->time_label_on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); return; } /* function called when we hit the apply button */ static void response_cb (GtkDialog * dialog, gint response_id, gpointer data) { ui_render_movie_t * ui_render_movie = data; renderings_t * temp_renderings; GtkWidget * file_chooser; gchar * filename; gchar * data_set_names = NULL; static guint save_image_num = 0; gboolean return_val; switch(response_id) { case AMITK_RESPONSE_EXECUTE: /* the rest of this function runs the file selection dialog box */ file_chooser = gtk_file_chooser_dialog_new(_("Output MPEG As"), GTK_WINDOW(dialog), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(ui_render_movie->ui_render->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ temp_renderings = ui_render_movie->ui_render->renderings; data_set_names = g_strdup(temp_renderings->rendering->name); temp_renderings = temp_renderings->next; while (temp_renderings != NULL) { filename = g_strdup_printf("%s+%s",data_set_names, temp_renderings->rendering->name); g_free(data_set_names); data_set_names = filename; temp_renderings = temp_renderings->next; } filename = g_strdup_printf("Rendering%s%s_%d.mpg", ui_render_movie->ui_render->stereoscopic ? "_stereo_" : "_", data_set_names,save_image_num++); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (file_chooser), filename); g_free(filename); /* run the dialog */ if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy (file_chooser); if (filename == NULL) return; /* return to movie generate dialog */ else { /* generate the movie */ movie_generate(ui_render_movie, filename); g_free(filename); } /* and fall through to close out the dialog */ case GTK_RESPONSE_CANCEL: g_signal_emit_by_name(G_OBJECT(dialog), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(dialog)); break; case GTK_RESPONSE_HELP: amide_call_help("rendering-movie-dialog"); break; default: break; } return; } /* function called to destroy the dialog */ static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_render_movie_t * ui_render_movie = data; ui_render_t * ui_render = ui_render_movie->ui_render; /* trying to close while we're generating */ if (ui_render_movie->in_generation) { ui_render_movie->quit_generation=TRUE; /* signal we need to exit rendering */ return TRUE; } /* trash collection */ /* also informs the ui_render widget that the movie widget is gone */ ui_render->movie = movie_unref(ui_render->movie); return FALSE; } static void dialog_set_sensitive(ui_render_movie_t * ui_render_movie, gboolean sensitive) { AmitkAxis i_axis; gtk_widget_set_sensitive(ui_render_movie->duration_spin_button, sensitive); for (i_axis=0; i_axisaxis_spin_button[i_axis], sensitive); gtk_widget_set_sensitive(ui_render_movie->start_time_spin_button, sensitive); gtk_widget_set_sensitive(ui_render_movie->end_time_spin_button, sensitive); gtk_widget_set_sensitive(ui_render_movie->start_frame_spin_button, sensitive); gtk_widget_set_sensitive(ui_render_movie->end_frame_spin_button, sensitive); gtk_widget_set_sensitive(ui_render_movie->dynamic_type, sensitive); gtk_dialog_set_response_sensitive(GTK_DIALOG(ui_render_movie->dialog), AMITK_RESPONSE_EXECUTE, sensitive); } /* destroy a ui_render_movie data structure */ static ui_render_movie_t * movie_unref(ui_render_movie_t * ui_render_movie) { gboolean return_val; if (ui_render_movie == NULL) return ui_render_movie; /* sanity checks */ g_return_val_if_fail(ui_render_movie->reference_count > 0, NULL); ui_render_movie->reference_count--; /* things we do if we've removed all references */ if (ui_render_movie->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing ui_render_movie\n"); #endif if (ui_render_movie->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(ui_render_movie->progress_dialog), "delete_event", NULL, &return_val); ui_render_movie->progress_dialog = NULL; } ui_render_movie->ui_render->time_label_on=FALSE; g_free(ui_render_movie); ui_render_movie = NULL; } return ui_render_movie; } /* allocate and initialize a ui_render_movie data structure */ static ui_render_movie_t * movie_init(void) { ui_render_movie_t * ui_render_movie; /* alloc space for the data structure */ if ((ui_render_movie = g_try_new(ui_render_movie_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for ui_render_movie_t")); return NULL; } ui_render_movie->reference_count = 1; ui_render_movie->duration = MOVIE_DEFAULT_DURATION; ui_render_movie->rotation[AMITK_AXIS_X] = 0; ui_render_movie->rotation[AMITK_AXIS_Y] = 1; ui_render_movie->rotation[AMITK_AXIS_Z] = 0; ui_render_movie->type = NOT_DYNAMIC; ui_render_movie->ui_render = NULL; ui_render_movie->start_time = 0.0; ui_render_movie->end_time = 1.0; ui_render_movie->start_frame = 0; ui_render_movie->end_frame = 0; ui_render_movie->in_generation=FALSE; ui_render_movie->quit_generation=FALSE; ui_render_movie->progress_dialog = NULL; return ui_render_movie; } /* perform the movie generation */ static void movie_generate(ui_render_movie_t * ui_render_movie, gchar * output_filename) { guint i_frame; gdouble rotation_step[AMITK_AXIS_NUM]; AmitkAxis i_axis; gint return_val = TRUE; amide_time_t initial_start, initial_duration; amide_time_t start_time, duration; ui_render_t * ui_render; AmitkDataSet * most_frames_ds=NULL; renderings_t * renderings; guint ds_frame=0; gdouble ds_frame_real; guint num_frames; gpointer mpeg_encode_context; gboolean continue_work=TRUE; gint ds_gate; GdkPixbuf * pixbuf; /* gray out anything that could screw up the movie */ dialog_set_sensitive(ui_render_movie, FALSE); ui_render_movie->in_generation=TRUE; /* indicate we're generating */ /* save the initial times so we can set it back later */ ui_render = ui_render_movie->ui_render; initial_start = ui_render->start; initial_duration = ui_render->duration; /* disable the normal rendering progress dialog */ ui_render->disable_progress_dialog = TRUE; /* figure out which data set has the most frames, need this if we're doing a movie over frames */ renderings = ui_render->renderings; while (renderings != NULL) { if (AMITK_IS_DATA_SET(renderings->rendering->object)) { if (most_frames_ds == NULL) most_frames_ds = AMITK_DATA_SET(renderings->rendering->object); else if (AMITK_DATA_SET_NUM_FRAMES(most_frames_ds) < AMITK_DATA_SET_NUM_FRAMES(renderings->rendering->object)) most_frames_ds = AMITK_DATA_SET(renderings->rendering->object); } renderings = renderings->next; } num_frames = ceil(ui_render_movie->duration*FRAMES_PER_SECOND); /* figure out each frame's duration, needed if we're doing a movie over time */ if ((ui_render_movie->type == OVER_FRAMES) || (ui_render_movie->type == OVER_FRAMES_SMOOTHED) || (ui_render_movie->type == OVER_TIME)) { ui_render->duration = (ui_render_movie->end_time-ui_render_movie->start_time) /((amide_time_t) num_frames); } mpeg_encode_context = mpeg_encode_setup(output_filename, ENCODE_MPEG1, ui_render->pixbuf_width, ui_render->pixbuf_height); g_return_if_fail(mpeg_encode_context != NULL); /* start generating the frames, continue while we haven't hit cancel */ for (i_frame = 0; ((i_frame < num_frames) && !ui_render_movie->quit_generation && return_val && continue_work); i_frame++) { /* update the progress bar */ continue_work = amitk_progress_dialog_set_fraction(AMITK_PROGRESS_DIALOG(ui_render_movie->progress_dialog), (gdouble) i_frame/((gdouble) num_frames)); /* figure out the rotation for this frame */ for (i_axis = 0; i_axis < AMITK_AXIS_NUM ; i_axis++) { rotation_step[i_axis] = (((gdouble) i_frame)*2.0*M_PI*ui_render_movie->rotation[i_axis]) / num_frames; renderings_set_rotation(ui_render->renderings, i_axis, rotation_step[i_axis]); } /* figure out the start interval for this frame */ switch (ui_render_movie->type) { case OVER_TIME: ui_render->start = ui_render_movie->start_time + i_frame*ui_render->duration; break; case OVER_FRAMES_SMOOTHED: case OVER_FRAMES: if (most_frames_ds) { ds_frame_real = (i_frame/((gdouble) num_frames)) * AMITK_DATA_SET_NUM_FRAMES(most_frames_ds); ds_frame = floor(ds_frame_real); start_time = amitk_data_set_get_start_time(most_frames_ds, ds_frame); duration = amitk_data_set_get_end_time(most_frames_ds, ds_frame) - start_time; ui_render->start = start_time + EPSILON*fabs(start_time) + ((ui_render_movie->type == OVER_FRAMES_SMOOTHED) ? ((ds_frame_real-ds_frame)*duration) : 0.0); ui_render->duration = duration - EPSILON*fabs(duration); } else { /* just have roi's.... doesn't make much sense if we get here */ ui_render->start = 0.0; ui_render->duration = 1.0; } break; case OVER_GATES: renderings = ui_render->renderings; while (renderings != NULL) { if (AMITK_IS_DATA_SET(renderings->rendering->object)) { ds_gate = floor((i_frame/((gdouble) num_frames))*AMITK_DATA_SET_NUM_GATES(renderings->rendering->object)); amitk_data_set_set_view_start_gate(AMITK_DATA_SET(renderings->rendering->object), ds_gate); amitk_data_set_set_view_end_gate(AMITK_DATA_SET(renderings->rendering->object), ds_gate); } renderings = renderings->next; } break; default: /* NOT_DYNAMIC */ break; } /* render the contexts */ ui_render_update_immediate(ui_render); if (ui_render->rendered_successfully) {/* if we rendered correct, encode the mpeg frame */ pixbuf = ui_render_get_pixbuf(ui_render); if (pixbuf == NULL) { g_warning(_("Canvas failed to return a valid image\n")); break; } return_val = mpeg_encode_frame(mpeg_encode_context, pixbuf); g_object_unref(pixbuf); } else return_val = FALSE; /* do any events pending, this allows the canvas to get displayed */ while (gtk_events_pending()) gtk_main_iteration(); /* and unrotate the rendering contexts so that we can properly rerotate for the next frame */ for (i_axis = AMITK_AXIS_NUM; i_axis > 0 ; i_axis--) { renderings_set_rotation(ui_render->renderings, i_axis-1, -rotation_step[i_axis-1]); } } mpeg_encode_close(mpeg_encode_context); amitk_progress_dialog_set_fraction(AMITK_PROGRESS_DIALOG(ui_render_movie->progress_dialog),2.0); /* and rerender one last time to back to the initial rotation and time */ ui_render->start = initial_start; ui_render->duration = initial_duration; ui_render->disable_progress_dialog = FALSE; ui_render_add_update(ui_render); ui_render_movie->in_generation = FALSE; /* done generating */ ui_render_movie->quit_generation = FALSE; dialog_set_sensitive(ui_render_movie, TRUE); /* let user change stuff again */ return; } /* function that sets up the rendering options dialog */ gpointer * ui_render_movie_dialog_create(ui_render_t * ui_render) { ui_render_movie_t * ui_render_movie; gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * hseparator; GtkWidget * label; GtkWidget * radio_button1; GtkWidget * radio_button2; GtkWidget * radio_button3; GtkWidget * radio_button4; GtkWidget * radio_button5; GtkWidget * hbox; guint table_row = 0; AmitkAxis i_axis; renderings_t * renderings; AmitkDataSet * temp_ds; gboolean valid; gint temp_end_frame; amide_time_t temp_end_time; amide_time_t temp_start_time; if (ui_render->movie != NULL) return ui_render->movie; ui_render_movie = movie_init(); ui_render->movie = ui_render_movie; ui_render_movie->ui_render = ui_render; ui_render_movie->start_frame = 0; /* try to get reasonable default values */ renderings = ui_render->renderings; valid = FALSE; while (renderings != NULL) { if (AMITK_IS_DATA_SET(renderings->rendering->object)) { temp_ds = AMITK_DATA_SET(renderings->rendering->object); temp_end_frame = AMITK_DATA_SET_NUM_FRAMES(temp_ds)-1; temp_start_time = amitk_data_set_get_start_time(temp_ds,0); temp_end_time = amitk_data_set_get_end_time(temp_ds, temp_end_frame); if (!valid) { ui_render_movie->end_frame = temp_end_frame; ui_render_movie->start_time = temp_start_time; ui_render_movie->end_time = temp_end_time; } else { if (temp_end_frame > ui_render_movie->end_frame) ui_render_movie->end_frame = temp_end_frame; if (temp_start_time < ui_render_movie->start_time) ui_render_movie->start_time = temp_start_time; if (temp_end_time > ui_render_movie->end_time) ui_render_movie->end_time = temp_end_time; } valid = TRUE; } renderings = renderings->next; } temp_string = g_strdup_printf(_("%s: Rendering Movie Generation Dialog"),PACKAGE); ui_render_movie->dialog = gtk_dialog_new_with_buttons(temp_string, ui_render->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_HELP, GTK_RESPONSE_HELP, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Generate Movie"), AMITK_RESPONSE_EXECUTE, NULL); g_free(temp_string); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(ui_render_movie->dialog), "response", G_CALLBACK(response_cb), ui_render_movie); g_signal_connect(G_OBJECT(ui_render_movie->dialog), "delete_event", G_CALLBACK(delete_event_cb), ui_render_movie); /* --------------------------- Basic Parameters page --------------------------- */ /* start making the widgets for this dialog box */ packing_table = gtk_table_new(5,3,FALSE); table_row=0; gtk_container_add (GTK_CONTAINER (GTK_DIALOG(ui_render_movie->dialog)->vbox), packing_table); /* widgets to specify how many frames */ label = gtk_label_new(_("Movie Duration (sec)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); ui_render_movie->duration_spin_button = gtk_spin_button_new_with_range(0, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_render_movie->duration_spin_button), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_render_movie->duration_spin_button), ui_render_movie->duration); g_signal_connect(G_OBJECT(ui_render_movie->duration_spin_button), "value_changed", G_CALLBACK(change_frames_cb), ui_render_movie); g_signal_connect(G_OBJECT(ui_render_movie->duration_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->duration_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0,3, table_row, table_row+1,GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* widgets to specify number of rotations on the axis */ for (i_axis=0;i_axisaxis_spin_button[i_axis] = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_render_movie->axis_spin_button[i_axis]), FALSE); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ui_render_movie->axis_spin_button[i_axis]), 2); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_render_movie->axis_spin_button[i_axis]), ui_render_movie->rotation[i_axis]); g_object_set_data(G_OBJECT(ui_render_movie->axis_spin_button[i_axis]), "which_entry", GINT_TO_POINTER(i_axis)); g_signal_connect(G_OBJECT(ui_render_movie->axis_spin_button[i_axis]), "value_changed", G_CALLBACK(change_rotation_cb), ui_render_movie); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->axis_spin_button[i_axis],1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; } /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0,3, table_row, table_row+1,GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* do we want to make a movie over time or over frames */ label = gtk_label_new(_("Dynamic Movie:")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(packing_table), hbox,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); table_row++; /* the radio buttons */ radio_button1 = gtk_radio_button_new_with_label(NULL, _("No")); gtk_box_pack_start(GTK_BOX(hbox), radio_button1, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button1), "dynamic_type", GINT_TO_POINTER(NOT_DYNAMIC)); ui_render_movie->dynamic_type = radio_button1; radio_button2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over time")); gtk_box_pack_start(GTK_BOX(hbox), radio_button2, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button2), "dynamic_type", GINT_TO_POINTER(OVER_TIME)); radio_button3 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over frames")); gtk_box_pack_start(GTK_BOX(hbox), radio_button3, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button3), "dynamic_type", GINT_TO_POINTER(OVER_FRAMES)); hbox = gtk_hbox_new(FALSE, 0); gtk_table_attach(GTK_TABLE(packing_table), hbox,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); gtk_widget_show(hbox); table_row++; radio_button4 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over frames smoothed")); gtk_box_pack_start(GTK_BOX(hbox), radio_button4, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button4), "dynamic_type", GINT_TO_POINTER(OVER_FRAMES_SMOOTHED)); radio_button5 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button1), _("over gates")); gtk_box_pack_start(GTK_BOX(hbox), radio_button5, FALSE, FALSE, 3); g_object_set_data(G_OBJECT(radio_button5), "dynamic_type", GINT_TO_POINTER(OVER_GATES)); g_signal_connect(G_OBJECT(radio_button1), "clicked", G_CALLBACK(dynamic_type_cb), ui_render_movie); g_signal_connect(G_OBJECT(radio_button2), "clicked", G_CALLBACK(dynamic_type_cb), ui_render_movie); g_signal_connect(G_OBJECT(radio_button3), "clicked", G_CALLBACK(dynamic_type_cb), ui_render_movie); g_signal_connect(G_OBJECT(radio_button4), "clicked", G_CALLBACK(dynamic_type_cb), ui_render_movie); g_signal_connect(G_OBJECT(radio_button5), "clicked", G_CALLBACK(dynamic_type_cb), ui_render_movie); /* widgets to specify the start and end times */ ui_render_movie->start_time_label = gtk_label_new(_("Start Time (s)")); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->start_time_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); ui_render_movie->start_frame_label = gtk_label_new(_("Start Frame")); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->start_frame_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); ui_render_movie->start_time_spin_button = gtk_spin_button_new_with_range(ui_render_movie->start_time, ui_render_movie->end_time, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_render_movie->start_time_spin_button), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_render_movie->start_time_spin_button), ui_render_movie->start_time); g_signal_connect(G_OBJECT(ui_render_movie->start_time_spin_button), "value_changed", G_CALLBACK(change_start_time_cb), ui_render_movie); g_signal_connect(G_OBJECT(ui_render_movie->start_time_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->start_time_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); ui_render_movie->start_frame_spin_button = gtk_spin_button_new_with_range(ui_render_movie->start_frame,ui_render_movie->end_frame+0.1, 1.0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ui_render_movie->start_frame_spin_button),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_render_movie->start_frame_spin_button), ui_render_movie->start_frame); g_signal_connect(G_OBJECT(ui_render_movie->start_frame_spin_button), "value_changed", G_CALLBACK(change_start_frame_cb), ui_render_movie); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->start_frame_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; ui_render_movie->end_time_label = gtk_label_new(_("End Time (s)")); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->end_time_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); ui_render_movie->end_frame_label = gtk_label_new(_("End Frame")); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->end_frame_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); ui_render_movie->end_time_spin_button = gtk_spin_button_new_with_range(ui_render_movie->start_time, ui_render_movie->end_time, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_render_movie->end_time_spin_button), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_render_movie->end_time_spin_button), ui_render_movie->end_time); g_signal_connect(G_OBJECT(ui_render_movie->end_time_spin_button), "value_changed", G_CALLBACK(change_end_time_cb), ui_render_movie); g_signal_connect(G_OBJECT(ui_render_movie->end_time_spin_button), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->end_time_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); ui_render_movie->end_frame_spin_button = gtk_spin_button_new_with_range(ui_render_movie->start_frame,ui_render_movie->end_frame+0.1, 1.0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ui_render_movie->end_frame_spin_button),0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_render_movie->end_frame_spin_button), ui_render_movie->end_frame); g_signal_connect(G_OBJECT(ui_render_movie->end_frame_spin_button), "value_changed", G_CALLBACK(change_end_frame_cb), ui_render_movie); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->end_frame_spin_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; ui_render_movie->time_on_image_label = gtk_label_new(_("Display time on image")); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->time_on_image_label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); ui_render_movie->time_on_image_button = gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui_render_movie->time_on_image_button), ui_render_movie->ui_render->time_label_on); g_signal_connect(G_OBJECT(ui_render_movie->time_on_image_button), "toggled", G_CALLBACK(time_label_on_cb), ui_render_movie); gtk_table_attach(GTK_TABLE(packing_table), ui_render_movie->time_on_image_button,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* progress dialog */ ui_render_movie->progress_dialog = amitk_progress_dialog_new(GTK_WINDOW(ui_render_movie->dialog)); amitk_progress_dialog_set_text(AMITK_PROGRESS_DIALOG(ui_render_movie->progress_dialog), _("Rendered Movie Progress")); /* show all our widgets */ gtk_widget_show_all(ui_render_movie->dialog); /* and hide the appropriate widgets */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button1), TRUE); gtk_widget_hide(ui_render_movie->start_frame_label); gtk_widget_hide(ui_render_movie->start_frame_spin_button); gtk_widget_hide(ui_render_movie->end_frame_label); gtk_widget_hide(ui_render_movie->end_frame_spin_button); gtk_widget_hide(ui_render_movie->start_time_label); gtk_widget_hide(ui_render_movie->start_time_spin_button); gtk_widget_hide(ui_render_movie->end_time_label); gtk_widget_hide(ui_render_movie->end_time_spin_button); gtk_widget_hide(ui_render_movie->time_on_image_label); gtk_widget_hide(ui_render_movie->time_on_image_button); return (gpointer) ui_render_movie; } #endif /* AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT */ #endif /* LIBVOLPACK_SUPPORT */ amide-1.0.6/amide-current/src/ui_render_movie.h000066400000000000000000000023171423227705100214550ustar00rootroot00000000000000/* ui_render_movie.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_LIBVOLPACK_SUPPORT #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) /* header files that are always needed with this file */ #include "ui_render.h" /* external functions */ gpointer * ui_render_movie_dialog_create(ui_render_t * ui_render); #endif /* AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT */ #endif /* LIBVOLPACK_SUPPORT */ amide-1.0.6/amide-current/src/ui_series.c000066400000000000000000001324331423227705100202670ustar00rootroot00000000000000/* ui_series.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "amide_gconf.h" #include "amitk_common.h" #include "amitk_threshold.h" #include "amitk_progress_dialog.h" #include "amitk_canvas_object.h" #include "amitk_tree_view.h" #include "image.h" #include "ui_common.h" #include "ui_series.h" typedef enum { OVER_SPACE, OVER_FRAMES, OVER_GATES, NUM_SERIES_TYPES, } series_type_t; /* external variables */ static gchar * series_names[] = { N_("over Space"), N_("over Time"), N_("over Gates") }; static gchar * series_explanations[] = { N_("Look at a series of images over a spatial dimension"), N_("Look at a series of images over time"), N_("Look at a series of images over gates") }; #define UPDATE_NONE 0 #define UPDATE_SERIES 0x1 #define GCONF_AMIDE_SERIES "SERIES" /* ui_series data structures */ typedef struct ui_series_t { GtkWindow * window; GtkWidget * window_vbox; GList * slice_cache; gint max_slice_cache_size; GList * objects; AmitkDataSet * active_ds; GtkWidget * canvas; gint canvas_height; gint canvas_width; GnomeCanvasItem ** images; GnomeCanvasItem ** captions; GList ** items; GtkWidget * thresholds_dialog; guint num_slices, rows, columns; AmitkVolume * volume; amide_time_t view_time; AmitkFuseType fuse_type; amide_real_t pixel_dim; series_type_t series_type; AmitkPreferences * preferences; GtkWidget * progress_dialog; gboolean in_generation; gboolean quit_generation; gint roi_width; #ifdef AMIDE_LIBGNOMECANVAS_AA gdouble roi_transparency; #else GdkLineStyle line_style; gboolean fill_roi; #endif gint pixbuf_width; gint pixbuf_height; /* for "OVER SPACE" series */ amide_time_t view_duration; amide_real_t start_z; amide_real_t z_point; /* current slice offset z component*/ amide_real_t end_z; /* for "OVER TIME" series */ guint view_frame; amide_time_t start_time; amide_time_t * frame_durations; /* an array of frame durations */ /* for "OVER GATES" series */ gint view_gate; gint num_gates; guint next_update; guint idle_handler_id; guint reference_count; } ui_series_t; static void scroll_change_cb(GtkAdjustment* adjustment, gpointer data); static void canvas_size_change_cb(GtkWidget * widget, GtkAllocation * allocation, gpointer ui_series); static void export_cb(GtkAction * action, gpointer data); static void changed_cb(gpointer dummy, gpointer ui_series); static void color_table_changed_cb(gpointer dummy, AmitkViewMode view_mode, gpointer ui_series); static void data_set_invalidate_slice_cache(AmitkDataSet *ds, gpointer ui_series); static void threshold_cb(GtkAction * action, gpointer data); static void close_cb(GtkAction * action, gpointer data); static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data); static void menus_toolbar_create(ui_series_t * ui_series); static ui_series_t * ui_series_unref(ui_series_t * ui_series); static ui_series_t * ui_series_init(GtkWindow * window, GtkWidget * window_vbox); static GtkAdjustment * ui_series_create_scroll_adjustment(ui_series_t * ui_series); static void add_update(ui_series_t * ui_series); static gboolean update_immediate(gpointer ui_series); static void read_series_preferences(series_type_t * series_type, AmitkView * view); /* function called by the adjustment in charge for scrolling */ static void scroll_change_cb(GtkAdjustment* adjustment, gpointer data) { ui_series_t * ui_series = data; switch(ui_series->series_type) { case OVER_GATES: ui_series->view_gate = adjustment->value; break; case OVER_FRAMES: ui_series->view_frame = adjustment->value; break; case OVER_SPACE: default: ui_series->z_point = adjustment->value-AMITK_VOLUME_Z_CORNER(ui_series->volume)/2.0; break; } add_update(ui_series); return; } static void canvas_size_change_cb(GtkWidget * widget, GtkAllocation * allocation, gpointer data) { ui_series_t * ui_series = data; ui_series->canvas_width = allocation->width; ui_series->canvas_height = allocation->height; add_update(ui_series); return; } /* function to save the series as an image */ static void export_cb(GtkAction * action, gpointer data) { ui_series_t * ui_series = data; GList * objects; GtkWidget * file_chooser; gchar * filename=NULL; gchar * data_set_names = NULL; GdkPixbuf * pixbuf; file_chooser = gtk_file_chooser_dialog_new(_("Export to Image"), GTK_WINDOW(ui_series->window), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(ui_series->preferences, file_chooser); /* set the default directory if applicable */ /* take a guess at the filename */ objects = ui_series->objects; while (objects != NULL) { if (AMITK_IS_DATA_SET(objects->data)) { if (data_set_names == NULL) filename = g_strdup(AMITK_OBJECT_NAME(objects->data)); else filename = g_strdup_printf("%s+%s",data_set_names, AMITK_OBJECT_NAME(objects->data)); g_free(data_set_names); data_set_names = filename; } objects = objects->next; } if (data_set_names == NULL) { objects = ui_series->objects; while (objects != NULL) { if (data_set_names == NULL) filename = g_strdup(AMITK_OBJECT_NAME(objects->data)); else filename = g_strdup_printf("%s+%s",data_set_names, AMITK_OBJECT_NAME(objects->data)); g_free(data_set_names); data_set_names = filename; objects = objects->next; } } switch(ui_series->series_type) { case OVER_GATES: filename = g_strdup_printf("%s_gated.jpg", data_set_names); break; case OVER_FRAMES: case OVER_SPACE: default: filename = g_strdup_printf("%s.jpg", data_set_names); break; } gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), filename); g_free(data_set_names); g_free(filename); if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy(file_chooser); if (filename == NULL) return; /* inappropriate name or don't want to overwrite */ pixbuf = amitk_get_pixbuf_from_canvas(GNOME_CANVAS(ui_series->canvas),0,0, ui_series->columns*(ui_series->pixbuf_width+UI_SERIES_R_MARGIN+UI_SERIES_L_MARGIN), ui_series->rows*(ui_series->pixbuf_height+UI_SERIES_TOP_MARGIN+UI_SERIES_BOTTOM_MARGIN)); if (pixbuf == NULL) { g_warning(_("ui_series canvas failed to return a valid image")); return; } if (gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", "100", NULL) == FALSE) { g_warning(_("Failure Saving File: %s"),filename); return; } g_object_unref(pixbuf); return; } /* function called when a data set changed */ static void changed_cb(gpointer dummy, gpointer data) { ui_series_t * ui_series=data; add_update(ui_series); return; } static void color_table_changed_cb(gpointer dummy, AmitkViewMode view_mode, gpointer ui_series) { g_return_if_fail(view_mode == AMITK_VIEW_MODE_SINGLE); changed_cb(dummy, ui_series); return; } static void data_set_invalidate_slice_cache(AmitkDataSet *ds, gpointer data) { ui_series_t * ui_series=data; if (ui_series->slice_cache != NULL) { ui_series->slice_cache = amitk_objects_unref(ui_series->slice_cache); } add_update(ui_series); return; } static gboolean thresholds_delete_event(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_series_t * ui_series = data; /* just keeping track on whether or not the threshold widget is up */ ui_series->thresholds_dialog = NULL; return FALSE; } /* function called when we hit the threshold button */ static void threshold_cb(GtkAction * action, gpointer data) { ui_series_t * ui_series = data; if (ui_series->thresholds_dialog != NULL) return; if (!amitk_objects_has_type(ui_series->objects, AMITK_OBJECT_TYPE_DATA_SET, FALSE)) { g_warning(_("No data sets to threshold\n")); return; } ui_common_place_cursor(UI_CURSOR_WAIT, ui_series->canvas); ui_series->thresholds_dialog = amitk_thresholds_dialog_new(ui_series->objects, ui_series->window); g_signal_connect(G_OBJECT(ui_series->thresholds_dialog), "delete_event", G_CALLBACK(thresholds_delete_event), ui_series); gtk_widget_show(ui_series->thresholds_dialog); ui_common_remove_wait_cursor(ui_series->canvas); return; } /* function ran when closing a series window */ static void close_cb(GtkAction * action, gpointer data) { ui_series_t * ui_series = data; GtkWindow * window = ui_series->window; gboolean return_val; /* run the delete event function */ g_signal_emit_by_name(G_OBJECT(window), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(window)); return; } /* function to run for a delete_event */ static gboolean delete_event_cb(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_series_t * ui_series = data; GtkWindow * window = ui_series->window; /* trying to close while we're generating */ if (ui_series->in_generation) { ui_series->quit_generation=TRUE; return TRUE; } /* free the associated data structure */ ui_series = ui_series_unref(ui_series); /* tell the rest of the program this window is no longer here */ amide_unregister_window((gpointer) window); return FALSE; } static const GtkActionEntry normal_items[] = { /* Toplevel */ { "FileMenu", NULL, N_("_File") }, { "HelpMenu", NULL, N_("_Help") }, /* File menu */ { "ExportSeries", NULL, N_("_Export Series"), NULL, N_("Export the series to a JPEG image file"), G_CALLBACK(export_cb)}, { "Close", GTK_STOCK_CLOSE, NULL, "W", N_("Close the series dialog"), G_CALLBACK (close_cb)}, /* Toolbar items */ { "Threshold", "amide_icon_thresholding", N_("Threshold"), NULL, N_("Set the thresholds and colormaps for the data sets in the series view"), G_CALLBACK(threshold_cb)} }; static const char *ui_description = "" " " " " " " " " " " " " HELP_MENU_UI_DESCRIPTION " " " " " " " " ""; /* function to setup the menus for the series ui */ static void menus_toolbar_create(ui_series_t * ui_series) { GtkWidget *menubar; GtkWidget *toolbar; GtkActionGroup *action_group; GtkUIManager *ui_manager; GtkAccelGroup *accel_group; GError *error; /* sanity check */ g_assert(ui_series!=NULL); /* create an action group with all the menu actions */ action_group = gtk_action_group_new ("MenuActions"); gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions(action_group, normal_items, G_N_ELEMENTS(normal_items),ui_series); gtk_action_group_add_actions(action_group, ui_common_help_menu_items, G_N_ELEMENTS(ui_common_help_menu_items),ui_series); /* create the ui manager, and add the actions and accel's */ ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); accel_group = gtk_ui_manager_get_accel_group (ui_manager); gtk_window_add_accel_group (ui_series->window, accel_group); /* create the actual menu/toolbar ui */ error = NULL; if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &error)) { g_warning ("%s: building menus failed in %s: %s", PACKAGE, __FILE__, error->message); g_error_free (error); return; } /* pack in the menu and toolbar */ menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu"); gtk_box_pack_start (GTK_BOX (ui_series->window_vbox), menubar, FALSE, FALSE, 0); toolbar = gtk_ui_manager_get_widget (ui_manager, "/ToolBar"); gtk_box_pack_start (GTK_BOX (ui_series->window_vbox), toolbar, FALSE, FALSE, 0); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); return; } /* destroy a ui_series data structure */ static ui_series_t * ui_series_unref(ui_series_t * ui_series) { GList * temp_objects; gboolean return_val; gint i; g_return_val_if_fail(ui_series != NULL, NULL); /* sanity checks */ g_return_val_if_fail(ui_series->reference_count > 0, NULL); /* remove a reference count */ ui_series->reference_count--; /* things to do if we've removed all reference's */ if (ui_series->reference_count == 0) { #ifdef AMIDE_DEBUG g_print("freeing ui_series\n"); #endif if (ui_series->idle_handler_id != 0) { g_source_remove(ui_series->idle_handler_id); ui_series->idle_handler_id = 0; } if (ui_series->active_ds != NULL) ui_series->active_ds = amitk_object_unref(ui_series->active_ds); if (ui_series->objects != NULL) { /* disconnect and signals */ temp_objects = ui_series->objects; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { g_signal_handlers_disconnect_by_func(G_OBJECT(temp_objects->data), G_CALLBACK(data_set_invalidate_slice_cache), ui_series); g_signal_handlers_disconnect_by_func(G_OBJECT(temp_objects->data), G_CALLBACK(color_table_changed_cb), ui_series); } g_signal_handlers_disconnect_by_func(G_OBJECT(temp_objects->data), G_CALLBACK(changed_cb), ui_series); temp_objects = temp_objects->next; } amitk_objects_unref(ui_series->objects); ui_series->objects = NULL; } if (ui_series->slice_cache != NULL) { ui_series->slice_cache = amitk_objects_unref(ui_series->slice_cache); } if (ui_series->volume != NULL) { amitk_object_unref(ui_series->volume); ui_series->volume = NULL; } if (ui_series->thresholds_dialog != NULL) { gtk_widget_destroy(ui_series->thresholds_dialog); ui_series->thresholds_dialog = NULL; } if (ui_series->preferences != NULL) { g_object_unref(ui_series->preferences); ui_series->preferences = NULL; } if (ui_series->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(ui_series->progress_dialog), "delete_event", NULL, &return_val); ui_series->progress_dialog = NULL; } if (ui_series->images != NULL) { g_free(ui_series->images); ui_series->images = NULL; } if (ui_series->captions != NULL) { g_free(ui_series->captions); ui_series->captions = NULL; } if (ui_series->items != NULL) { for (i=0; i < ui_series->num_slices; i++) { if (ui_series->items[i] != NULL) { g_list_free(ui_series->items[i]); ui_series->items[i] = NULL; } } g_free(ui_series->items); ui_series->items = NULL; } if (ui_series->frame_durations != NULL) { g_free(ui_series->frame_durations); ui_series->frame_durations = NULL; } g_free(ui_series); ui_series = NULL; } return ui_series; } /* allocate and initialize a ui_series data structure */ static ui_series_t * ui_series_init(GtkWindow * window, GtkWidget * window_vbox) { ui_series_t * ui_series; /* alloc space for the data structure for passing ui info */ if ((ui_series = g_try_new(ui_series_t,1)) == NULL) { g_warning(_("couldn't allocate memory space for ui_series_t")); return NULL; } ui_series->reference_count = 1; /* set any needed parameters */ ui_series->window = window; ui_series->window_vbox = window_vbox; ui_series->slice_cache = NULL; ui_series->max_slice_cache_size=10; ui_series->num_slices = 0; ui_series->rows = 0; ui_series->columns = 0; ui_series->canvas_height = 0; ui_series->canvas_width = 1; ui_series->images = NULL; ui_series->captions = NULL; ui_series->items = NULL; ui_series->objects = NULL; ui_series->active_ds = NULL; ui_series->fuse_type = AMITK_FUSE_TYPE_BLEND; ui_series->pixel_dim = 1.0; ui_series->volume = NULL; ui_series->view_time = 0.0; ui_series->series_type = OVER_SPACE; ui_series->thresholds_dialog = NULL; ui_series->preferences = NULL; ui_series->progress_dialog = amitk_progress_dialog_new(ui_series->window); ui_series->in_generation=FALSE; ui_series->quit_generation=FALSE; ui_series->roi_width = 1.0; #ifdef AMIDE_LIBGNOMECANVAS_AA ui_series->roi_transparency = 0.5; #else ui_series->line_style = 0; ui_series->fill_roi = TRUE; #endif ui_series->pixbuf_width = 0; ui_series->pixbuf_height = 0; ui_series->view_duration = 1.0; ui_series->start_z = 0.0; ui_series->end_z = 0.0; ui_series->z_point = 0.0; ui_series->view_frame = 0; ui_series->start_time = 0.0; ui_series->frame_durations = NULL; ui_series->view_gate = 0; ui_series->num_gates = 1; ui_series->next_update = UPDATE_NONE; ui_series->idle_handler_id = 0; return ui_series; } /* function to make the adjustments for the scrolling scale */ static GtkAdjustment * ui_series_create_scroll_adjustment(ui_series_t * ui_series) { amide_real_t thickness; GtkObject * adjustment; switch(ui_series->series_type) { case OVER_GATES: adjustment = gtk_adjustment_new(ui_series->view_gate, 0, ui_series->num_slices, 1,1,1); break; case OVER_FRAMES: adjustment = gtk_adjustment_new(ui_series->view_frame, 0, ui_series->num_slices, 1,1,1); break; case OVER_SPACE: default: thickness = AMITK_VOLUME_Z_CORNER(ui_series->volume); adjustment = gtk_adjustment_new(ui_series->z_point-thickness/2.0, ui_series->start_z+thickness/2.0, ui_series->end_z-thickness/2.0, thickness, thickness, thickness); break; } return GTK_ADJUSTMENT(adjustment); } static void add_update(ui_series_t * ui_series) { ui_series->next_update = ui_series->next_update | UPDATE_SERIES; if (ui_series->idle_handler_id == 0) { ui_common_place_cursor_no_wait(UI_CURSOR_WAIT, ui_series->canvas); ui_series->idle_handler_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,update_immediate, ui_series, NULL); } return; } /* funtion to update the canvas */ static gboolean update_immediate(gpointer data) { ui_series_t * ui_series = data; AmitkPoint temp_point; amide_time_t temp_time, temp_duration; gint temp_gate; gint i, start_i; gdouble x, y; AmitkVolume * view_volume; gint image_width, image_height; gchar * temp_string; GdkPixbuf * pixbuf; gboolean can_continue=TRUE; gboolean return_val = TRUE; GList * objects; GnomeCanvasItem * item; rgba_t outline_color; gint rows, columns; ui_series->in_generation=TRUE; temp_string = g_strdup_printf(_("Slicing for series")); amitk_progress_dialog_set_text(AMITK_PROGRESS_DIALOG(ui_series->progress_dialog), temp_string); g_free(temp_string); /* allocate space for the following if this is the first time through */ if (ui_series->images == NULL) { if ((ui_series->images = g_try_new(GnomeCanvasItem *,ui_series->num_slices)) == NULL) { g_warning(_("couldn't allocate memory space for pointers to image GnomeCanvasItem's")); return_val = FALSE; goto exit_update; } if ((ui_series->captions = g_try_new(GnomeCanvasItem *,ui_series->num_slices)) == NULL) { g_warning(_("couldn't allocate memory space for pointers to caption GnomeCanvasItem's")); return_val = FALSE; goto exit_update; } if ((ui_series->items = g_try_new(GList *,ui_series->num_slices)) == NULL) { g_warning(_("couldn't allocate memory space for pointers to GnomeCanavasItem lists")); return_val = FALSE; goto exit_update; } for (i=0; i < ui_series->num_slices ; i++) { ui_series->images[i] = NULL; ui_series->captions[i] = NULL; ui_series->items[i] = NULL; } } image_width = ui_series->pixbuf_width + UI_SERIES_R_MARGIN + UI_SERIES_L_MARGIN; image_height = ui_series->pixbuf_height + UI_SERIES_TOP_MARGIN + UI_SERIES_BOTTOM_MARGIN; /* figure out how many images we can display at once */ columns = floor(ui_series->canvas_width/image_width); if (columns < 1) columns = 1; rows = floor(ui_series->canvas_height/image_height); if (rows < 1) rows = 1; /* compensate for cases where we don't need all the rows */ if ((columns * rows) > ui_series->num_slices) rows = ceil((double) ui_series->num_slices/(double) columns); /* if we've changed rows or columns, delete prexisting canvas objects */ if ((ui_series->rows != rows) || (ui_series->columns != columns)) { ui_series->rows = rows; ui_series->columns = columns; for (i=0; i < ui_series->num_slices ; i++) { if (ui_series->images[i] != NULL) { gtk_object_destroy(GTK_OBJECT(ui_series->images[i])); ui_series->images[i] = NULL; } if (ui_series->captions[i] != NULL) { gtk_object_destroy(GTK_OBJECT(ui_series->captions[i])); ui_series->captions[i] = NULL; } if (ui_series->items[i] != NULL) { while (ui_series->items[i] != NULL) { item = ui_series->items[i]->data; ui_series->items[i] = g_list_remove(ui_series->items[i], item); gtk_object_destroy(GTK_OBJECT(item)); } ui_series->items[i] = NULL; } } gnome_canvas_set_scroll_region(GNOME_CANVAS(ui_series->canvas), 0.0, 0.0, (double) (ui_series->columns*image_width), (double) (ui_series->rows*image_height)); } /* figure out what's the first image we want to display */ switch(ui_series->series_type) { case OVER_GATES: start_i = ui_series->view_gate; break; case OVER_FRAMES: start_i = ui_series->view_frame; break; case OVER_SPACE: default: start_i = ui_series->num_slices*((ui_series->z_point-ui_series->start_z)/ (ui_series->end_z-ui_series->start_z-AMITK_VOLUME_Z_CORNER(ui_series->volume))); break; } /* correct i for special cases */ if (ui_series->num_slices < ui_series->columns*ui_series->rows) start_i=0; else if (start_i < (ui_series->columns*ui_series->rows/2.0)) start_i=0; else if (start_i > (ui_series->num_slices - ui_series->columns*ui_series->rows)) start_i = ui_series->num_slices - ui_series->columns*ui_series->rows; else start_i = start_i-ui_series->columns*ui_series->rows/2.0; temp_time = ui_series->start_time; temp_point = zero_point; temp_gate = -1; if (ui_series->series_type == OVER_FRAMES) { for (i=0;i< start_i; i++) temp_time += ui_series->frame_durations[i]; temp_time -= ui_series->frame_durations[start_i];/* well get added back 1st time through loop */ temp_duration = ui_series->frame_durations[start_i]; } else { temp_time = ui_series->view_time; temp_duration = ui_series->view_duration; } x = y = 0.0; view_volume = AMITK_VOLUME(amitk_object_copy(AMITK_OBJECT(ui_series->volume))); for (i=start_i; (((i-start_i) < (ui_series->rows*ui_series->columns)) && (i < ui_series->num_slices) && can_continue && (!ui_series->quit_generation)); i++) { switch (ui_series->series_type) { case OVER_GATES: temp_gate=i; break; case OVER_FRAMES: temp_time += temp_duration; /* duration from last time through the loop */ temp_duration = ui_series->frame_durations[i]; break; case OVER_SPACE: default: temp_point.z = i*AMITK_VOLUME_Z_CORNER(ui_series->volume)+ui_series->start_z; break; } amitk_space_set_offset(AMITK_SPACE(view_volume), amitk_space_s2b(AMITK_SPACE(ui_series->volume), temp_point)); /* figure out the next x,y spot to put this guy */ y = floor((i-start_i)/ui_series->columns)*image_height; x = (i-start_i-ui_series->columns*floor((i-start_i)/ui_series->columns))*image_width; if (amitk_objects_has_type(ui_series->objects, AMITK_OBJECT_TYPE_DATA_SET, FALSE)) { pixbuf = image_from_data_sets(NULL, &(ui_series->slice_cache), ui_series->max_slice_cache_size, ui_series->objects, ui_series->active_ds, temp_time+EPSILON*fabs(temp_time), temp_duration-EPSILON*fabs(temp_duration), temp_gate, ui_series->pixel_dim, view_volume, ui_series->fuse_type, AMITK_VIEW_MODE_SINGLE); if (ui_series->images[i-start_i] == NULL) ui_series->images[i-start_i] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(ui_series->canvas)), gnome_canvas_pixbuf_get_type(), "pixbuf", pixbuf, "x", x+UI_SERIES_L_MARGIN, "y", y+UI_SERIES_TOP_MARGIN, NULL); else gnome_canvas_item_set(ui_series->images[i-start_i], "pixbuf", pixbuf, NULL); g_object_unref(pixbuf); } /* draw the rest of the objects */ while (ui_series->items[i-start_i] != NULL) { /* first, delete the old objects */ item = ui_series->items[i-start_i]->data; ui_series->items[i-start_i] = g_list_remove(ui_series->items[i-start_i], item); gtk_object_destroy(GTK_OBJECT(item)); } /* add the new item to the canvas */ objects = ui_series->objects; while (objects != NULL) { if (AMITK_IS_FIDUCIAL_MARK(objects->data) || AMITK_IS_ROI(objects->data)) { if (AMITK_IS_DATA_SET(AMITK_OBJECT_PARENT(objects->data))) outline_color = amitk_color_table_outline_color(AMITK_DATA_SET_COLOR_TABLE(AMITK_OBJECT_PARENT(objects->data), AMITK_VIEW_MODE_SINGLE), TRUE); else outline_color = amitk_color_table_outline_color(AMITK_COLOR_TABLE_BW_LINEAR, TRUE); item = amitk_canvas_object_draw(GNOME_CANVAS(ui_series->canvas), view_volume, objects->data, AMITK_VIEW_MODE_SINGLE, NULL, ui_series->pixel_dim, ui_series->pixbuf_width, ui_series->pixbuf_height, x+UI_SERIES_L_MARGIN, y+UI_SERIES_TOP_MARGIN, outline_color, ui_series->roi_width, #ifdef AMIDE_LIBGNOMECANVAS_AA ui_series->roi_transparency #else ui_series->line_style, ui_series->fill_roi #endif ); if (item != NULL) ui_series->items[i-start_i] = g_list_append(ui_series->items[i-start_i], item); } objects = objects->next; } /* write the caption */ switch (ui_series->series_type) { case OVER_GATES: temp_string = g_strdup_printf("gate %d", temp_gate); break; case OVER_FRAMES: temp_string = g_strdup_printf("%2.1f-%2.1f s", temp_time, temp_time+temp_duration); break; case OVER_SPACE: default: temp_string = g_strdup_printf("%2.1f-%2.1f mm", temp_point.z, temp_point.z+AMITK_VOLUME_Z_CORNER(ui_series->volume)); break; } if (ui_series->captions[i-start_i] == NULL) ui_series->captions[i-start_i] = gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(ui_series->canvas)), gnome_canvas_text_get_type(), "justification", GTK_JUSTIFY_LEFT, "anchor", GTK_ANCHOR_NORTH_WEST, "text", temp_string, "x", x+UI_SERIES_L_MARGIN, "y", y+image_height-UI_SERIES_BOTTOM_MARGIN, "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); else gnome_canvas_item_set(ui_series->captions[i-start_i], "text", temp_string, NULL); g_free(temp_string); can_continue = amitk_progress_dialog_set_fraction(AMITK_PROGRESS_DIALOG(ui_series->progress_dialog), (i-start_i)/((gdouble) ui_series->rows*ui_series->columns)); } amitk_object_unref(view_volume); return_val = FALSE; exit_update: amitk_progress_dialog_set_fraction(AMITK_PROGRESS_DIALOG(ui_series->progress_dialog), 2.0); /* hide progress dialog */ ui_common_remove_wait_cursor(ui_series->canvas); ui_series->idle_handler_id=0; ui_series->quit_generation=FALSE; ui_series->in_generation=FALSE; return return_val; } static void read_series_preferences(series_type_t * series_type, AmitkView * view) { *series_type = amide_gconf_get_int(GCONF_AMIDE_SERIES,"Type"); *view = amide_gconf_get_int(GCONF_AMIDE_SERIES,"View"); return; } /* function that sets up the series dialog */ void ui_series_create(AmitkStudy * study, AmitkObject * active_object, GList * selected_objects, AmitkPreferences * preferences) { ui_series_t * ui_series; GtkWindow * window; GtkWidget * window_vbox; gchar * title = NULL; GtkWidget * packing_table; GtkAdjustment * adjustment; GtkWidget * scale; amide_time_t min_duration; GList * temp_objects; guint num_data_sets = 0; guint total_data_set_frames=0; gint width, height; series_type_t series_type; AmitkView view; read_series_preferences(&series_type, &view); /* sanity checks */ g_return_if_fail(AMITK_IS_STUDY(study)); title = g_strdup_printf(_("Series: %s (%s - %s)"), AMITK_OBJECT_NAME(study), amitk_view_get_name(view), _(series_names[series_type])); window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); gtk_window_set_title(window, title); g_free(title); gtk_window_set_resizable(window, TRUE); width = 0.5*gdk_screen_width(); height = 0.5*gdk_screen_height(); gtk_window_set_default_size(window, width, height); window_vbox = gtk_vbox_new(FALSE,0); gtk_container_add (GTK_CONTAINER (window), window_vbox); ui_series = ui_series_init(window, window_vbox); ui_series->preferences = g_object_ref(preferences); ui_series->series_type = series_type; #ifdef AMIDE_LIBGNOMECANVAS_AA ui_series->roi_transparency = AMITK_STUDY_CANVAS_ROI_TRANSPARENCY(study); #else ui_series->line_style = AMITK_STUDY_CANVAS_LINE_STYLE(study); ui_series->fill_roi = AMITK_STUDY_CANVAS_FILL_ROI(study); #endif ui_series->roi_width = AMITK_STUDY_CANVAS_ROI_WIDTH(study); ui_series->objects = amitk_objects_ref(selected_objects); if (ui_series->objects == NULL) { g_warning(_("Need selected objects to create a series")); ui_series_unref(ui_series); return; } if (active_object != NULL) if (AMITK_IS_DATA_SET(active_object)) ui_series->active_ds = amitk_object_ref(active_object); /* save a pointer to which object is active */ /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(ui_series->window), "delete_event", G_CALLBACK(delete_event_cb), ui_series); /* save the coordinate space of the series and some other parameters */ ui_series->volume = amitk_volume_new(); amitk_space_set_view_space(AMITK_SPACE(ui_series->volume), view, AMITK_STUDY_CANVAS_LAYOUT(study)); amitk_volumes_calc_display_volume(selected_objects, AMITK_SPACE(ui_series->volume), AMITK_STUDY_VIEW_CENTER(study), AMITK_STUDY_VIEW_THICKNESS(study), AMITK_STUDY_FOV(study), ui_series->volume); ui_series->fuse_type = AMITK_STUDY_FUSE_TYPE(study); ui_series->view_time = AMITK_STUDY_VIEW_START_TIME(study); min_duration = amitk_data_sets_get_min_frame_duration(ui_series->objects); ui_series->view_duration = (min_duration > AMITK_STUDY_VIEW_DURATION(study)) ? min_duration : AMITK_STUDY_VIEW_DURATION(study); ui_series->pixel_dim = (1/AMITK_STUDY_ZOOM(study)) * AMITK_STUDY_VOXEL_DIM(study); ui_series->pixbuf_width = ceil(AMITK_VOLUME_X_CORNER(ui_series->volume)/ui_series->pixel_dim); ui_series->pixbuf_height = ceil(AMITK_VOLUME_Y_CORNER(ui_series->volume)/ui_series->pixel_dim); /* count the number of data sets */ temp_objects = ui_series->objects; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { num_data_sets++; total_data_set_frames += AMITK_DATA_SET_NUM_FRAMES(temp_objects->data); } temp_objects = temp_objects->next; } /* do some initial calculations */ switch (ui_series->series_type) { case OVER_GATES: temp_objects = ui_series->objects; ui_series->num_gates = 1; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { if (AMITK_DATA_SET_NUM_GATES(temp_objects->data) > ui_series->num_gates) ui_series->num_gates = AMITK_DATA_SET_NUM_GATES(temp_objects->data); } temp_objects = temp_objects->next; } ui_series->num_slices = ui_series->num_gates; break; case OVER_FRAMES: { amide_time_t current_start = 0.0; amide_time_t last_start, current_end, temp_time; guint * frames; guint i; guint series_frame = 0; gboolean done; gboolean valid; if (num_data_sets == 0) { g_warning(_("Need selected data sets to generate a series of slices over time")); ui_series_unref(ui_series); return; } /* get space for the array that'll take care of which frame of which data set we're looking at*/ frames = g_try_new(guint,num_data_sets); if (frames == NULL) { g_warning(_("unable to allocate memory space for frames")); ui_series_unref(ui_series); return; } for (i=0;iframe_durations = g_try_new(amide_time_t,total_data_set_frames+2); if (ui_series->frame_durations == NULL) { g_warning(_("unable to allocate memory for frame durations")); g_free(frames); ui_series_unref(ui_series); return; } /* do the initial case */ temp_objects = ui_series->objects; i=0; valid = FALSE; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { if (AMITK_DATA_SET_NUM_FRAMES(temp_objects->data) != frames[i]) { temp_time = amitk_data_set_get_start_time(AMITK_DATA_SET(temp_objects->data), frames[i]); if (!valid) /* first valid data set */ { current_start = temp_time; valid = TRUE; } else if (temp_time < current_start) { current_start = temp_time; } } i++; } temp_objects = temp_objects->next; } ui_series->start_time = current_start; /* ignore any frames boundaries close to this one */ temp_objects = ui_series->objects; i=0; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { temp_time = amitk_data_set_get_start_time(AMITK_DATA_SET(temp_objects->data), frames[i]); if (REAL_EQUAL(ui_series->start_time, temp_time)) frames[i]++; i++; } temp_objects = temp_objects->next; } done = FALSE; last_start = ui_series->start_time; while (!done) { /* check if we're done */ temp_objects = ui_series->objects; i=0; done = TRUE; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { if (frames[i] != AMITK_DATA_SET_NUM_FRAMES(temp_objects->data)) done = FALSE; i++; } temp_objects = temp_objects->next; } if (!done) { /* check for the next earliest start time */ temp_objects = ui_series->objects; i=0; valid = FALSE; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { if (AMITK_DATA_SET_NUM_FRAMES(temp_objects->data) != frames[i]) { temp_time = amitk_data_set_get_start_time(AMITK_DATA_SET(temp_objects->data), frames[i]); if (!valid) /* first valid data set */ { current_start = temp_time; valid = TRUE; } else if (temp_time < current_start) { current_start = temp_time; } } i++; } temp_objects = temp_objects->next; } /* allright, found the next start time */ ui_series->frame_durations[series_frame] = current_start-last_start; series_frame++; last_start = current_start; /* and ignore any frames boundaries close to this one */ temp_objects = ui_series->objects; i=0; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { if (AMITK_DATA_SET_NUM_FRAMES(temp_objects->data) != frames[i]) { temp_time = amitk_data_set_get_start_time(AMITK_DATA_SET(temp_objects->data), frames[i]); if (REAL_EQUAL(current_start, temp_time)) frames[i]++; } i++; } temp_objects = temp_objects->next; } } } /* need to get the last frame */ temp_objects = ui_series->objects; i=0; current_end = amitk_data_set_get_end_time(temp_objects->data, frames[i]-1); temp_objects = temp_objects->next; i++; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { temp_time = amitk_data_set_get_end_time(AMITK_DATA_SET(temp_objects->data), frames[i]-1); if (temp_time > current_end) { current_end = temp_time; } i++; } temp_objects = temp_objects->next; } ui_series->frame_durations[series_frame] = current_end-last_start; series_frame++; /* save how many frames we'll need */ ui_series->num_slices = series_frame; /* garbage collection */ g_free(frames); /* figure out the view_frame */ temp_time = ui_series->start_time; for (i=0; inum_slices;i++) { if ((temp_time <= ui_series->view_time) && (ui_series->view_time < temp_time+ui_series->frame_durations[i])) ui_series->view_frame = i; temp_time += ui_series->frame_durations[i]; } } break; case OVER_SPACE: { AmitkCorners view_corners; amitk_volumes_get_enclosing_corners(ui_series->objects, AMITK_SPACE(ui_series->volume), view_corners); ui_series->start_z = view_corners[0].z; ui_series->end_z = view_corners[1].z; ui_series->num_slices = ceil((ui_series->end_z-ui_series->start_z)/AMITK_VOLUME_Z_CORNER(ui_series->volume)); } break; default: g_error("unexpected case in %s at line %d",__FILE__, __LINE__); break; } ui_series->max_slice_cache_size = ui_series->num_slices*num_data_sets+5; /* connect the thresholding and color table signals */ temp_objects = ui_series->objects; while (temp_objects != NULL) { if (AMITK_IS_DATA_SET(temp_objects->data)) { g_signal_connect(G_OBJECT(temp_objects->data), "thresholding_changed", G_CALLBACK(changed_cb), ui_series); g_signal_connect(G_OBJECT(temp_objects->data), "thresholds_changed", G_CALLBACK(changed_cb), ui_series); g_signal_connect(G_OBJECT(temp_objects->data), "color_table_changed", G_CALLBACK(color_table_changed_cb), ui_series); g_signal_connect(G_OBJECT(temp_objects->data), "invalidate_slice_cache", G_CALLBACK(data_set_invalidate_slice_cache), ui_series); g_signal_connect(G_OBJECT(temp_objects->data), "interpolation_changed", G_CALLBACK(changed_cb), ui_series); g_signal_connect(G_OBJECT(temp_objects->data), "rendering_changed", G_CALLBACK(changed_cb), ui_series); } g_signal_connect(G_OBJECT(temp_objects->data), "space_changed", G_CALLBACK(changed_cb), ui_series); temp_objects = temp_objects->next; } menus_toolbar_create(ui_series); /* setup the menu and toolbar */ /* make the widgets for this dialog box */ packing_table = gtk_table_new(1,2,FALSE); gtk_box_pack_start (GTK_BOX (ui_series->window_vbox), packing_table, TRUE,TRUE, 0); /* setup the canvas */ #ifdef AMIDE_LIBGNOMECANVAS_AA ui_series->canvas = gnome_canvas_new_aa(); #else ui_series->canvas = gnome_canvas_new(); #endif g_signal_connect(G_OBJECT(ui_series->canvas), "size_allocate", G_CALLBACK(canvas_size_change_cb), ui_series); gtk_table_attach(GTK_TABLE(packing_table), ui_series->canvas, 0,1,1,2, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); /* make a nice scroll bar */ adjustment = ui_series_create_scroll_adjustment(ui_series); scale = gtk_hscale_new(adjustment); if ((ui_series->series_type == OVER_FRAMES) || (ui_series->series_type == OVER_GATES)) gtk_scale_set_digits(GTK_SCALE(scale), 0); /* want integer for frames */ gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_DISCONTINUOUS); gtk_table_attach(GTK_TABLE(packing_table), GTK_WIDGET(scale), 0,1,0,1, X_PACKING_OPTIONS | GTK_FILL, 0, X_PADDING, Y_PADDING); g_signal_connect(G_OBJECT(adjustment), "value_changed", G_CALLBACK(scroll_change_cb), ui_series); /* show all our widgets */ gtk_widget_show_all(GTK_WIDGET(ui_series->window)); amide_register_window((gpointer) ui_series->window); return; } static void init_series_type_cb(GtkWidget * widget, gpointer data); static void init_view_cb(GtkWidget * widget, gpointer data); static void init_series_type_cb(GtkWidget * widget, gpointer data) { amide_gconf_set_int(GCONF_AMIDE_SERIES,"Type", GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "series_type"))); return; } static void init_view_cb(GtkWidget * widget, gpointer data) { amide_gconf_set_int(GCONF_AMIDE_SERIES,"View", GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "view"))); return; } /* function to setup a dialog to allow us to choose options for the series */ GtkWidget * ui_series_init_dialog_create(AmitkStudy * study, GtkWindow * parent) { GtkWidget * dialog; gchar * temp_string; GtkWidget * table; guint table_row; GtkWidget * label; GtkWidget * radio_button[4]; GtkWidget * hseparator; GtkWidget * scrolled; GtkWidget * tree_view; series_type_t i_series_type; AmitkView i_view; series_type_t series_type; AmitkView view; read_series_preferences(&series_type, &view); temp_string = g_strdup_printf(_("%s: Series Initialization Dialog"), PACKAGE); dialog = gtk_dialog_new_with_buttons (temp_string, parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, GTK_STOCK_EXECUTE, AMITK_RESPONSE_EXECUTE, NULL); gtk_window_set_title(GTK_WINDOW(dialog), temp_string); g_free(temp_string); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(ui_common_init_dialog_response_cb), NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); /* start making the widgets for this dialog box */ table = gtk_table_new(7,3,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); /* what series type do we want */ label = gtk_label_new(_("Series Type:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); for (i_series_type = 0; i_series_type < NUM_SERIES_TYPES; i_series_type++) { if (i_series_type == 0) radio_button[i_series_type] = gtk_radio_button_new_with_label(NULL, _(series_names[i_series_type])); else radio_button[i_series_type] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button[0]), _(series_names[i_series_type])); gtk_widget_set_tooltip_text(radio_button[i_series_type], _(series_explanations[i_series_type])); gtk_table_attach(GTK_TABLE(table), radio_button[i_series_type], 1, 2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[i_series_type]), "series_type", GINT_TO_POINTER(i_series_type)); table_row++; } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[series_type]), TRUE); for (i_series_type = 0; i_series_type < NUM_SERIES_TYPES; i_series_type++) { g_signal_connect(G_OBJECT(radio_button[i_series_type]), "clicked", G_CALLBACK(init_series_type_cb), NULL); } hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(table), hseparator, 0,2, table_row, table_row+1,GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* what view type do we want */ label = gtk_label_new(_("View Type:")); gtk_table_attach(GTK_TABLE(table), label, 0,1, table_row, table_row+1, X_PACKING_OPTIONS, 0, X_PADDING, Y_PADDING); for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { if (i_view == 0) radio_button[i_view] = gtk_radio_button_new_with_label(NULL, amitk_view_get_name(i_view)); else radio_button[i_view] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_button[0]), amitk_view_get_name(i_view)); gtk_table_attach(GTK_TABLE(table), radio_button[i_view], 1, 2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); g_object_set_data(G_OBJECT(radio_button[i_view]), "view", GINT_TO_POINTER(i_view)); table_row++; } gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button[view]), TRUE); for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { g_signal_connect(G_OBJECT(radio_button[i_view]), "clicked", G_CALLBACK(init_view_cb), NULL); } tree_view = amitk_tree_view_new(AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION,NULL, NULL); g_object_set_data(G_OBJECT(dialog), "tree_view", tree_view); amitk_tree_view_set_study(AMITK_TREE_VIEW(tree_view), study); amitk_tree_view_expand_object(AMITK_TREE_VIEW(tree_view), AMITK_OBJECT(study)); /* make a scrolled area for the tree */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,250,-1); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), tree_view); gtk_table_attach(GTK_TABLE(table), scrolled, 2,3, 0, table_row,GTK_FILL, GTK_FILL | GTK_EXPAND, X_PADDING, Y_PADDING); /* and show all our widgets */ gtk_widget_show_all(dialog); return dialog; } amide-1.0.6/amide-current/src/ui_series.h000066400000000000000000000027111423227705100202670ustar00rootroot00000000000000/* ui_series.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __UI_SERIES_H__ #define __UI_SERIES_H__ /* header files that are always needed with this file */ #include #include "amitk_study.h" #define UI_SERIES_L_MARGIN 2.0 #define UI_SERIES_R_MARGIN UI_SERIES_L_MARGIN #define UI_SERIES_TOP_MARGIN 2.0 #define UI_SERIES_BOTTOM_MARGIN 15.0 /* external functions */ void ui_series_create(AmitkStudy * study, AmitkObject * active_object, GList * selected_objects, AmitkPreferences * preferences); GtkWidget * ui_series_init_dialog_create(AmitkStudy * study, GtkWindow * parent); #endif /* UI_SERIES_H */ amide-1.0.6/amide-current/src/ui_study.c000066400000000000000000002171071423227705100201470ustar00rootroot00000000000000/* ui_study.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "image.h" #include "ui_common.h" #include "ui_study.h" #include "ui_study_cb.h" #include "ui_gate_dialog.h" #include "ui_time_dialog.h" #include "amitk_tree_view.h" #include "amitk_canvas.h" #include "amitk_threshold.h" #include "amitk_progress_dialog.h" #include "amitk_common.h" #include "libmdc_interface.h" #define HELP_INFO_LINE_HEIGHT 13 #define LEFT_COLUMN_WIDTH 350 /* internal variables */ static gchar * help_info_legends[NUM_HELP_INFO_LINES] = { N_("m1"), N_("shift-m1"), N_("m2"), N_("shift-m2"), N_("m3"), N_("shift-m3"), N_("ctrl-m3"), "variable_place_holder" }; enum { HELP_INFO_VARIABLE_LINE_CTRL_X, HELP_INFO_VARIABLE_LINE_SHIFT_CTRL_3, NUM_HELP_INFO_VARIABLE_LINES }; static gchar * help_info_variable_legend[NUM_HELP_INFO_VARIABLE_LINES] = { N_("ctrl-x"), N_("shift-m3") }; static gchar * help_info_lines[][NUM_HELP_INFO_LINES] = { {"", "", "", "", "", "", "", ""}, /* BLANK */ {N_("move view"), N_("shift data set"), N_("move view, min. depth"), "", N_("change depth"), N_("rotate data set"), N_("add fiducial mark"), ""}, /* DATA SET */ {N_("shift"), "", N_("scale"), "", N_("rotate"), "", N_("set data set inside roi to zero"), N_("set data set outside roi to zero")}, /*CANVAS_ROI */ {N_("shift"), "", "", "", "", "", "", ""}, /*CANVAS_FIDUCIAL_MARK */ {N_("move view"), "", N_("move view, min. depth"), "", N_("change depth"), N_("rotate study"), "", ""}, /* STUDY */ {N_("shift"), "", N_("enter draw mode"), "", N_("start isocontour change"), "", N_("set data set inside roi to zero"), N_("set data set outside roi to zero")}, /*CANVAS_ISOCONTOUR_ROI */ {N_("shift"), "", N_("enter draw mode"), "", "", "", N_("set data set inside roi to zero"), N_("set data set outside roi to zero")}, /*CANVAS_FREEHAND_ROI */ {N_("draw point"),N_("draw large point"), N_("leave draw mode"), "", N_("erase point"), N_("erase large point"), "", ""}, /* CANVAS_DRAWING_MODE */ {N_("move line"), "", "", "", N_("rotate line"), "", "", ""}, /* CANVAS_LINE_PROFILE */ {N_("draw - edge-to-edge"), "", N_("draw - center out"), "", "", "", "", ""}, /* CANVAS_NEW_ROI */ {N_("pick isocontour start point"), "", "", "", "", "", "", ""}, /* CANVAS_NEW_ISOCONTOUR_ROI */ {N_("pick freehand drawing start point"), "", "", "", "", "", "", ""}, /* CANVAS_NEW_FREEHAND_ROI */ {N_("cancel"), "", "", "", N_("pick new isocontour"), "", "", ""}, /*CANVAS CHANGE ISOCONTOUR */ {N_("cancel"), "", "", "", N_("shift"), "", "", ""}, /*CANVAS SHIFT OBJECT */ {N_("cancel"), "", "", "", N_("rotate"), "", "", ""}, /*CANVAS ROTATE OBJECT */ {N_("select data set"), "", N_("make active"), "", N_("pop up data set dialog"), N_("add roi"), N_("add fiducial mark"), N_("delete data set")}, /* TREE_DATA_SET */ {N_("select roi"), "", N_("center view on roi"), "", N_("pop up roi dialog"), "", "", N_("delete roi")}, /* TREE_ROI */ {N_("select point"), "", N_("center view on point"), "", N_("pop up point dialog"), "", "", N_("delete mark")}, /* TREE_FIDUCIAL_MARK */ {"", "", N_("make active"), "", N_("pop up study dialog"),N_("add roi"), "", ""}, /* TREE_STUDY */ {"", "", "", "", N_("add roi"),"", "", ""} /* TREE_NONE */ }; static void update_interpolation_and_rendering(ui_study_t * ui_study); static void object_selection_changed_cb(AmitkObject * object, gpointer ui_study); static void study_name_changed_cb(AmitkObject * object, gpointer ui_study); static void object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer ui_study); static void object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer ui_study); static void add_object(ui_study_t * ui_study, AmitkObject * object); static void remove_object(ui_study_t * ui_study, AmitkObject * object); static void menus_toolbar_create(ui_study_t * ui_study); /* updates the settings of the interpolation radio button/rendering combo box, will not change canvas */ static void update_interpolation_and_rendering(ui_study_t * ui_study) { AmitkInterpolation i_interpolation; AmitkInterpolation interpolation; if (AMITK_IS_STUDY(ui_study->active_object)) { for (i_interpolation = 0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) gtk_action_set_sensitive(ui_study->interpolation_action[i_interpolation], FALSE); gtk_widget_set_sensitive(ui_study->rendering_menu, FALSE); } else if (AMITK_IS_DATA_SET(ui_study->active_object)) { for (i_interpolation = 0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) gtk_action_set_sensitive(ui_study->interpolation_action[i_interpolation], TRUE); gtk_widget_set_sensitive(ui_study->rendering_menu, TRUE); /* block signals, as we only want to change the value, it's up to the caller of this function to change anything on the actual canvases... we'll unblock at the end of this function */ for (i_interpolation = 0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) g_signal_handlers_block_by_func(G_OBJECT(ui_study->interpolation_action[i_interpolation]), G_CALLBACK(ui_study_cb_interpolation), ui_study); g_signal_handlers_block_by_func(G_OBJECT(ui_study->rendering_menu), G_CALLBACK(ui_study_cb_rendering), ui_study); interpolation = AMITK_DATA_SET_INTERPOLATION(ui_study->active_object); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(ui_study->interpolation_action[interpolation]), TRUE); gtk_combo_box_set_active(GTK_COMBO_BOX(ui_study->rendering_menu), AMITK_DATA_SET_RENDERING(ui_study->active_object)); for (i_interpolation = 0; i_interpolation < AMITK_INTERPOLATION_NUM; i_interpolation++) g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->interpolation_action[i_interpolation]), G_CALLBACK(ui_study_cb_interpolation), ui_study); g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->rendering_menu), G_CALLBACK(ui_study_cb_rendering), ui_study); } } static void object_selection_changed_cb(AmitkObject * object, gpointer data) { ui_study_t * ui_study = data; if (AMITK_IS_DATA_SET(object)) { if (ui_study->time_dialog != NULL) ui_time_dialog_set_times(ui_study->time_dialog); if (AMITK_IS_STUDY(ui_study->active_object) && amitk_object_get_selected(object, AMITK_SELECTION_ANY)) ui_study_make_active_object(ui_study, object); } return; } static void study_name_changed_cb(AmitkObject * object, gpointer data) { ui_study_t * ui_study = data; if (AMITK_IS_STUDY(object)) { ui_study_update_title(ui_study); } return; } static void object_add_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data ) { ui_study_t * ui_study = data; amide_real_t vox_size; g_return_if_fail(AMITK_IS_OBJECT(child)); add_object(ui_study, child); /* reset the view thickness if indicated */ if (AMITK_IS_DATA_SET(child)) { vox_size = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(ui_study->study)); amitk_study_set_view_thickness(ui_study->study, vox_size); } return; } static void object_remove_child_cb(AmitkObject * parent, AmitkObject * child, gpointer data) { ui_study_t * ui_study = data; g_return_if_fail(AMITK_IS_OBJECT(child)); remove_object(ui_study, child); return; } static void add_object(ui_study_t * ui_study, AmitkObject * object) { GList * children; AmitkViewMode i_view_mode; AmitkView i_view; amitk_object_ref(object); /* add a reference */ if (AMITK_IS_STUDY(object)) { /* save a ref to a study object */ if (ui_study->study != NULL) remove_object(ui_study, AMITK_OBJECT(ui_study->study)); ui_study->study = AMITK_STUDY(object); ui_study->active_object = AMITK_OBJECT(ui_study->study); ui_study->study_virgin=FALSE; /* set any settings we can */ ui_study_update_thickness(ui_study, AMITK_STUDY_VIEW_THICKNESS(object)); ui_study_update_zoom(ui_study); ui_study_update_fov(ui_study); ui_study_update_canvas_target(ui_study); ui_study_update_title(ui_study); ui_study_update_time_button(ui_study); ui_study_update_layout(ui_study); ui_study_update_canvas_visible_buttons(ui_study); ui_study_update_fuse_type(ui_study); ui_study_update_view_mode(ui_study); amitk_tree_view_set_study(AMITK_TREE_VIEW(ui_study->tree_view), AMITK_STUDY(object)); amitk_tree_view_expand_object(AMITK_TREE_VIEW(ui_study->tree_view), object); for (i_view_mode = 0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) for (i_view=0; i_view< AMITK_VIEW_NUM; i_view++) if (AMITK_STUDY_CANVAS_VISIBLE(object, i_view)) amitk_canvas_set_study(AMITK_CANVAS(ui_study->canvas[i_view_mode][i_view]), AMITK_STUDY(object)); g_signal_connect(G_OBJECT(object), "time_changed", G_CALLBACK(ui_study_cb_study_changed), ui_study); g_signal_connect(G_OBJECT(object), "filename_changed", G_CALLBACK(study_name_changed_cb), ui_study); g_signal_connect(G_OBJECT(object), "thickness_changed", G_CALLBACK(ui_study_cb_thickness_changed), ui_study); g_signal_connect(G_OBJECT(object), "object_name_changed", G_CALLBACK(study_name_changed_cb), ui_study); g_signal_connect(G_OBJECT(object), "canvas_visible_changed", G_CALLBACK(ui_study_cb_canvas_layout_changed), ui_study); g_signal_connect(G_OBJECT(object), "view_mode_changed", G_CALLBACK(ui_study_cb_canvas_layout_changed), ui_study); g_signal_connect(G_OBJECT(object), "canvas_target_changed", G_CALLBACK(ui_study_cb_study_changed), ui_study); g_signal_connect(G_OBJECT(object), "canvas_layout_preference_changed", G_CALLBACK(ui_study_cb_canvas_layout_changed), ui_study); g_signal_connect(G_OBJECT(object), "panel_layout_preference_changed", G_CALLBACK(ui_study_cb_canvas_layout_changed), ui_study); g_signal_connect(G_OBJECT(object), "voxel_dim_or_zoom_changed", G_CALLBACK(ui_study_cb_voxel_dim_or_zoom_changed), ui_study); g_signal_connect(G_OBJECT(object), "fov_changed", G_CALLBACK(ui_study_cb_fov_changed), ui_study); } else if (AMITK_IS_DATA_SET(object)) { amitk_tree_view_expand_object(AMITK_TREE_VIEW(ui_study->tree_view), AMITK_OBJECT_PARENT(object)); /* see if we should reset the study name */ if (AMITK_DATA_SET_SUBJECT_NAME(object) != NULL) amitk_study_suggest_name(ui_study->study, AMITK_DATA_SET_SUBJECT_NAME(object)); else amitk_study_suggest_name(ui_study->study, AMITK_OBJECT_NAME(object)); if (ui_study->study_altered != TRUE) { ui_study->study_altered=TRUE; ui_study->study_virgin=FALSE; ui_study_update_title(ui_study); } } g_signal_connect(G_OBJECT(object), "object_selection_changed", G_CALLBACK(object_selection_changed_cb), ui_study); g_signal_connect(G_OBJECT(object), "object_add_child", G_CALLBACK(object_add_child_cb), ui_study); g_signal_connect(G_OBJECT(object), "object_remove_child", G_CALLBACK(object_remove_child_cb), ui_study); /* add children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { add_object(ui_study, children->data); children = children->next; } return; } static void remove_object(ui_study_t * ui_study, AmitkObject * object) { GList * children; /* recursive remove children */ children = AMITK_OBJECT_CHILDREN(object); while (children != NULL) { remove_object(ui_study, children->data); children = children->next; } /* disconnect the object's signals */ if (AMITK_IS_STUDY(object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(ui_study_cb_study_changed), ui_study); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(ui_study_cb_thickness_changed), ui_study); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(ui_study_cb_canvas_layout_changed), ui_study); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(study_name_changed_cb), ui_study); } g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(object_selection_changed_cb), ui_study); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(object_add_child_cb), ui_study); g_signal_handlers_disconnect_by_func(G_OBJECT(object), G_CALLBACK(object_remove_child_cb), ui_study); /* close down the object's dialog if it's up */ if (object->dialog != NULL) { gtk_widget_destroy(GTK_WIDGET(object->dialog)); object->dialog = NULL; } /* and unref */ amitk_object_unref(object); return; } static const GtkActionEntry normal_items[] = { /* Toplevel */ { "FileMenu", NULL, N_("_File") }, { "EditMenu", NULL, N_("_Edit") }, { "ViewMenu", NULL, N_("_View") }, { "ToolsMenu", NULL, N_("_Tools") }, { "HelpMenu", NULL, N_("_Help") }, /* submenus */ { "ImportSpecificMenu", NULL, N_("Import File (_specify)")}, //N_("Import an image data file into this study, specifying the import type"), { "ExportView", NULL, N_("_Export View")}, //N_("Export one of the views to a picture file") { "AddRoi", NULL, N_("Add _ROI")}, //N_("Add a new ROI"), #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) { "FlyThrough",NULL,N_("Generate _Fly Through")}, //N_("generate an mpeg fly through of the data sets") #endif /* FileMenu */ { "NewStudy", GTK_STOCK_NEW, N_("_New Study"), NULL, N_("Create a new study viewer window"), G_CALLBACK(ui_study_cb_new_study)}, { "OpenXIFFile", GTK_STOCK_OPEN, N_("_Open Study"), NULL, N_("Open a previously saved study (XIF file)"), G_CALLBACK(ui_study_cb_open_xif_file)}, { "SaveAsXIFFile", GTK_STOCK_SAVE_AS, N_("Save Study As"), NULL, N_("Save current study (as a XIF file)"), G_CALLBACK(ui_study_cb_save_as_xif_file)}, { "ImportGuess", NULL, N_("Import File (guess)"), NULL, N_("Import an image data file into this study, guessing at the file type"),G_CALLBACK(ui_study_cb_import)}, { "ImportObject", NULL, N_("Import _Object from Study"),NULL, N_("Import an object, such as an ROI, from a preexisting study (XIF file)"),G_CALLBACK(ui_study_cb_import_object_from_xif_file)}, { "ExportDataSet", NULL, N_("Export _Data Set"),NULL,N_("Export data set(s) to a medical image format"),G_CALLBACK(ui_study_cb_export_data_set)}, { "RecoverXIFFile", NULL, N_("_Recover Study"),NULL,N_("Try to recover a corrupted XIF file"),G_CALLBACK(ui_study_cb_recover_xif_file)}, { "OpenXIFDir", NULL, N_("Open XIF Directory"), NULL, N_("Open a study stored in XIF directory format"), G_CALLBACK(ui_study_cb_open_xif_dir)}, { "SaveAsXIFDir", NULL, N_("Save As XIF Drectory"), NULL, N_("Save a study in XIF directory format"), G_CALLBACK(ui_study_cb_save_as_xif_dir)}, { "ImportFromXIFDir", NULL, N_("Import from XIF Directory"),NULL, N_("Import an object, such as an ROI, from a preexisting XIF directory"),G_CALLBACK(ui_study_cb_import_object_from_xif_dir)}, { "Close", GTK_STOCK_CLOSE, NULL, "W", N_("Close the current study"), G_CALLBACK (ui_study_cb_close)}, { "Quit", GTK_STOCK_QUIT, NULL, "Q", N_("Quit AMIDE"), G_CALLBACK (ui_study_cb_quit)}, /* ExportView Submenu */ { "ExportViewTransverse", NULL, N_("_Transverse"),NULL,N_("Export the current transaxial view to an image file (JPEG/TIFF/PNG/etc.)"),G_CALLBACK(ui_study_cb_export_view)}, { "ExportViewCoronal",NULL, N_("_Coronal"),NULL,N_("Export the current coronal view to an image file (JPEG/TIFF/PNG/etc.)"),G_CALLBACK(ui_study_cb_export_view)}, { "ExportViewSagittal",NULL, N_("_Sagittal"),NULL,N_("Export the current sagittal view to an image file (JPEG/TIFF/PNG/etc.)"),G_CALLBACK(ui_study_cb_export_view)}, /* EditMenu */ { "AddFiducial", NULL, N_("Add _Fiducial Mark"),NULL,N_("Add a new fiducial mark to the active data set"),G_CALLBACK(ui_study_cb_add_fiducial_mark)}, { "Preferences", GTK_STOCK_PREFERENCES,NULL, NULL,NULL,G_CALLBACK(ui_study_cb_preferences)}, /* ViewMenu */ { "ViewSeries", NULL, N_("_Series"),NULL,N_("Look at a series of images"), G_CALLBACK(ui_study_cb_series)}, #if AMIDE_LIBVOLPACK_SUPPORT { "ViewRendering",NULL,N_("_Volume Rendering"),NULL,N_("perform a volume rendering on the currently selected objects"),G_CALLBACK(ui_study_cb_render)}, #endif /* ToolsMenu */ { "AlignmentWizard",NULL,N_("_Alignment Wizard"),NULL,N_("guides you throw the processing of alignment"),G_CALLBACK(ui_study_cb_alignment_selected)}, { "CropWizard",NULL,N_("_Crop Active Data Set"),NULL,N_("allows you to crop the active data set"),G_CALLBACK(ui_study_cb_crop_selected)}, { "DistanceWizard",NULL,N_("Distance Measurements"),NULL,N_("calculate distances between fiducial marks and ROIs"),G_CALLBACK(ui_study_cb_distance_selected)}, { "FactorAnalysisWizard", NULL,N_("_Factor Analysis"),NULL,N_("allows you to do factor analysis of dynamic data on the active data set"),G_CALLBACK(ui_study_cb_fads_selected)}, { "FilterWizard",NULL,N_("_Filter Active Data Set"),NULL,N_("allows you to filter the active data set"),G_CALLBACK(ui_study_cb_filter_selected)}, { "LineProfile",NULL,N_("Generate Line _Profile"),NULL,N_("allows generating a line profile between two fiducial marks"),G_CALLBACK(ui_study_cb_profile_selected)}, { "MathWizard",NULL,N_("Perform _Math on Data Set(s)"),NULL,N_("perform simple math operations on a data set or between data sets"),G_CALLBACK(ui_study_cb_data_set_math_selected)}, { "RoiStats",NULL,N_("Calculate _ROI Statistics"),NULL,N_("caculate ROI statistics"),G_CALLBACK(ui_study_cb_roi_statistics)}, /* Flythrough Submenu */ #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) { "FlyThroughTransverse",NULL,N_("_Transverse"),NULL,N_("Generate a fly through using transaxial slices"),G_CALLBACK(ui_study_cb_fly_through)}, { "FlyThroughCoronal",NULL,N_("_Coronal"),NULL,N_("Generate a fly through using coronal slices"),G_CALLBACK(ui_study_cb_fly_through)}, { "FlyThroughSagittal",NULL,N_("_Sagittal"),NULL,N_("Generate a fly through using sagittal slices"),G_CALLBACK(ui_study_cb_fly_through)}, #endif /* Toolbar items */ { "Thresholding", "amide_icon_thresholding", N_("_Threshold"),NULL,N_("Set the thresholds and colormaps for the active data set"), G_CALLBACK(ui_study_cb_thresholding)}, }; static const GtkRadioActionEntry interpolation_radio_entries[AMITK_INTERPOLATION_NUM] = { { "InterpolationNearestNeighbor", "amide_icon_interpolation_nearest_neighbor", N_("Near."), NULL, N_("interpolate using nearest neighbor (fast)"),AMITK_INTERPOLATION_NEAREST_NEIGHBOR}, { "InterpolationTrilinear", "amide_icon_interpolation_trilinear", N_("Tri."), NULL, N_("interpolate using trilinear interpolation (slow)"), AMITK_INTERPOLATION_TRILINEAR}, }; static const GtkRadioActionEntry fuse_type_radio_entries[AMITK_FUSE_TYPE_NUM] = { { "FuseTypeBlend", "amide_icon_fuse_type_blend", N_("Blend"), NULL, N_("blend all data sets"), AMITK_FUSE_TYPE_BLEND }, { "FuseTypeOverlay", "amide_icon_fuse_type_overlay", N_("Overlay"), NULL, N_("overlay active data set on blended data sets"),AMITK_FUSE_TYPE_OVERLAY }, }; static const GtkRadioActionEntry view_mode_radio_entries[AMITK_VIEW_MODE_NUM] = { { "CanvasViewModeSingle", "amide_icon_view_mode_single", N_("Single"), NULL, N_("All objects are shown in a single view"),AMITK_VIEW_MODE_SINGLE }, { "CanvasViewModeLinked2Way", "amide_icon_view_mode_linked_2way", N_("2-way"), NULL,N_("Objects are shown between 2 linked views"), AMITK_VIEW_MODE_LINKED_2WAY }, { "CanvasViewModeLinked3Way", "amide_icon_view_mode_linked_3way", N_("3-way"), NULL,N_("Objects are shown between 3 linked views"), AMITK_VIEW_MODE_LINKED_3WAY }, }; /* Toggle items */ static const GtkToggleActionEntry toggle_entries[] = { { "CanvasTarget", "amide_icon_canvas_target", N_("Target"), NULL, N_("Leave crosshairs on views"), G_CALLBACK(ui_study_cb_canvas_target), FALSE}, { "CanvasViewTransverse", "amide_icon_view_transverse", N_("Transverse"), NULL, N_("Enable transverse view"), G_CALLBACK(ui_study_cb_canvas_visible), FALSE}, { "CanvasViewCoronal", "amide_icon_view_coronal", N_("Coronal"), NULL, N_("Enable coronal view"), G_CALLBACK(ui_study_cb_canvas_visible), FALSE}, { "CanvasViewSagittal", "amide_icon_view_sagittal", N_("Sagittal"), NULL, N_("Enable sagittal view"), G_CALLBACK(ui_study_cb_canvas_visible), FALSE}, }; static const char *ui_description = "" " " " " " " " " " " " " " " " " /* filled in the function */ " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " /* filled in the function */ " " " " " " " " " " " " " " #if AMIDE_LIBVOLPACK_SUPPORT " " #endif " " " " " " " " " " " " " " #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) " " " " " " " " " " #endif " " " " " " " " HELP_MENU_UI_DESCRIPTION " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " /*" " */ /* " " */ " " ""; /* function to setup the menus for the study ui */ static void menus_toolbar_create(ui_study_t * ui_study) { GtkWidget *menubar; GtkWidget *toolbar; GtkActionGroup *action_group; GtkUIManager *ui_manager; GtkAccelGroup *accel_group; GError *error; GtkWidget * label; AmitkImportMethod i_import_method; AmitkRendering i_rendering; GtkAction * action; GtkWidget * menu; GtkWidget * submenu; GtkWidget * menu_item; #ifdef AMIDE_LIBMDC_SUPPORT libmdc_import_t i_libmdc_import; #endif AmitkRoiType i_roi_type; GtkObject * adjustment; GtkWidget * placeholder; g_assert(ui_study!=NULL); /* sanity check */ /* create an action group with all the menu actions */ action_group = gtk_action_group_new ("MenuActions"); gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions(action_group, normal_items, G_N_ELEMENTS(normal_items),ui_study); gtk_action_group_add_actions(action_group, ui_common_help_menu_items, G_N_ELEMENTS(ui_common_help_menu_items),ui_study); gtk_action_group_add_toggle_actions(action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), ui_study); gtk_action_group_add_radio_actions(action_group, interpolation_radio_entries, G_N_ELEMENTS (interpolation_radio_entries), 0, G_CALLBACK(ui_study_cb_interpolation), ui_study); gtk_action_group_add_radio_actions(action_group, fuse_type_radio_entries, G_N_ELEMENTS (fuse_type_radio_entries), 0, G_CALLBACK(ui_study_cb_fuse_type), ui_study); gtk_action_group_add_radio_actions(action_group, view_mode_radio_entries, G_N_ELEMENTS (view_mode_radio_entries), 0, G_CALLBACK(ui_study_cb_view_mode), ui_study); /* create the ui manager, and add the actions and accel's */ ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); accel_group = gtk_ui_manager_get_accel_group (ui_manager); gtk_window_add_accel_group (ui_study->window, accel_group); /* create the actual menu/toolbar ui */ error = NULL; if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &error)) { g_warning ("%s: building menus failed in %s: %s", PACKAGE, __FILE__, error->message); g_error_free (error); return; } /* set additional info so we can tell the menus apart */ g_object_set_data(G_OBJECT(gtk_action_group_get_action (action_group, "ExportViewTransverse")), "view", GINT_TO_POINTER(AMITK_VIEW_TRANSVERSE)); g_object_set_data(G_OBJECT(gtk_action_group_get_action (action_group, "ExportViewCoronal")), "view", GINT_TO_POINTER(AMITK_VIEW_CORONAL)); g_object_set_data(G_OBJECT(gtk_action_group_get_action (action_group, "ExportViewSagittal")), "view", GINT_TO_POINTER(AMITK_VIEW_SAGITTAL)); #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) g_object_set_data(G_OBJECT(gtk_action_group_get_action (action_group, "FlyThroughTransverse")), "view", GINT_TO_POINTER(AMITK_VIEW_TRANSVERSE)); g_object_set_data(G_OBJECT(gtk_action_group_get_action (action_group, "FlyThroughCoronal")), "view", GINT_TO_POINTER(AMITK_VIEW_CORONAL)); g_object_set_data(G_OBJECT(gtk_action_group_get_action (action_group, "FlyThroughSagittal")), "view", GINT_TO_POINTER(AMITK_VIEW_SAGITTAL)); #endif /* build the import menu */ submenu = gtk_menu_new(); for (i_import_method = AMITK_IMPORT_METHOD_RAW; i_import_method < AMITK_IMPORT_METHOD_NUM; i_import_method++) { #ifdef AMIDE_LIBMDC_SUPPORT if (i_import_method == AMITK_IMPORT_METHOD_LIBMDC) { for (i_libmdc_import = 0; i_libmdc_import < LIBMDC_NUM_IMPORT_METHODS; i_libmdc_import++) { if (libmdc_supports(libmdc_import_to_format[i_libmdc_import])) { menu_item = gtk_menu_item_new_with_mnemonic(libmdc_import_menu_names[i_libmdc_import]); /* if tooltip support existed - libmdc_import_menu_explanations[i_libmdc_import] */ gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menu_item); g_object_set_data(G_OBJECT(menu_item), "method", GINT_TO_POINTER(i_import_method)); g_object_set_data(G_OBJECT(menu_item), "submethod", GINT_TO_POINTER(libmdc_import_to_format[i_libmdc_import])); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(ui_study_cb_import), ui_study); gtk_widget_show(menu_item); } } } else #endif { menu_item = gtk_menu_item_new_with_mnemonic(amitk_import_menu_names[i_import_method]); /* if tooltip support existed - amitk_import_menu_explanations[i_import_method] */ gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menu_item); g_object_set_data(G_OBJECT(menu_item), "method", GINT_TO_POINTER(i_import_method)); g_object_set_data(G_OBJECT(menu_item), "submethod", GINT_TO_POINTER(0)); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(ui_study_cb_import), ui_study); gtk_widget_show(menu_item); } } menu = gtk_ui_manager_get_widget(ui_manager, "ui/MainMenu/FileMenu/ImportSpecificMenu"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu), submenu); gtk_widget_show(submenu); gtk_widget_show(menu); /* build the add roi menu */ submenu = gtk_menu_new(); for (i_roi_type=0; i_roi_typeinterpolation_action[AMITK_INTERPOLATION_NEAREST_NEIGHBOR] = gtk_action_group_get_action(action_group, "InterpolationNearestNeighbor"); ui_study->interpolation_action[AMITK_INTERPOLATION_TRILINEAR] = gtk_action_group_get_action(action_group, "InterpolationTrilinear"); g_assert(AMITK_INTERPOLATION_TRILINEAR+1 == AMITK_INTERPOLATION_NUM); /* make sure we handle all types */ ui_study->fuse_type_action[AMITK_FUSE_TYPE_BLEND] = gtk_action_group_get_action(action_group, "FuseTypeBlend"); ui_study->fuse_type_action[AMITK_FUSE_TYPE_OVERLAY] = gtk_action_group_get_action(action_group, "FuseTypeOverlay"); g_assert(AMITK_FUSE_TYPE_OVERLAY+1 == AMITK_FUSE_TYPE_NUM); /* make sure we handle all types */ ui_study->view_mode_action[AMITK_VIEW_MODE_SINGLE] = gtk_action_group_get_action(action_group, "CanvasViewModeSingle"); ui_study->view_mode_action[AMITK_VIEW_MODE_LINKED_2WAY] = gtk_action_group_get_action(action_group, "CanvasViewModeLinked2Way"); ui_study->view_mode_action[AMITK_VIEW_MODE_LINKED_3WAY] = gtk_action_group_get_action(action_group, "CanvasViewModeLinked3Way"); g_assert(AMITK_VIEW_MODE_LINKED_3WAY+1 == AMITK_VIEW_MODE_NUM); /* make sure we handle all types */ ui_study->canvas_target_action = gtk_action_group_get_action(action_group, "CanvasTarget"); action = gtk_action_group_get_action(action_group, "CanvasViewTransverse"); ui_study->canvas_visible_action[AMITK_VIEW_TRANSVERSE] = action; g_object_set_data(G_OBJECT(action), "view", GINT_TO_POINTER(AMITK_VIEW_TRANSVERSE)); action = gtk_action_group_get_action(action_group, "CanvasViewCoronal"); ui_study->canvas_visible_action[AMITK_VIEW_CORONAL] = action; g_object_set_data(G_OBJECT(action), "view", GINT_TO_POINTER(AMITK_VIEW_CORONAL)); action = gtk_action_group_get_action(action_group, "CanvasViewSagittal"); ui_study->canvas_visible_action[AMITK_VIEW_SAGITTAL] = action; g_object_set_data(G_OBJECT(action), "view", GINT_TO_POINTER(AMITK_VIEW_SAGITTAL)); /* pack in the menu and toolbar */ menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu"); gtk_box_pack_start (GTK_BOX (ui_study->window_vbox), menubar, FALSE, FALSE, 0); toolbar = gtk_ui_manager_get_widget (ui_manager, "/ToolBar"); gtk_box_pack_start (GTK_BOX (ui_study->window_vbox), toolbar, FALSE, FALSE, 0); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), FALSE); /* insert the rendering menu into the toolbar */ placeholder = gtk_ui_manager_get_widget (ui_manager, "/ToolBar/RenderingCombo"); ui_study->rendering_menu = gtk_combo_box_new_text(); /* gtk_widget_set_tooltip_text(ui_study->rendering_menu, _(amitk_rendering_explanation)); combo box's (as of 2.24 at least, don't have functioning tool tips */ for (i_rendering = 0; i_rendering < AMITK_RENDERING_NUM; i_rendering++) gtk_combo_box_append_text(GTK_COMBO_BOX(ui_study->rendering_menu), amitk_rendering_get_name(i_rendering)); g_signal_connect(G_OBJECT(ui_study->rendering_menu), "changed", G_CALLBACK(ui_study_cb_rendering), ui_study); ui_common_toolbar_insert_widget(toolbar, ui_study->rendering_menu, "", gtk_toolbar_get_item_index(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(placeholder))); /* and finish off the rest of the toolbar */ /* starting with a separator for clarity */ ui_common_toolbar_append_separator(toolbar); /* add the zoom widget to our toolbar */ label = gtk_label_new(_("zoom:")); ui_common_toolbar_append_widget(toolbar, label, NULL); ui_study->zoom_spin = gtk_spin_button_new_with_range(AMIDE_LIMIT_ZOOM_LOWER, AMIDE_LIMIT_ZOOM_UPPER, AMIDE_LIMIT_ZOOM_STEP); gtk_widget_set_size_request(ui_study->zoom_spin, 50,-1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ui_study->zoom_spin), 3); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ui_study->zoom_spin),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(ui_study->zoom_spin), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_study->zoom_spin), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(ui_study->zoom_spin), GTK_UPDATE_ALWAYS); g_signal_connect(G_OBJECT(ui_study->zoom_spin), "value_changed",G_CALLBACK(ui_study_cb_zoom), ui_study); g_signal_connect(G_OBJECT(ui_study->zoom_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(ui_study->zoom_spin), "button_press_event", G_CALLBACK(amitk_spin_button_discard_double_or_triple_click), NULL); ui_common_toolbar_append_widget(toolbar,ui_study->zoom_spin,_("specify how much to magnify the images")); /* a separator for clarity */ ui_common_toolbar_append_separator(toolbar); /* add the field of view widget to our toolbar */ label = gtk_label_new(_("fov (%):")); ui_common_toolbar_append_widget(toolbar, label, NULL); ui_study->fov_spin = gtk_spin_button_new_with_range(AMIDE_LIMIT_FOV_LOWER, AMIDE_LIMIT_FOV_UPPER, AMIDE_LIMIT_FOV_STEP); gtk_widget_set_size_request(ui_study->fov_spin, 50,-1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ui_study->fov_spin), 0); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ui_study->fov_spin),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(ui_study->fov_spin), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_study->fov_spin), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(ui_study->fov_spin), GTK_UPDATE_ALWAYS); g_signal_connect(G_OBJECT(ui_study->fov_spin), "value_changed", G_CALLBACK(ui_study_cb_fov), ui_study); g_signal_connect(G_OBJECT(ui_study->fov_spin), "button_press_event", G_CALLBACK(amitk_spin_button_discard_double_or_triple_click), NULL); ui_common_toolbar_append_widget(toolbar,ui_study->fov_spin,_("specify how much of the image field of view to display")); /* a separator for clarity */ ui_common_toolbar_append_separator(toolbar); /* add the slice thickness selector */ label = gtk_label_new(_("thickness (mm):")); ui_common_toolbar_append_widget(toolbar, label, NULL); adjustment = gtk_adjustment_new(1.0, 0.2, G_MAXDOUBLE, 0.2, 0.2, 0.0); ui_study->thickness_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjustment),1.0, 3); gtk_widget_set_size_request (ui_study->thickness_spin, 60, -1); gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(ui_study->thickness_spin),FALSE); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(ui_study->thickness_spin), FALSE); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(ui_study->thickness_spin), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(ui_study->thickness_spin), GTK_UPDATE_ALWAYS); g_signal_connect(G_OBJECT(ui_study->thickness_spin), "value_changed", G_CALLBACK(ui_study_cb_thickness), ui_study); g_signal_connect(G_OBJECT(ui_study->thickness_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); g_signal_connect(G_OBJECT(ui_study->thickness_spin), "button_press_event", G_CALLBACK(amitk_spin_button_discard_double_or_triple_click), NULL); ui_common_toolbar_append_widget(toolbar,ui_study->thickness_spin,_("specify how thick to make the slices (mm)")); /* a separator for clarity */ ui_common_toolbar_append_separator(toolbar); /* gate */ /* note, can't use gtk_tool_button, as no way to set the relief in gtk 2.10, and the default is no relief so you can't tell that it's a button.... - */ label = gtk_label_new(_("gate:")); ui_common_toolbar_append_widget(toolbar, label, NULL); ui_study->gate_button = gtk_button_new_with_label("?"); g_signal_connect(G_OBJECT(ui_study->gate_button), "clicked", G_CALLBACK(ui_study_cb_gate), ui_study); ui_common_toolbar_append_widget(toolbar, ui_study->gate_button, _("the gate range over which to view the data")); /* a separator for clarity */ ui_common_toolbar_append_separator(toolbar); /* frame selector */ label = gtk_label_new(_("time:")); ui_common_toolbar_append_widget(toolbar, label, NULL); ui_study->time_button = gtk_button_new_with_label("?"); g_signal_connect(G_OBJECT(ui_study->time_button), "clicked", G_CALLBACK(ui_study_cb_time), ui_study); ui_common_toolbar_append_widget(toolbar, ui_study->time_button, _("the time range over which to view the data (s)")); return; } /* destroy a ui_study data structure */ ui_study_t * ui_study_free(ui_study_t * ui_study) { gboolean return_val; if (ui_study == NULL) return ui_study; /* sanity checks */ g_return_val_if_fail(ui_study->reference_count > 0, NULL); /* remove a reference count */ ui_study->reference_count--; /* if we've removed all reference's, free the structure */ if (ui_study->reference_count == 0) { /* these two lines forces any remaining spin button updates, so that we don't call any spin button callbacks with invalid data */ gtk_widget_grab_focus(GTK_WIDGET(ui_study->window)); while (gtk_events_pending()) gtk_main_iteration(); #ifdef AMIDE_DEBUG g_print("freeing ui_study\n"); #endif if (ui_study->study != NULL) { remove_object(ui_study, AMITK_OBJECT(ui_study->study)); ui_study->study = NULL; } if (ui_study->progress_dialog != NULL) { g_signal_emit_by_name(G_OBJECT(ui_study->progress_dialog), "delete_event", NULL, &return_val); ui_study->progress_dialog = NULL; } if (ui_study->preferences != NULL) { g_object_unref(ui_study->preferences); ui_study->preferences = NULL; } g_free(ui_study); ui_study = NULL; } return ui_study; } /* allocate and initialize a ui_study data structure */ ui_study_t * ui_study_init(AmitkPreferences * preferences) { ui_study_t * ui_study; AmitkViewMode i_view_mode; AmitkView i_view; help_info_line_t i_line; /* alloc space for the data structure for passing ui info */ ui_study = g_try_new(ui_study_t,1); g_return_val_if_fail(ui_study != NULL, NULL); ui_study->reference_count = 1; ui_study->study = NULL; ui_study->threshold_dialog = NULL; ui_study->gate_dialog = NULL; ui_study->time_dialog = NULL; ui_study->thickness_spin = NULL; ui_study->active_object = NULL; for (i_view_mode=0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { ui_study->canvas_table[i_view_mode] = NULL; for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) { ui_study->canvas[i_view_mode][i_view] = NULL; } } ui_study->study_altered=FALSE; ui_study->study_virgin=TRUE; for (i_line=0 ;i_line < NUM_HELP_INFO_LINES;i_line++) { ui_study->help_line[i_line] = NULL; ui_study->help_legend[i_line] = NULL; } ui_study->preferences = g_object_ref(preferences); return ui_study; } /* if object is NULL, it'll do its best guess */ void ui_study_make_active_object(ui_study_t * ui_study, AmitkObject * object) { AmitkView i_view; GList * current_objects; AmitkViewMode i_view_mode; g_return_if_fail(ui_study->study != NULL); g_return_if_fail(ui_study->active_object != NULL); if (AMITK_IS_DATA_SET(ui_study->active_object)) { g_signal_handlers_disconnect_by_func(G_OBJECT(ui_study->active_object), G_CALLBACK(update_interpolation_and_rendering), ui_study); g_signal_handlers_disconnect_by_func(G_OBJECT(ui_study->active_object), G_CALLBACK(ui_study_update_gate_button), ui_study); } ui_study->active_object = object; if (object == NULL) { /* guessing */ /* find visible data set to make active object */ for (i_view_mode = 0; (i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study)) && (ui_study->active_object == NULL); i_view_mode++) { current_objects = amitk_object_get_selected_children_of_type(AMITK_OBJECT(ui_study->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_VIEW_MODE_SINGLE+i_view_mode, TRUE); if (current_objects != NULL) { ui_study->active_object = AMITK_OBJECT(current_objects->data); amitk_objects_unref(current_objects); } } if (ui_study->active_object == NULL) /* study as backup */ ui_study->active_object = AMITK_OBJECT(ui_study->study); } /* indicate this is now the active object */ amitk_tree_view_set_active_object(AMITK_TREE_VIEW(ui_study->tree_view), ui_study->active_object); /* connect any needed signals */ if (AMITK_IS_DATA_SET(ui_study->active_object)) { g_signal_connect_swapped(G_OBJECT(ui_study->active_object), "interpolation_changed", G_CALLBACK(update_interpolation_and_rendering), ui_study); g_signal_connect_swapped(G_OBJECT(ui_study->active_object), "rendering_changed", G_CALLBACK(update_interpolation_and_rendering), ui_study); g_signal_connect_swapped(G_OBJECT(ui_study->active_object), "view_gates_changed", G_CALLBACK(ui_study_update_gate_button), ui_study); } update_interpolation_and_rendering(ui_study); for (i_view_mode = 0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) for (i_view=0; i_view< AMITK_VIEW_NUM; i_view++) if (ui_study->canvas[i_view_mode][i_view] != NULL) amitk_canvas_set_active_object(AMITK_CANVAS(ui_study->canvas[i_view_mode][i_view]), ui_study->active_object); /* reset the threshold widget based on the current data set */ if (ui_study->threshold_dialog != NULL) { if (AMITK_IS_STUDY(ui_study->active_object)) { gtk_widget_destroy(ui_study->threshold_dialog); ui_study->threshold_dialog = NULL; } else if (AMITK_IS_DATA_SET(ui_study->active_object)) { amitk_threshold_dialog_new_data_set(AMITK_THRESHOLD_DIALOG(ui_study->threshold_dialog), AMITK_DATA_SET(ui_study->active_object)); } } if (ui_study->gate_dialog != NULL) { if (AMITK_IS_DATA_SET(ui_study->active_object)) ui_gate_dialog_set_active_data_set(ui_study->gate_dialog, AMITK_DATA_SET(ui_study->active_object)); else ui_gate_dialog_set_active_data_set(ui_study->gate_dialog, NULL); } ui_study_update_gate_button(ui_study); } /* function for adding a fiducial mark */ void ui_study_add_fiducial_mark(ui_study_t * ui_study, AmitkObject * parent_object, gboolean selected, AmitkPoint position) { GtkWidget * dialog; gint return_val; AmitkFiducialMark * new_pt=NULL; gchar * temp_string; gchar * return_str=NULL; g_return_if_fail(AMITK_IS_OBJECT(parent_object)); temp_string = g_strdup_printf(_("Adding fiducial mark for data set: %s\nEnter the mark's name:"), AMITK_OBJECT_NAME(parent_object)); dialog = ui_common_entry_dialog(ui_study->window, temp_string, &return_str); return_val = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); g_free(temp_string); if (return_val == GTK_RESPONSE_OK) { new_pt = amitk_fiducial_mark_new(); amitk_space_copy_in_place(AMITK_SPACE(new_pt), AMITK_SPACE(parent_object)); amitk_fiducial_mark_set(new_pt, position); amitk_object_set_name(AMITK_OBJECT(new_pt), return_str); amitk_object_add_child(AMITK_OBJECT(parent_object), AMITK_OBJECT(new_pt)); amitk_tree_view_expand_object(AMITK_TREE_VIEW(ui_study->tree_view), AMITK_OBJECT(parent_object)); amitk_object_unref(new_pt); /* don't want an extra ref */ if (selected) amitk_object_set_selected(AMITK_OBJECT(new_pt), TRUE, AMITK_SELECTION_SELECTED_0); if (ui_study->study_altered != TRUE) { ui_study->study_virgin=FALSE; ui_study->study_altered=TRUE; ui_study_update_title(ui_study); } } if (return_str != NULL) g_free(return_str); return; } void ui_study_add_roi(ui_study_t * ui_study, AmitkObject * parent_object, AmitkRoiType roi_type) { GtkWidget * dialog; gint return_val; AmitkRoi * roi; gchar * temp_string; gchar * return_str=NULL; AmitkViewMode i_view_mode; g_return_if_fail(AMITK_IS_OBJECT(parent_object)); temp_string = g_strdup_printf(_("Adding ROI to: %s\nEnter ROI Name:"), AMITK_OBJECT_NAME(parent_object)); dialog = ui_common_entry_dialog(ui_study->window, temp_string, &return_str); return_val = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); g_free(temp_string); if (return_val == GTK_RESPONSE_OK) { roi = amitk_roi_new(roi_type); amitk_object_set_name(AMITK_OBJECT(roi), return_str); amitk_object_add_child(parent_object, AMITK_OBJECT(roi)); amitk_object_unref(roi); /* don't want an extra ref */ if (AMITK_ROI_UNDRAWN(roi)) /* undrawn roi's selected to begin with*/ for (i_view_mode = 0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) amitk_object_set_selected(AMITK_OBJECT(roi), TRUE, i_view_mode); if (ui_study->study_altered != TRUE) { ui_study->study_altered=TRUE; ui_study->study_virgin=FALSE; ui_study_update_title(ui_study); } } if (return_str != NULL) g_free(return_str); return; } void ui_study_update_canvas_visible_buttons(ui_study_t * ui_study) { AmitkView i_view; for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) { g_signal_handlers_block_by_func(G_OBJECT(ui_study->canvas_visible_action[i_view]), G_CALLBACK(ui_study_cb_canvas_visible), ui_study); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(ui_study->canvas_visible_action[i_view]), AMITK_STUDY_CANVAS_VISIBLE(ui_study->study, i_view)); g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->canvas_visible_action[i_view]), G_CALLBACK(ui_study_cb_canvas_visible), ui_study); } return; } /* function to update the text in the gate dialog popup widget */ void ui_study_update_gate_button(ui_study_t * ui_study) { gchar * temp_string; if (AMITK_IS_DATA_SET(ui_study->active_object)) temp_string = g_strdup_printf(_("%d-%d"), AMITK_DATA_SET_VIEW_START_GATE(ui_study->active_object), AMITK_DATA_SET_VIEW_END_GATE(ui_study->active_object)); else temp_string = g_strdup_printf(_("N/A")); gtk_button_set_label(GTK_BUTTON(ui_study->gate_button),temp_string); g_free(temp_string); return; } /* function to update the text in the time dialog popup widget */ void ui_study_update_time_button(ui_study_t * ui_study) { gchar * temp_string; temp_string = g_strdup_printf(_("%g-%g s"), AMITK_STUDY_VIEW_START_TIME(ui_study->study), AMITK_STUDY_VIEW_START_TIME(ui_study->study)+ AMITK_STUDY_VIEW_DURATION(ui_study->study)); gtk_button_set_label(GTK_BUTTON(ui_study->time_button),temp_string); g_free(temp_string); return; } /* This function updates the little info box which tells us what the different mouse buttons will do */ void ui_study_update_help_info(ui_study_t * ui_study, AmitkHelpInfo which_info, AmitkPoint point, amide_data_t value) { help_info_line_t i_line; gchar * location_text[2]; gchar * legend; AmitkPoint location_p; gchar * help_info_line; /* put up the help lines... except for the given info types, in which case we leave the last one displayed up */ if ((which_info != AMITK_HELP_INFO_UPDATE_LOCATION) && (which_info != AMITK_HELP_INFO_UPDATE_SHIFT) && (which_info != AMITK_HELP_INFO_UPDATE_THETA)) { for (i_line=0; i_line < HELP_INFO_LINE_BLANK;i_line++) { /* the line's legend */ if (strlen(help_info_lines[which_info][i_line]) > 0) { if (i_line == HELP_INFO_LINE_VARIABLE) { if ((which_info == AMITK_HELP_INFO_CANVAS_ROI) || (which_info == AMITK_HELP_INFO_CANVAS_ISOCONTOUR_ROI) || (which_info == AMITK_HELP_INFO_CANVAS_FREEHAND_ROI)) { legend = _(help_info_variable_legend[HELP_INFO_VARIABLE_LINE_SHIFT_CTRL_3]); } else { legend = _(help_info_variable_legend[HELP_INFO_VARIABLE_LINE_CTRL_X]); } } else { legend = _(help_info_legends[i_line]); } } else { legend = ""; } if (ui_study->help_legend[i_line] == NULL) ui_study->help_legend[i_line] = gnome_canvas_item_new(gnome_canvas_root(ui_study->help_info), gnome_canvas_text_get_type(), "justification", GTK_JUSTIFY_RIGHT, "anchor", GTK_ANCHOR_NORTH_EAST, "text", legend, "x", (gdouble) 55.0, "y", (gdouble) (i_line*HELP_INFO_LINE_HEIGHT), "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); else /* just need to change the text */ gnome_canvas_item_set(ui_study->help_legend[i_line], "text", legend, NULL); /* gettext can't handle "" */ if (g_strcmp0(help_info_lines[which_info][i_line],"") != 0) help_info_line = _(help_info_lines[which_info][i_line]); else help_info_line = help_info_lines[which_info][i_line]; /* and the button info */ if (ui_study->help_line[i_line] == NULL) ui_study->help_line[i_line] = gnome_canvas_item_new(gnome_canvas_root(ui_study->help_info), gnome_canvas_text_get_type(), "justification", GTK_JUSTIFY_LEFT, "anchor", GTK_ANCHOR_NORTH_WEST, "text", help_info_line, "x", (gdouble) 65.0, "y", (gdouble) (i_line*HELP_INFO_LINE_HEIGHT), "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); else /* just need to change the text */ gnome_canvas_item_set(ui_study->help_line[i_line], "text", help_info_line, NULL); } } /* update the location information */ if ((which_info == AMITK_HELP_INFO_UPDATE_LOCATION) || (which_info == AMITK_HELP_INFO_CANVAS_DRAWING_MODE)) { location_text[0] = g_strdup_printf(_("[x,y,z] = [% 5.2f,% 5.2f,% 5.2f] mm"), point.x, point.y, point.z); if (!isnan(value)) location_text[1] = g_strdup_printf(_("value = % 5.3g"), value); else location_text[1] = g_strdup_printf(_("value = none")); } else if (which_info == AMITK_HELP_INFO_UPDATE_SHIFT) { location_text[0] = g_strdup_printf(_("shift (x,y,z) =")); location_text[1] = g_strdup_printf(_("[% 5.2f,% 5.2f,% 5.2f] mm"), point.x, point.y, point.z); } else if (which_info == AMITK_HELP_INFO_UPDATE_THETA) { location_text[0] = g_strdup(""); location_text[1] = g_strdup_printf(_("theta = % 5.3f degrees"), value); } else { location_p = AMITK_STUDY_VIEW_CENTER(ui_study->study); location_text[0] = g_strdup_printf(_("view center (x,y,z) =")); location_text[1] = g_strdup_printf(_("[% 5.2f,% 5.2f,% 5.2f] mm"), location_p.x, location_p.y, location_p.z); } /* update the location display */ for (i_line=HELP_INFO_LINE_LOCATION1; i_line <= HELP_INFO_LINE_LOCATION2;i_line++) { if (ui_study->help_line[i_line] == NULL) ui_study->help_line[i_line] = gnome_canvas_item_new(gnome_canvas_root(ui_study->help_info), gnome_canvas_text_get_type(), "justification", GTK_JUSTIFY_LEFT, "anchor", GTK_ANCHOR_NORTH_WEST, "text", location_text[i_line-HELP_INFO_LINE_LOCATION1], "x", (gdouble) 2.0, "y", (gdouble) (i_line*HELP_INFO_LINE_HEIGHT), "fill_color", "black", "font_desc", amitk_fixed_font_desc, NULL); else /* just need to change the text */ gnome_canvas_item_set(ui_study->help_line[i_line], "text", location_text[i_line-HELP_INFO_LINE_LOCATION1], NULL); g_free(location_text[i_line-HELP_INFO_LINE_LOCATION1]); } return; } /* updates the settings of the thickness spin button, will not change anything about the canvas */ void ui_study_update_thickness(ui_study_t * ui_study, amide_real_t thickness) { amide_real_t min_voxel_size, max_size; /* there's no spin button if we don't create the toolbar at this moment */ if (ui_study->thickness_spin == NULL) return; min_voxel_size = amitk_data_sets_get_min_voxel_size(AMITK_OBJECT_CHILDREN(ui_study->study)); max_size = amitk_volumes_get_max_size(AMITK_OBJECT_CHILDREN(ui_study->study)); if ((min_voxel_size < 0) || (max_size < 0)) return; /* no valid objects */ /* block signals to the spin button, as we only want to change the value of the spin button, it's up to the caller of this function to change anything on the actual canvases... we'll unblock at the end of this function */ g_signal_handlers_block_by_func(G_OBJECT(ui_study->thickness_spin), G_CALLBACK(ui_study_cb_thickness), ui_study); /* set the current thickness if it hasn't already been set or if it's no longer valid*/ if (thickness < min_voxel_size) thickness = min_voxel_size; gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_study->thickness_spin), thickness); gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ui_study->thickness_spin), min_voxel_size, min_voxel_size); gtk_spin_button_set_range(GTK_SPIN_BUTTON(ui_study->thickness_spin), min_voxel_size, max_size); gtk_spin_button_configure(GTK_SPIN_BUTTON(ui_study->thickness_spin),NULL, thickness, gtk_spin_button_get_digits(GTK_SPIN_BUTTON(ui_study->thickness_spin))); /* and now, reconnect the signal */ g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->thickness_spin), G_CALLBACK(ui_study_cb_thickness), ui_study); return; } /* updates the settings of the zoom spinbutton, will not change anything about the canvas */ void ui_study_update_zoom(ui_study_t * ui_study) { /* block signals to the zoom spin button, as we only want to change the value of the spin button, it's up to the caller of this function to change anything on the actual canvases... we'll unblock at the end of this function */ g_signal_handlers_block_by_func(G_OBJECT(ui_study->zoom_spin), G_CALLBACK(ui_study_cb_zoom), ui_study); if (ui_study->study != NULL) gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_study->zoom_spin), AMITK_STUDY_ZOOM(ui_study->study)); /* and now, reconnect the signal */ g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->zoom_spin), G_CALLBACK(ui_study_cb_zoom), ui_study); return; } /* updates the settings of the fov spinbutton, will not change anything about the canvas */ void ui_study_update_fov(ui_study_t * ui_study) { /* block signals to the fov spin button, as we only want to change the value of the spin button, it's up to the caller of this function to change anything on the actual canvases... we'll unblock at the end of this function */ g_signal_handlers_block_by_func(G_OBJECT(ui_study->fov_spin), G_CALLBACK(ui_study_cb_fov), ui_study); gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui_study->fov_spin), AMITK_STUDY_FOV(ui_study->study)); /* and now, reconnect the signal */ g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->fov_spin), G_CALLBACK(ui_study_cb_fov), ui_study); return; } /* updates the settings of the canvas target button */ void ui_study_update_canvas_target(ui_study_t * ui_study) { g_signal_handlers_block_by_func(G_OBJECT(ui_study->canvas_target_action), G_CALLBACK(ui_study_cb_canvas_target), ui_study); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(ui_study->canvas_target_action), AMITK_STUDY_CANVAS_TARGET(ui_study->study)); g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->canvas_target_action), G_CALLBACK(ui_study_cb_canvas_target), ui_study); return; } void ui_study_update_fuse_type(ui_study_t * ui_study) { AmitkFuseType i_fuse_type; g_return_if_fail(ui_study->study != NULL); for (i_fuse_type = 0; i_fuse_type < AMITK_FUSE_TYPE_NUM; i_fuse_type++) g_signal_handlers_block_by_func(G_OBJECT(ui_study->fuse_type_action[i_fuse_type]), G_CALLBACK(ui_study_cb_fuse_type), ui_study); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(ui_study->fuse_type_action[AMITK_STUDY_FUSE_TYPE(ui_study->study)]), TRUE); for (i_fuse_type = 0; i_fuse_type < AMITK_FUSE_TYPE_NUM; i_fuse_type++) g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->fuse_type_action[i_fuse_type]), G_CALLBACK(ui_study_cb_fuse_type), ui_study); } void ui_study_update_view_mode(ui_study_t * ui_study) { AmitkViewMode i_view_mode; g_return_if_fail(ui_study->study != NULL); for (i_view_mode = 0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) g_signal_handlers_block_by_func(G_OBJECT(ui_study->view_mode_action[i_view_mode]), G_CALLBACK(ui_study_cb_view_mode), ui_study); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(ui_study->view_mode_action[AMITK_STUDY_VIEW_MODE(ui_study->study)]), TRUE); for (i_view_mode = 0; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) g_signal_handlers_unblock_by_func(G_OBJECT(ui_study->view_mode_action[i_view_mode]), G_CALLBACK(ui_study_cb_view_mode),ui_study); } void ui_study_update_title(ui_study_t * ui_study) { gchar * title; if (AMITK_STUDY_FILENAME(ui_study->study) == NULL) { title = g_strdup_printf(_("Study: %s %s"), AMITK_OBJECT_NAME(ui_study->study), ui_study->study_altered ? "*" : ""); } else { title = g_strdup_printf(_("Study: %s (%s) %s"), AMITK_OBJECT_NAME(ui_study->study), AMITK_STUDY_FILENAME(ui_study->study), ui_study->study_altered ? "*" : ""); } gtk_window_set_title(ui_study->window, title); g_free(title); } /* taken/modified from gtkhandlebox.c - note, no reattach signal gets called when this is used */ static void handle_box_reattach (GtkHandleBox *hb) { GtkWidget *widget = GTK_WIDGET (hb); if (hb->child_detached) { hb->child_detached = FALSE; if (GTK_WIDGET_REALIZED (hb)) { gdk_window_hide (hb->float_window); gdk_window_reparent (hb->bin_window, widget->window, 0, 0); } hb->float_window_mapped = FALSE; } gtk_widget_queue_resize (GTK_WIDGET (hb)); } void ui_study_update_layout(ui_study_t * ui_study) { AmitkView i_view; AmitkViewMode i_view_mode; gint row, column, table_column, table_row; // GtkWidget * scrolled; g_return_if_fail(ui_study->study != NULL); /* get rid of visible canvases that are no longer visible */ for (i_view_mode = AMITK_STUDY_VIEW_MODE(ui_study->study)+1; i_view_mode < AMITK_VIEW_MODE_NUM; i_view_mode++) { if (ui_study->canvas_table[i_view_mode] != NULL) { gtk_widget_destroy(ui_study->canvas_table[i_view_mode]); ui_study->canvas_table[i_view_mode] = NULL; gtk_widget_destroy(ui_study->canvas_handle[i_view_mode]); ui_study->canvas_handle[i_view_mode] = NULL; for (i_view=0; i_view < AMITK_VIEW_NUM; i_view++) ui_study->canvas[i_view_mode][i_view] = NULL; } } for (i_view_mode = 0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) { for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { if ((!AMITK_STUDY_CANVAS_VISIBLE(ui_study->study, i_view)) && (ui_study->canvas[i_view_mode][i_view] != NULL)) { gtk_widget_destroy(ui_study->canvas[i_view_mode][i_view]); ui_study->canvas[i_view_mode][i_view] = NULL; } } } for (i_view_mode = 0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) { if (ui_study->canvas_table[i_view_mode] == NULL) { ui_study->canvas_table[i_view_mode] = gtk_table_new(3, 2,FALSE); // scrolled = gtk_scrolled_window_new(NULL, NULL); // gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); // gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), ui_study->canvas_table[i_view_mode]); ui_study->canvas_handle[i_view_mode] = gtk_handle_box_new(); g_object_ref(G_OBJECT(ui_study->canvas_handle[i_view_mode])); /* gets removed below */ gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(ui_study->canvas_handle[i_view_mode]), GTK_SHADOW_NONE); gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(ui_study->canvas_handle[i_view_mode]), GTK_POS_TOP); gtk_container_add(GTK_CONTAINER(ui_study->canvas_handle[i_view_mode]), ui_study->canvas_table[i_view_mode]); // gtk_container_add(GTK_CONTAINER(ui_study->canvas_handle[i_view_mode]), scrolled); } else { g_return_if_fail(ui_study->canvas_handle[i_view_mode] != NULL); /* extra ref so widget not destroyed on container_remove - gets removed below */ g_object_ref(G_OBJECT(ui_study->canvas_handle[i_view_mode])); /* note, ui_study->panel_layout doesn't get set till end of function, but first time through this function we never hit this condition */ if (ui_study->panel_layout != AMITK_STUDY_PANEL_LAYOUT(ui_study->study)) { /* hack! to force handle box to reattach. If we don't force a reattach, the widget doesn't get enough size allocated to it on the gtk_table_attach that follows */ handle_box_reattach(GTK_HANDLE_BOX(ui_study->canvas_handle[i_view_mode])); gtk_container_remove(GTK_CONTAINER(ui_study->center_table), ui_study->canvas_handle[i_view_mode]); } } for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) { if (AMITK_STUDY_CANVAS_VISIBLE(ui_study->study, i_view)) { if (ui_study->canvas[i_view_mode][i_view] == NULL) { /* new canvas */ ui_study->canvas[i_view_mode][i_view] = amitk_canvas_new(ui_study->study, i_view, i_view_mode, AMITK_CANVAS_TYPE_NORMAL); g_object_ref(G_OBJECT(ui_study->canvas[i_view_mode][i_view])); /* will be removed below */ amitk_canvas_set_active_object(AMITK_CANVAS(ui_study->canvas[i_view_mode][i_view]), ui_study->active_object); g_signal_connect(G_OBJECT(ui_study->canvas[i_view_mode][i_view]), "help_event", G_CALLBACK(ui_study_cb_canvas_help_event), ui_study); g_signal_connect(G_OBJECT(ui_study->canvas[i_view_mode][i_view]), "view_changing", G_CALLBACK(ui_study_cb_canvas_view_changing), ui_study); g_signal_connect(G_OBJECT(ui_study->canvas[i_view_mode][i_view]), "view_changed", G_CALLBACK(ui_study_cb_canvas_view_changed), ui_study); g_signal_connect(G_OBJECT(ui_study->canvas[i_view_mode][i_view]), "erase_volume", G_CALLBACK(ui_study_cb_canvas_erase_volume), ui_study); g_signal_connect(G_OBJECT(ui_study->canvas[i_view_mode][i_view]), "new_object", G_CALLBACK(ui_study_cb_canvas_new_object), ui_study); } else { /* not a new canvas */ /* add ref so it's not destroyed when we remove it from the container */ g_object_ref(G_OBJECT(ui_study->canvas[i_view_mode][i_view])); /* note, ui_study->canvas_layout doesn't get set till end of function, but first time through this function we never hit this condition */ if (ui_study->canvas_layout != AMITK_STUDY_CANVAS_LAYOUT(ui_study->study)) { gtk_widget_hide(ui_study->canvas[i_view_mode][i_view]); /* hide, so we get more fluid moving */ gtk_container_remove(GTK_CONTAINER(ui_study->canvas_table[i_view_mode]), ui_study->canvas[i_view_mode][i_view]); } } } } } for (i_view_mode = 0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) { /* put the canvases in each table/handlebox according to the desired layout */ switch(AMITK_STUDY_CANVAS_LAYOUT(ui_study->study)) { case AMITK_LAYOUT_ORTHOGONAL: row = column = 0; if (ui_study->canvas[i_view_mode][AMITK_VIEW_TRANSVERSE] != NULL) { if (gtk_widget_get_parent(ui_study->canvas[i_view_mode][AMITK_VIEW_TRANSVERSE]) == NULL) gtk_table_attach(GTK_TABLE(ui_study->canvas_table[i_view_mode]), ui_study->canvas[i_view_mode][AMITK_VIEW_TRANSVERSE], column,column+1, row,row+1,FALSE,FALSE, X_PADDING, Y_PADDING); row++; } if (ui_study->canvas[i_view_mode][AMITK_VIEW_CORONAL] != NULL) { if (gtk_widget_get_parent(ui_study->canvas[i_view_mode][AMITK_VIEW_CORONAL]) == NULL) gtk_table_attach(GTK_TABLE(ui_study->canvas_table[i_view_mode]), ui_study->canvas[i_view_mode][AMITK_VIEW_CORONAL], column, column+1, row, row+1, FALSE,FALSE, X_PADDING, Y_PADDING); } row = 0; column++; if (ui_study->canvas[i_view_mode][AMITK_VIEW_SAGITTAL] != NULL) if (gtk_widget_get_parent(ui_study->canvas[i_view_mode][AMITK_VIEW_SAGITTAL]) == NULL) gtk_table_attach(GTK_TABLE(ui_study->canvas_table[i_view_mode]), ui_study->canvas[i_view_mode][AMITK_VIEW_SAGITTAL], column, column+1,row, row+1, FALSE,FALSE, X_PADDING, Y_PADDING); break; case AMITK_LAYOUT_LINEAR: default: for (i_view=0;i_view< AMITK_VIEW_NUM;i_view++) if (ui_study->canvas[i_view_mode][i_view] != NULL) if (gtk_widget_get_parent(ui_study->canvas[i_view_mode][i_view]) == NULL) gtk_table_attach(GTK_TABLE(ui_study->canvas_table[i_view_mode]), ui_study->canvas[i_view_mode][i_view], i_view, i_view+1, 0,1, FALSE, FALSE, X_PADDING, Y_PADDING); break; } /* place the handleboxes */ if (gtk_widget_get_parent(ui_study->canvas_handle[i_view_mode]) == NULL) { switch(AMITK_STUDY_PANEL_LAYOUT(ui_study->study)) { case AMITK_PANEL_LAYOUT_LINEAR_X: table_column=i_view_mode; table_row=0; break; case AMITK_PANEL_LAYOUT_LINEAR_Y: table_row=i_view_mode; table_column=0; break; case AMITK_PANEL_LAYOUT_MIXED: default: table_column = (i_view_mode % 2); table_row = floor((i_view_mode)/2); break; } gtk_table_attach(GTK_TABLE(ui_study->center_table), ui_study->canvas_handle[i_view_mode], table_column, table_column+1, table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); } /* remove the additional reference */ for (i_view = 0; i_view < AMITK_VIEW_NUM; i_view++) if (ui_study->canvas[i_view_mode][i_view] != NULL) g_object_unref(G_OBJECT(ui_study->canvas[i_view_mode][i_view])); g_object_unref(ui_study->canvas_handle[i_view_mode]); gtk_widget_show_all(ui_study->canvas_handle[i_view_mode]); /* and show */ } /* record the layout */ ui_study->panel_layout = AMITK_STUDY_PANEL_LAYOUT(ui_study->study); ui_study->canvas_layout = AMITK_STUDY_CANVAS_LAYOUT(ui_study->study); return; } /* function to setup the widgets inside of the study ui */ void ui_study_setup_widgets(ui_study_t * ui_study) { GtkWidget * scrolled; GtkWidget * left_vbox; GtkWidget * hbox; GtkWidget * handle_box; /* the hbox that'll contain everything in the ui besides the menu and toolbar */ hbox = gtk_hbox_new(FALSE,0); gtk_box_pack_start (GTK_BOX (ui_study->window_vbox), hbox, TRUE, TRUE, 0); /* make and add the left packing table */ left_vbox = gtk_vbox_new(FALSE,0); handle_box = gtk_handle_box_new(); gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(handle_box), GTK_SHADOW_NONE); gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(handle_box), GTK_POS_TOP); gtk_container_add(GTK_CONTAINER(handle_box), left_vbox); gtk_box_pack_start(GTK_BOX(hbox), handle_box, FALSE, FALSE, X_PADDING); /* connect the blank help signal */ g_object_set_data(G_OBJECT(ui_study->window), "which_help", GINT_TO_POINTER(AMITK_HELP_INFO_BLANK)); g_signal_connect(G_OBJECT(ui_study->window), "enter_notify_event", G_CALLBACK(ui_study_cb_update_help_info), ui_study); ui_study->tree_view = amitk_tree_view_new(AMITK_TREE_VIEW_MODE_MAIN, ui_study->preferences, ui_study->progress_dialog); g_signal_connect(G_OBJECT(ui_study->tree_view), "help_event", G_CALLBACK(ui_study_cb_tree_view_help_event), ui_study); g_signal_connect(G_OBJECT(ui_study->tree_view), "activate_object", G_CALLBACK(ui_study_cb_tree_view_activate_object), ui_study); g_signal_connect(G_OBJECT(ui_study->tree_view), "popup_object", G_CALLBACK(ui_study_cb_tree_view_popup_object), ui_study); g_signal_connect(G_OBJECT(ui_study->tree_view), "add_object", G_CALLBACK(ui_study_cb_tree_view_add_object), ui_study); g_signal_connect(G_OBJECT(ui_study->tree_view), "delete_object", G_CALLBACK(ui_study_cb_tree_view_delete_object), ui_study); /* make a scrolled area for the tree */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,LEFT_COLUMN_WIDTH,250); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), ui_study->tree_view); gtk_box_pack_start(GTK_BOX(left_vbox), scrolled, TRUE, TRUE,Y_PADDING); /* the help information canvas */ #ifdef AMIDE_LIBGNOMECANVAS_AA ui_study->help_info = GNOME_CANVAS(gnome_canvas_new_aa()); #else ui_study->help_info = GNOME_CANVAS(gnome_canvas_new()); #endif gtk_box_pack_start(GTK_BOX(left_vbox), GTK_WIDGET(ui_study->help_info), FALSE, TRUE, Y_PADDING); gtk_widget_set_size_request(GTK_WIDGET(ui_study->help_info), LEFT_COLUMN_WIDTH, HELP_INFO_LINE_HEIGHT*NUM_HELP_INFO_LINES+2); gnome_canvas_set_scroll_region(ui_study->help_info, 0.0, 0.0, LEFT_COLUMN_WIDTH, HELP_INFO_LINE_HEIGHT*NUM_HELP_INFO_LINES+2.0); /* make the stuff in the center */ ui_study->center_table = gtk_table_new(2, 2,FALSE); gtk_box_pack_start(GTK_BOX(hbox),ui_study->center_table, TRUE, TRUE, X_PADDING); return; } /* replace what's currently in the ui_study with the specified study */ void ui_study_set_study(ui_study_t * ui_study, AmitkStudy * study) { add_object(ui_study, AMITK_OBJECT(study)); ui_study->study_altered=FALSE; ui_study_update_title(ui_study); ui_study_make_active_object(ui_study, NULL); } /* procedure to set up the study window */ GtkWidget * ui_study_create(AmitkStudy * study, AmitkPreferences * preferences) { ui_study_t * ui_study; GdkPixbuf * pixbuf; g_return_val_if_fail(preferences != NULL, NULL); ui_study = ui_study_init(preferences); /* setup the study window */ ui_study->window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); ui_study->window_vbox = gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER (ui_study->window), ui_study->window_vbox); /* set the icon that the window manager knows about */ pixbuf = gtk_widget_render_icon(GTK_WIDGET(ui_study->window), "amide_icon_logo", -1, 0); gtk_window_set_icon(ui_study->window, pixbuf); gtk_window_set_default_icon(pixbuf); /* sets it as the default for all additional windows */ g_object_unref(pixbuf); /* disable user resizability, allows the window to autoshrink */ gtk_window_set_resizable(ui_study->window, FALSE); /* setup the callbacks for the window */ g_signal_connect(G_OBJECT(ui_study->window), "delete_event", G_CALLBACK(ui_study_cb_delete_event), ui_study); ui_study->progress_dialog = amitk_progress_dialog_new(ui_study->window); /* setup the menu and toolbar */ menus_toolbar_create(ui_study); /* setup the rest of the study window */ ui_study_setup_widgets(ui_study); /* add the study to the ui_study */ if (study == NULL) { study = amitk_study_new(preferences); ui_study_set_study(ui_study, study); amitk_object_unref(study); ui_study->study_virgin=TRUE; } else { ui_study_set_study(ui_study, study); ui_study->study_virgin=FALSE; } ui_study_update_title(ui_study); /* get the study window running */ gtk_widget_show_all(GTK_WIDGET(ui_study->window)); amide_register_window((gpointer) ui_study->window); return GTK_WIDGET(ui_study->window); } amide-1.0.6/amide-current/src/ui_study.h000066400000000000000000000111341423227705100201440ustar00rootroot00000000000000/* ui_study.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __UI_STUDY_H__ #define __UI_STUDY_H__ /* header files that are always needed with this file */ #include #include "amitk_study.h" #include #define AMIDE_LIMIT_ZOOM_UPPER 10.0 #define AMIDE_LIMIT_ZOOM_LOWER 0.2 #define AMIDE_LIMIT_ZOOM_STEP 0.2 /* in percent */ #define AMIDE_LIMIT_FOV_UPPER 100.0 #define AMIDE_LIMIT_FOV_LOWER 10.0 #define AMIDE_LIMIT_FOV_STEP 10.0 typedef enum { HELP_INFO_LINE_1, HELP_INFO_LINE_1_SHIFT, HELP_INFO_LINE_2, HELP_INFO_LINE_2_SHIFT, HELP_INFO_LINE_3, HELP_INFO_LINE_3_SHIFT, HELP_INFO_LINE_3_CTRL, HELP_INFO_LINE_VARIABLE, HELP_INFO_LINE_BLANK, HELP_INFO_LINE_LOCATION1, HELP_INFO_LINE_LOCATION2, NUM_HELP_INFO_LINES /* corresponds to the location line */ } help_info_line_t; #define UI_STUDY_DEFAULT_ENTRY_WIDTH 75 /* ui_study data structures */ typedef struct ui_study_t { GtkWindow * window; /* pointer to the window managing this study */ GtkWidget * window_vbox; GtkWidget * thickness_spin; GtkWidget * zoom_spin; GtkWidget * fov_spin; GtkAction * interpolation_action[AMITK_INTERPOLATION_NUM]; GtkWidget * rendering_menu; GtkAction * canvas_target_action; GtkAction * canvas_visible_action[AMITK_VIEW_NUM]; GtkAction * view_mode_action[AMITK_VIEW_MODE_NUM]; GtkAction * fuse_type_action[AMITK_FUSE_TYPE_NUM]; GtkWidget * tree_view; /* the tree showing the study data structure info */ GtkWidget * gate_dialog; GtkWidget * gate_button; GtkWidget * time_dialog; GtkWidget * time_button; AmitkObject * active_object; /* which object to use for actions that are for one object */ AmitkStudy * study; /* pointer to the study data structure */ GtkWidget * threshold_dialog; /* pointer to the threshold dialog */ GtkWidget * progress_dialog; /* canvas specific info */ GtkWidget * center_table; GtkWidget * canvas_table[AMITK_VIEW_MODE_NUM]; GtkWidget * canvas_handle[AMITK_VIEW_MODE_NUM]; GtkWidget * canvas[AMITK_VIEW_MODE_NUM][AMITK_VIEW_NUM]; AmitkPanelLayout panel_layout; AmitkLayout canvas_layout; /* help canvas info */ GnomeCanvas * help_info; GnomeCanvasItem * help_legend[NUM_HELP_INFO_LINES]; GnomeCanvasItem * help_line[NUM_HELP_INFO_LINES]; /* preferences */ AmitkPreferences * preferences; gboolean study_altered; gboolean study_virgin; guint reference_count; } ui_study_t; /* external functions */ ui_study_t * ui_study_free(ui_study_t * ui_study); ui_study_t * ui_study_init(AmitkPreferences * preferences); void ui_study_make_active_object(ui_study_t * ui_study, AmitkObject * object); void ui_study_add_fiducial_mark(ui_study_t * ui_study, AmitkObject * parent_object, gboolean selected, AmitkPoint position); void ui_study_add_roi(ui_study_t * ui_study, AmitkObject * parent_object, AmitkRoiType roi_type); void ui_study_set_study(ui_study_t * ui_study, AmitkStudy * study); GtkWidget * ui_study_create(AmitkStudy * study, AmitkPreferences * preferences); void ui_study_update_help_info(ui_study_t * ui_study, AmitkHelpInfo which_info, AmitkPoint point, amide_data_t value); void ui_study_update_canvas_visible_buttons(ui_study_t * ui_study); void ui_study_update_gate_button(ui_study_t * ui_study); void ui_study_update_time_button(ui_study_t * ui_study); void ui_study_update_thickness(ui_study_t * ui_study, amide_real_t thickness); void ui_study_update_zoom(ui_study_t * ui_study); void ui_study_update_fov(ui_study_t * ui_study); void ui_study_update_canvas_target(ui_study_t * ui_study); void ui_study_update_fuse_type(ui_study_t * ui_study); void ui_study_update_view_mode(ui_study_t * ui_study); void ui_study_update_title(ui_study_t * ui_study); void ui_study_update_layout(ui_study_t * ui_study); void ui_study_setup_widgets(ui_study_t * ui_study); #endif /* __UI_STUDY_H__ */ amide-1.0.6/amide-current/src/ui_study_cb.c000066400000000000000000001263651423227705100206200ustar00rootroot00000000000000/* ui_study_cb.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include /* needed for stat */ #include /* needed for dirent.h on mac os */ #include #include #include "amide.h" #include "amitk_threshold.h" #include "amitk_canvas.h" #include "amitk_tree_view.h" #include "ui_common.h" #include "ui_render.h" #include "ui_series.h" #include "ui_study.h" #include "ui_study_cb.h" #include "ui_preferences_dialog.h" #include "amitk_object_dialog.h" #include "amitk_progress_dialog.h" #include "ui_gate_dialog.h" #include "ui_time_dialog.h" #include "tb_export_data_set.h" #include "tb_distance.h" #include "tb_fly_through.h" #include "tb_alignment.h" #include "tb_crop.h" #include "tb_fads.h" #include "tb_filter.h" #include "tb_math.h" #include "tb_profile.h" #include "tb_roi_analysis.h" static gchar * no_active_ds = N_("No data set is currently marked as active"); #ifndef AMIDE_LIBGSL_SUPPORT static gchar * no_gsl = N_("This wizard requires compiled in support from the GNU Scientific Library (libgsl), which this copy of AMIDE does not have."); #endif static void object_picker(ui_study_t * ui_study, AmitkStudy * import_study) { GtkWidget * dialog; gchar * temp_string; GtkWidget * table; guint table_row; GtkWidget * tree_view; GtkWidget * scrolled; GList * selected_objects; GList * temp_objects; gint return_val; /* unselect all objects in study */ amitk_object_set_selected(AMITK_OBJECT(import_study), FALSE, AMITK_SELECTION_ALL); temp_string = g_strdup_printf(_("%s: Pick Object(s) to Import"), PACKAGE); dialog = gtk_dialog_new_with_buttons (temp_string, ui_study->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_EXECUTE, AMITK_RESPONSE_EXECUTE, GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE, NULL); gtk_window_set_title(GTK_WINDOW(dialog), temp_string); g_free(temp_string); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(ui_common_init_dialog_response_cb), NULL); gtk_container_set_border_width(GTK_CONTAINER(dialog), 10); /* start making the widgets for this dialog box */ table = gtk_table_new(5,2,FALSE); table_row=0; gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); tree_view = amitk_tree_view_new(AMITK_TREE_VIEW_MODE_MULTIPLE_SELECTION,NULL, NULL); g_object_set_data(G_OBJECT(dialog), "tree_view", tree_view); amitk_tree_view_set_study(AMITK_TREE_VIEW(tree_view), import_study); amitk_tree_view_expand_object(AMITK_TREE_VIEW(tree_view), AMITK_OBJECT(import_study)); /* make a scrolled area for the tree */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,250,250); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), tree_view); gtk_table_attach(GTK_TABLE(table), scrolled, 0,2, table_row, table_row+1,GTK_FILL, GTK_FILL | GTK_EXPAND, X_PADDING, Y_PADDING); table_row++; /* and show all our widgets */ gtk_widget_show_all(dialog); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(dialog)); /* get which objects were selected */ selected_objects = ui_common_init_dialog_selected_objects(dialog); gtk_widget_destroy(dialog); /* add on the new objects i fwe want */ if (return_val == AMITK_RESPONSE_EXECUTE) { temp_objects = selected_objects; while (temp_objects != NULL) { amitk_object_remove_child(AMITK_OBJECT(import_study), AMITK_OBJECT(temp_objects->data)); amitk_object_add_child(AMITK_OBJECT(ui_study->study), AMITK_OBJECT(temp_objects->data)); temp_objects = temp_objects->next; } } selected_objects = amitk_objects_unref(selected_objects); } gboolean xif_files_filter(const GtkFileFilterInfo *filter_info, gpointer data) { g_return_val_if_fail(filter_info->filename != NULL, FALSE); // amitk_is_xif_directory(filter_info->filename, NULL, NULL) return amitk_is_xif_flat_file(filter_info->filename, NULL, NULL); } void create_xif_filters(GtkFileChooser * file_chooser) { GtkFileFilter * filter; /* create the filter for .xif files */ filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("XIF Files")); // gtk_file_filter_add_pattern (filter, "*"); gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, xif_files_filter, NULL, NULL); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), filter); gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (file_chooser), filter); /* xif filter is default */ filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("All Files")); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser), filter); return; } void read_xif(ui_study_t * ui_study, gboolean import_object, gboolean as_directory, gboolean recovery_mode) { GtkWidget * file_chooser; AmitkStudy * study; gchar * filename; /* get the name of the file to import */ file_chooser = gtk_file_chooser_dialog_new (recovery_mode ? _("Recover AMIDE XIF FILE") : _("Open AMIDE XIF File"), GTK_WINDOW(ui_study->window), /* parent window */ as_directory ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(ui_study->preferences, file_chooser); /* set the default directory if applicable */ if (!as_directory) create_xif_filters(GTK_FILE_CHOOSER(file_chooser)); /* only include *.xif in the list by default */ if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy (file_chooser); if (filename == NULL) return; if (!ui_common_check_filename(filename)) { g_warning(_("Inappropriate filename: %s"),filename); g_free(filename); return; } ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); /* try loading the study into memory */ if (recovery_mode) { study = amitk_study_recover_xml(filename, ui_study->preferences); if (study == NULL) g_warning(_("error recovering study: %s"),filename); } else { study = amitk_study_load_xml(filename); if (study == NULL) g_warning(_("error loading study: %s"),filename); } if (study != NULL) { if (!import_object) { /* setup the study window */ if (ui_study->study_virgin) ui_study_set_study(ui_study, study); else ui_study_create(study, ui_study->preferences); } else { object_picker(ui_study, study); } amitk_object_unref(study); } ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); g_free(filename); } /* function to load a study into the study widget */ void ui_study_cb_open_xif_file(GtkAction * action, gpointer data) { ui_study_t * ui_study=data; read_xif(ui_study, FALSE, FALSE, FALSE); return; } void ui_study_cb_open_xif_dir(GtkAction * action, gpointer data) { ui_study_t * ui_study=data; read_xif(ui_study, FALSE, TRUE, FALSE); return; } /* function to load an object from a pre-existing study into the current study widget */ void ui_study_cb_import_object_from_xif_file(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; read_xif(ui_study, TRUE, FALSE, FALSE); return; } void ui_study_cb_import_object_from_xif_dir(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; read_xif(ui_study, TRUE, TRUE, FALSE); return; } /* try to recover portions of a study file */ void ui_study_cb_recover_xif_file(GtkAction * action, gpointer data) { ui_study_t * ui_study=data; read_xif(ui_study, FALSE, FALSE, TRUE); return; } /* function to create a new study widget */ void ui_study_cb_new_study(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; ui_study_create(NULL, ui_study->preferences); return; } /* returned save_filename needs to be free'd */ static gchar * verify_save_name(GtkWindow * parent, const gchar * filename) { gchar * save_filename; gchar * prev_filename; gchar ** frags1=NULL; gchar ** frags2=NULL; struct stat file_info; GtkWidget * question; gint return_val; g_return_val_if_fail(filename != NULL, NULL); /* make sure the filename ends with .xif */ save_filename = g_strdup(filename); g_strreverse(save_filename); frags1 = g_strsplit(save_filename, ".", 2); g_strreverse(save_filename); g_strreverse(frags1[0]); frags2 = g_strsplit(frags1[0], G_DIR_SEPARATOR_S, -1); if (g_ascii_strcasecmp(frags2[0], "xif") != 0) { prev_filename = save_filename; save_filename = g_strdup_printf("%s%s",prev_filename, ".xif"); g_free(prev_filename); } g_strfreev(frags2); g_strfreev(frags1); /* check with user if filename already exists */ if (stat(save_filename, &file_info) == 0) { /* check if it's okay to writeover the file */ question = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("Overwrite file: %s"), save_filename); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val != GTK_RESPONSE_OK) { return NULL; /* we don't want to overwrite the file.... */ } } /* unlinking the file doesn't occur here */ return save_filename; } void save_xif(ui_study_t * ui_study, gboolean as_directory) { GtkWidget * file_chooser; gchar * initial_filename; gchar * final_filename; gchar * temp_str; /* get the name of the file to save */ file_chooser = gtk_file_chooser_dialog_new (_("Save AMIDE XIF File"), GTK_WINDOW(ui_study->window), /* parent window */ as_directory ? GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); if (!as_directory) create_xif_filters(GTK_FILE_CHOOSER(file_chooser)); /* only include *.xif in the list by default */ /* take a guess at the filename */ if (AMITK_STUDY_FILENAME(ui_study->study) == NULL) { if (AMITK_OBJECT_NAME(ui_study->study) != NULL) { initial_filename = g_strdup_printf("%s.xif",AMITK_OBJECT_NAME(ui_study->study)); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), initial_filename); g_free(initial_filename); } else { gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_chooser), "Untitled.xif"); } temp_str = ui_common_suggest_path(); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), temp_str); g_free(temp_str); } else { /* don't already have a filename */ if (!as_directory) { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser), AMITK_STUDY_FILENAME(ui_study->study)); } else { /* as_directory */ /* have to do all this crap, as gtk_file_chooser_set_filename doesn't play well with GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */ temp_str = g_path_get_basename(AMITK_STUDY_FILENAME(ui_study->study)); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), temp_str); g_free(temp_str); temp_str = g_path_get_dirname(AMITK_STUDY_FILENAME(ui_study->study)); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), temp_str); g_free(temp_str); } } if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) initial_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); else initial_filename = NULL; gtk_widget_destroy (file_chooser); if (initial_filename == NULL) return; /* sanity checks */ if (!ui_common_check_filename(initial_filename)) { g_warning(_("Inappropriate filename: %s"),initial_filename); g_free(initial_filename); return; } /* verify the file name is kosher, and if we really want to overwrite */ if (!as_directory) { final_filename = verify_save_name(GTK_WINDOW(ui_study->window), initial_filename); g_free(initial_filename); if (final_filename == NULL) return; } else { /* we don't force the user to end the directory name with .xif this is mainly because gtk_file_chooser already creates the directory (annoying) */ final_filename = initial_filename; initial_filename = NULL; } ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); /* allright, save our study */ if (amitk_study_save_xml(ui_study->study, final_filename, as_directory) == FALSE) { g_warning(_("Failure Saving File: %s"),final_filename); } else { /* indicate no new changes */ ui_study->study_altered=FALSE; ui_study_update_title(ui_study); } ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); ui_common_set_last_path_used(final_filename); g_free(final_filename); } void ui_study_cb_save_as_xif_file(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; save_xif(ui_study, FALSE); return; } void ui_study_cb_save_as_xif_dir(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; save_xif(ui_study, TRUE); return; } /* function to selection which file to import */ void ui_study_cb_import(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; GtkWidget * file_chooser; AmitkImportMethod method; int submethod; gchar * filename; gchar * studyname = NULL; GList * import_data_sets; AmitkDataSet * import_ds; /* get the name of the file to import */ file_chooser = gtk_file_chooser_dialog_new (_("Import File"), GTK_WINDOW(ui_study->window), /* parent window */ GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(ui_study->preferences, file_chooser); /* set the default directory if applicable */ if (gtk_dialog_run (GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy (file_chooser); if (filename == NULL) return; if (!ui_common_check_filename(filename)) { g_warning(_("Inappropriate Filename: %s"), filename); g_free(filename); return; } #ifdef AMIDE_DEBUG g_print("file to import: %s\n",filename); #endif /* method we're trying to use to read in the file */ method = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "method")); submethod = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "submethod")); ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); /* now, what we need to do if we've successfully gotten an image filename */ if ((import_data_sets = amitk_data_set_import_file(method, submethod, filename, &studyname, ui_study->preferences, amitk_progress_dialog_update, ui_study->progress_dialog)) != NULL) { if (studyname != NULL) { amitk_study_suggest_name(ui_study->study, studyname); g_free(studyname); } while (import_data_sets != NULL) { import_ds = import_data_sets->data; #ifdef AMIDE_DEBUG g_print("imported data set name %s\n",AMITK_OBJECT_NAME(import_ds)); #endif amitk_object_add_child(AMITK_OBJECT(ui_study->study), AMITK_OBJECT(import_ds)); /* this adds a reference to the data set*/ import_data_sets = g_list_remove(import_data_sets, import_ds); amitk_object_unref(import_ds); /* so remove a reference */ } } else { g_warning(_("Could not import data sets from file %s\n"), filename); } ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); ui_common_set_last_path_used(filename); g_free(filename); return; } /* function to selection which file to export to */ void ui_study_cb_export_data_set(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; if (!AMITK_IS_DATA_SET(ui_study->active_object)) { g_warning(_("There's currently no active data set to export")); return; } /* let the user input rendering options */ tb_export_data_set(ui_study->study, AMITK_DATA_SET(ui_study->active_object), ui_study->preferences, ui_study->window); return; } /* function to save a view as an external data format */ void ui_study_cb_export_view(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; GList * current_data_sets; GList * temp_sets; GtkWidget * file_chooser; gchar * filename; gchar * data_set_names = NULL; AmitkView view; amide_real_t upper, lower; AmitkPoint temp_p; AmitkVolume * canvas_volume; GdkPixbuf * pixbuf; gboolean save_as_png=FALSE; gint length; const gchar * extension; gboolean return_val; current_data_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(ui_study->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_SELECTED_0, TRUE); if (current_data_sets == NULL) return; file_chooser = gtk_file_chooser_dialog_new(_("Export to File"), GTK_WINDOW(ui_study->window), /* parent window */ GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (file_chooser), TRUE); amitk_preferences_set_file_chooser_directory(ui_study->preferences, file_chooser); /* set the default directory if applicable */ view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "view")); if (ui_study->canvas[AMITK_VIEW_MODE_SINGLE][view] == NULL) return; canvas_volume = AMITK_CANVAS(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][view])->volume; g_return_if_fail(canvas_volume != NULL); /* translate the center so that the z coordinate corresponds to depth in this view */ temp_p = amitk_space_b2s(AMITK_SPACE(canvas_volume), AMITK_STUDY_VIEW_CENTER(ui_study->study)); /* figure out the top and bottom of this slice */ upper = temp_p.z + AMITK_STUDY_VIEW_THICKNESS(ui_study->study)/2.0; lower = temp_p.z - AMITK_STUDY_VIEW_THICKNESS(ui_study->study)/2.0; /* take a guess at the filename */ data_set_names = g_strdup(AMITK_OBJECT_NAME(current_data_sets->data)); temp_sets = current_data_sets->next; while (temp_sets != NULL) { filename = g_strdup_printf("%s+%s",data_set_names, AMITK_OBJECT_NAME(temp_sets->data)); g_free(data_set_names); data_set_names = filename; temp_sets = temp_sets->next; } filename = g_strdup_printf("%s_%s_%s_%3.1f-%3.1f.jpg", AMITK_OBJECT_NAME(ui_study->study), data_set_names, amitk_view_get_name(view), lower, upper); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser), filename); g_free(data_set_names); g_free(filename); amitk_objects_unref(current_data_sets); /* run the file chooser dialog */ if (gtk_dialog_run(GTK_DIALOG (file_chooser)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser)); else filename = NULL; gtk_widget_destroy (file_chooser); if (filename == NULL) return; /* check if we want a png */ length = strlen(filename); if (length > 4) { extension = filename + length-4; if (g_ascii_strncasecmp(extension, ".png", 4)==0) { save_as_png = TRUE; } } /* get a pixbuf of the canvas */ pixbuf = amitk_canvas_get_pixbuf(AMITK_CANVAS(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][view])); if (pixbuf == NULL) { g_warning(_("Canvas failed to return a valid image\n")); } else { if (save_as_png) return_val = gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL); else return_val = gdk_pixbuf_save (pixbuf, filename, "jpeg", NULL, "quality", "100", NULL); if (!return_val) g_warning(_("Failure Saving File: %s"),filename); g_object_unref(pixbuf); } g_free(filename); return; } /* callback generally attached to the entry_notify_event */ gboolean ui_study_cb_update_help_info(GtkWidget * widget, GdkEventCrossing * event, gpointer data) { ui_study_t * ui_study = data; AmitkHelpInfo which_info; which_info = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "which_help")); ui_study_update_help_info(ui_study, which_info, AMITK_STUDY_VIEW_CENTER(ui_study->study), 0.0); return FALSE; } void ui_study_cb_canvas_help_event(GtkWidget * canvas, AmitkHelpInfo help_type, AmitkPoint *location, amide_data_t value, gpointer data) { ui_study_t * ui_study = data; ui_study_update_help_info(ui_study, help_type, *location, value); return; } void ui_study_cb_canvas_view_changing(GtkWidget * canvas, AmitkPoint *position, amide_real_t thickness, gpointer data) { ui_study_t * ui_study = data; AmitkView i_view; AmitkViewMode i_view_mode; g_return_if_fail(ui_study->study != NULL); /* update the other canvases accordingly */ for (i_view_mode=0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) for (i_view=0; i_viewcanvas[i_view_mode][i_view] != NULL) if (canvas != ui_study->canvas[i_view_mode][i_view]) amitk_canvas_update_target(AMITK_CANVAS(ui_study->canvas[i_view_mode][i_view]), AMITK_CANVAS_TARGET_ACTION_SHOW,*position, thickness); if (!REAL_EQUAL(AMITK_STUDY_VIEW_THICKNESS(ui_study->study), thickness)) ui_study_update_thickness(ui_study, thickness); return; } void ui_study_cb_canvas_view_changed(GtkWidget * canvas, AmitkPoint *position, amide_real_t thickness, gpointer data) { ui_study_t * ui_study = data; AmitkView i_view; AmitkViewMode i_view_mode; g_return_if_fail(ui_study->study != NULL); amitk_study_set_view_thickness(ui_study->study, thickness); amitk_study_set_view_center(ui_study->study, *position); /* update the other canvases accordingly */ for (i_view_mode=0; i_view_mode <= AMITK_STUDY_VIEW_MODE(ui_study->study); i_view_mode++) { for (i_view=0; i_viewcanvas[i_view_mode][i_view] != NULL) amitk_canvas_update_target(AMITK_CANVAS(ui_study->canvas[i_view_mode][i_view]), AMITK_CANVAS_TARGET_ACTION_HIDE,*position, thickness); } return; } void ui_study_cb_canvas_erase_volume(GtkWidget * canvas, AmitkRoi * roi, gboolean outside, gpointer data) { ui_study_t * ui_study = data; GtkWidget * question; gint return_val; if (!AMITK_IS_DATA_SET(ui_study->active_object)) { g_warning(_("no active data set to erase from")); return; } /* make sure we really want to delete */ question = gtk_message_dialog_new(ui_study->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("Do you really wish to erase the data set %s\n to the ROI: %s\n on the data set: %s\nThis step is irreversible\nThe minimum threshold value: %5.3f\n will be used to fill in the volume"), outside ? _("exterior") : _("interior"), AMITK_OBJECT_NAME(roi), AMITK_OBJECT_NAME(ui_study->active_object), AMITK_DATA_SET_THRESHOLD_MIN(ui_study->active_object,0)); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val != GTK_RESPONSE_OK) return; /* cancel */ amitk_roi_erase_volume(roi, AMITK_DATA_SET(ui_study->active_object), outside, amitk_progress_dialog_update, ui_study->progress_dialog); return; } void ui_study_cb_canvas_new_object(GtkWidget * canvas, AmitkObject * parent, AmitkObjectType type, AmitkPoint *position, gpointer data) { ui_study_t * ui_study = data; /* only handles fiducial marks currently */ g_return_if_fail(type == AMITK_OBJECT_TYPE_FIDUCIAL_MARK); ui_study_add_fiducial_mark(ui_study, parent, TRUE, *position); return; } void ui_study_cb_tree_view_activate_object(GtkWidget * tree_view, AmitkObject * object, gpointer data) { ui_study_t * ui_study = data; AmitkPoint center; if (object == NULL) { ui_study_make_active_object(ui_study, object); } else if (AMITK_IS_DATA_SET(object) || AMITK_IS_STUDY(object)) { ui_study_make_active_object(ui_study, object); } else if (AMITK_IS_ROI(object)) { if (!AMITK_ROI_UNDRAWN(AMITK_ROI(object))) { center = amitk_volume_get_center(AMITK_VOLUME(object)); if (!POINT_EQUAL(center, AMITK_STUDY_VIEW_CENTER(ui_study->study))) amitk_study_set_view_center(ui_study->study, center); } } else if (AMITK_IS_FIDUCIAL_MARK(object)) { center = AMITK_FIDUCIAL_MARK_GET(object); if ( !POINT_EQUAL(center, AMITK_STUDY_VIEW_CENTER(ui_study->study))) amitk_study_set_view_center(ui_study->study, center); } } void ui_study_cb_tree_view_popup_object(GtkWidget * tree_view, AmitkObject * object, gpointer data) { ui_study_t * ui_study = data; GtkWidget * dialog; if (AMITK_IS_DATA_SET(object)) { ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); if (ui_study->threshold_dialog != NULL) { if (amitk_threshold_dialog_data_set(AMITK_THRESHOLD_DIALOG(ui_study->threshold_dialog)) == AMITK_DATA_SET(object)) { gtk_widget_destroy(ui_study->threshold_dialog); ui_study->threshold_dialog = NULL; } } } dialog = amitk_object_dialog_new(object); if (AMITK_IS_DATA_SET(object)) ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); if (dialog != NULL) gtk_widget_show(dialog); else /* already up ,pop the window to the top */ gtk_window_present(GTK_WINDOW(object->dialog)); return; } void ui_study_cb_tree_view_add_object(GtkWidget * tree_view, AmitkObject * parent, AmitkObjectType object_type, AmitkRoiType roi_type, gpointer data) { ui_study_t * ui_study = data; if (parent == NULL) parent = AMITK_OBJECT(ui_study->study); if (object_type == AMITK_OBJECT_TYPE_FIDUCIAL_MARK) ui_study_add_fiducial_mark(ui_study, parent, TRUE,AMITK_STUDY_VIEW_CENTER(ui_study->study)); else if (object_type == AMITK_OBJECT_TYPE_ROI) ui_study_add_roi(ui_study, parent, roi_type); return; } void ui_study_cb_tree_view_delete_object(GtkWidget * tree_view, AmitkObject * object, gpointer data) { ui_study_t * ui_study = data; GtkWidget * question; gint return_val; g_return_if_fail(AMITK_IS_OBJECT(object)); question = gtk_message_dialog_new(ui_study->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("Do you really want to delete: %s%s"), AMITK_OBJECT_NAME(object), AMITK_OBJECT_CHILDREN(object) != NULL ? _("\nand its children") : ""); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(question)); gtk_widget_destroy(question); if (return_val != GTK_RESPONSE_OK) return; amitk_object_remove_child(AMITK_OBJECT_PARENT(object), object); if (ui_study->study_altered != TRUE) { ui_study->study_virgin=FALSE; ui_study->study_altered=TRUE; ui_study_update_title(ui_study); } return; } void ui_study_cb_tree_view_help_event(GtkWidget * widget, AmitkHelpInfo help_type, gpointer data) { ui_study_t * ui_study = data; ui_study_update_help_info(ui_study, help_type, zero_point, 0.0); return; } void ui_study_cb_zoom(GtkSpinButton * spin_button, gpointer data) { ui_study_t * ui_study = data; amide_real_t zoom; if (AMITK_OBJECT_CHILDREN(ui_study->study)==NULL) return; zoom = gtk_spin_button_get_value(spin_button); amitk_study_set_zoom(ui_study->study, zoom); return; } void ui_study_cb_fov(GtkSpinButton * spin_button, gpointer data) { ui_study_t * ui_study = data; amide_real_t fov; if (AMITK_OBJECT_CHILDREN(ui_study->study)==NULL) return; fov = gtk_spin_button_get_value(spin_button); amitk_study_set_fov(ui_study->study, fov); return; } void ui_study_cb_thickness(GtkSpinButton * spin_button, gpointer data) { ui_study_t * ui_study = data; amide_real_t thickness; if (AMITK_OBJECT_CHILDREN(ui_study->study)==NULL) return; /* this does the equivalent of hitting "enter", makes sure any rounding error that is done on the entry is performed before we get the value */ g_signal_emit_by_name(G_OBJECT(spin_button), "activate", NULL, NULL); thickness = gtk_spin_button_get_value(spin_button); amitk_study_set_view_thickness(ui_study->study, thickness); return; } static gboolean gate_delete_event(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_study_t * ui_study = data; /* just keeping track on whether or not the gate widget is up */ ui_study->gate_dialog = NULL; return FALSE; } void ui_study_cb_gate(GtkWidget * button, gpointer data) { ui_study_t * ui_study = data; if (ui_study->gate_dialog == NULL) { if (AMITK_IS_DATA_SET(ui_study->active_object)) { ui_study->gate_dialog = ui_gate_dialog_create(AMITK_DATA_SET(ui_study->active_object), ui_study->window); g_signal_connect(G_OBJECT(ui_study->gate_dialog), "delete_event", G_CALLBACK(gate_delete_event), ui_study); gtk_widget_show(ui_study->gate_dialog); } } else /* pop the window to the top */ gtk_window_present(GTK_WINDOW(ui_study->gate_dialog)); return; } static gboolean time_delete_event(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_study_t * ui_study = data; /* just keeping track on whether or not the time widget is up */ ui_study->time_dialog = NULL; return FALSE; } void ui_study_cb_time(GtkWidget * button, gpointer data) { ui_study_t * ui_study = data; if (ui_study->time_dialog == NULL) { ui_study->time_dialog = ui_time_dialog_create(ui_study->study, ui_study->window); g_signal_connect(G_OBJECT(ui_study->time_dialog), "delete_event", G_CALLBACK(time_delete_event), ui_study); gtk_widget_show(ui_study->time_dialog); } else /* pop the window to the top */ gtk_window_present(GTK_WINDOW(ui_study->time_dialog)); return; } /* callbacks for setting up a set of slices in a new window */ void ui_study_cb_series(GtkAction * action, gpointer data) { GtkWidget * dialog; ui_study_t * ui_study = data; gint return_val; GList * selected_objects; /* let the user input rendering options */ dialog = ui_series_init_dialog_create(ui_study->study, ui_study->window); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(dialog)); selected_objects = ui_common_init_dialog_selected_objects(dialog); gtk_widget_destroy(dialog); /* we want to create the series */ if (return_val == AMITK_RESPONSE_EXECUTE) { ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); ui_series_create(ui_study->study, ui_study->active_object, selected_objects, ui_study->preferences); ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); } selected_objects = amitk_objects_unref(selected_objects); return; } #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) void ui_study_cb_fly_through(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; AmitkView view; view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "view")); tb_fly_through(ui_study->study, view, ui_study->preferences, ui_study->window); return; } #endif #ifdef AMIDE_LIBVOLPACK_SUPPORT /* callback for starting up volume rendering */ void ui_study_cb_render(GtkAction * action, gpointer data) { GtkWidget * dialog; ui_study_t * ui_study = data; gint return_val; GList * selected_objects; /* let the user input rendering options */ dialog = ui_render_init_dialog_create(ui_study->study, ui_study->window); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(dialog)); selected_objects = ui_common_init_dialog_selected_objects(dialog); gtk_widget_destroy(dialog); /* we want to render */ if (return_val == AMITK_RESPONSE_EXECUTE) { ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); ui_render_create(ui_study->study, selected_objects, ui_study->preferences); ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); } selected_objects = amitk_objects_unref(selected_objects); return; } #endif /* do roi calculations */ void ui_study_cb_roi_statistics(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; GtkWidget * dialog; gint return_val; /* let the user input roi analysis options */ dialog = tb_roi_analysis_init_dialog(ui_study->window); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); if (return_val != AMITK_RESPONSE_EXECUTE) return; /* we hit cancel */ ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); tb_roi_analysis(ui_study->study, ui_study->preferences, ui_study->window); ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); return; } /* user wants to run the alignment wizard */ void ui_study_cb_alignment_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; tb_alignment(ui_study->study, ui_study->window); return; } /* user wants to run the crop wizard */ void ui_study_cb_crop_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; if (!AMITK_IS_DATA_SET(ui_study->active_object)) g_warning("%s",no_active_ds); else tb_crop(ui_study->study, AMITK_DATA_SET(ui_study->active_object), ui_study->window); return; } /* user wants to run the distance wizard */ void ui_study_cb_distance_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; tb_distance(ui_study->study, ui_study->window); return; } /* user wants to run the fads wizard */ void ui_study_cb_fads_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; if (!AMITK_IS_DATA_SET(ui_study->active_object)) g_warning("%s",no_active_ds); else { #ifdef AMIDE_LIBGSL_SUPPORT tb_fads(AMITK_DATA_SET(ui_study->active_object), ui_study->preferences, ui_study->window); #else g_warning("%s",no_gsl); #endif } return; } /* user wants to run the filter wizard */ void ui_study_cb_filter_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; if (!AMITK_IS_DATA_SET(ui_study->active_object)) g_warning("%s",no_active_ds); else tb_filter(ui_study->study, AMITK_DATA_SET(ui_study->active_object), ui_study->window); return; } /* user wants to run the profile wizard */ void ui_study_cb_profile_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; tb_profile(ui_study->study, ui_study->preferences, ui_study->window); return; } /* user wants to run the image math wizard */ void ui_study_cb_data_set_math_selected(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; tb_math(ui_study->study, ui_study->window); return; } static gboolean threshold_delete_event(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_study_t * ui_study = data; /* just keeping track on whether or not the threshold widget is up */ ui_study->threshold_dialog = NULL; return FALSE; } /* function called when target button toggled on toolbar */ void ui_study_cb_canvas_target(GtkToggleAction * action, gpointer data) { ui_study_t * ui_study = data; amitk_study_set_canvas_target(ui_study->study, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); } /* function called when hitting the threshold button, pops up a dialog */ void ui_study_cb_thresholding(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; if (!AMITK_IS_DATA_SET(ui_study->active_object)) return; /* make sure we don't already have a data set edit dialog up */ if ((ui_study->active_object->dialog == NULL) && (ui_study->threshold_dialog == NULL)) { ui_common_place_cursor(UI_CURSOR_WAIT, ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); ui_study->threshold_dialog = amitk_threshold_dialog_new(AMITK_DATA_SET(ui_study->active_object), ui_study->window); ui_common_remove_wait_cursor(ui_study->canvas[AMITK_VIEW_MODE_SINGLE][AMITK_VIEW_TRANSVERSE]); g_signal_connect(G_OBJECT(ui_study->threshold_dialog), "delete_event", G_CALLBACK(threshold_delete_event), ui_study); gtk_widget_show(ui_study->threshold_dialog); } else { /* pop the window to the top */ if (ui_study->active_object->dialog) gtk_window_present(GTK_WINDOW(ui_study->active_object->dialog)); else gtk_window_present(GTK_WINDOW(ui_study->threshold_dialog)); } return; } /* callback function for adding an roi */ void ui_study_cb_add_roi(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; AmitkRoiType roi_type; /* figure out which menu item called me */ roi_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"roi_type")); ui_study_add_roi(ui_study, AMITK_OBJECT(ui_study->study), roi_type); return; } /* callback function for adding a fiducial mark */ void ui_study_cb_add_fiducial_mark(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; if (AMITK_IS_DATA_SET(ui_study->active_object)) { ui_study_add_fiducial_mark(ui_study, ui_study->active_object, TRUE, AMITK_STUDY_VIEW_CENTER(ui_study->study)); } return; } /* callback function for changing user's preferences */ void ui_study_cb_preferences(GtkAction * action, gpointer data) { ui_study_t * ui_study=data; ui_preferences_dialog_create(ui_study); return; } /* function to switch the interpolation method */ void ui_study_cb_interpolation(GtkRadioAction * action, GtkRadioAction * current, gpointer data) { ui_study_t * ui_study = data; g_return_if_fail(AMITK_IS_DATA_SET(ui_study->active_object)); amitk_data_set_set_interpolation(AMITK_DATA_SET(ui_study->active_object), gtk_radio_action_get_current_value((GTK_RADIO_ACTION(current)))); return; } /* function to switch the rendering method */ void ui_study_cb_rendering(GtkWidget * widget, gpointer data) { ui_study_t * ui_study = data; g_return_if_fail(AMITK_IS_DATA_SET(ui_study->active_object)); amitk_data_set_set_rendering(AMITK_DATA_SET(ui_study->active_object), gtk_combo_box_get_active(GTK_COMBO_BOX(widget))); return; } void ui_study_cb_study_changed(AmitkStudy * study, gpointer data) { ui_study_t * ui_study = data; ui_study_update_time_button(ui_study); ui_study_update_canvas_target(ui_study); return; } void ui_study_cb_thickness_changed(AmitkStudy * study, gpointer data) { ui_study_t * ui_study = data; ui_study_update_thickness(ui_study, AMITK_STUDY_VIEW_THICKNESS(ui_study->study)); return; } void ui_study_cb_canvas_layout_changed(AmitkStudy * study, gpointer data) { ui_study_t * ui_study = data; ui_study_update_canvas_visible_buttons(ui_study); ui_study_update_layout(ui_study); return; } void ui_study_cb_voxel_dim_or_zoom_changed(AmitkStudy * study, gpointer data) { ui_study_t * ui_study = data; ui_study_update_zoom(ui_study); return; } void ui_study_cb_fov_changed(AmitkStudy * study, gpointer data) { ui_study_t * ui_study = data; ui_study_update_fov(ui_study); return; } /* function to switch the image fusion type */ void ui_study_cb_fuse_type(GtkRadioAction * action, GtkRadioAction * current, gpointer data) { ui_study_t * ui_study = data; amitk_study_set_fuse_type(ui_study->study, gtk_radio_action_get_current_value((GTK_RADIO_ACTION(current)))); ui_study_update_fuse_type(ui_study); return; } void ui_study_cb_canvas_visible(GtkToggleAction * action, gpointer data) { ui_study_t * ui_study = data; AmitkView view; view = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action),"view")); amitk_study_set_canvas_visible(ui_study->study, view, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); ui_study_update_canvas_visible_buttons(ui_study); return; } void ui_study_cb_view_mode(GtkRadioAction * action, GtkRadioAction * current, gpointer data) { ui_study_t * ui_study = data; amitk_study_set_view_mode(ui_study->study, gtk_radio_action_get_current_value((GTK_RADIO_ACTION(current)))); ui_study_update_view_mode(ui_study); return; } /* function ran to exit the program */ void ui_study_cb_quit(GtkAction * action, gpointer data) { ui_study_t * ui_study = data; GtkWindow * window = ui_study->window; gboolean return_val; /* run the delete event function */ g_signal_emit_by_name(G_OBJECT(window), "delete_event", NULL, &return_val); if (!return_val) { /* if we don't cancel the quit */ gtk_widget_destroy(GTK_WIDGET(window)); amide_unregister_all_windows(); /* kill everything */ } return; } /* function ran when closing a study window */ void ui_study_cb_close(GtkAction* action, gpointer data) { ui_study_t * ui_study = data; GtkWindow * window = ui_study->window; gboolean return_val; /* run the delete event function */ g_signal_emit_by_name(G_OBJECT(window), "delete_event", NULL, &return_val); if (!return_val) gtk_widget_destroy(GTK_WIDGET(window)); return; } /* function to run for a delete_event */ gboolean ui_study_cb_delete_event(GtkWidget* widget, GdkEvent * event, gpointer data) { ui_study_t * ui_study = data; GtkWindow * window = ui_study->window; GtkWidget * exit_dialog; gint return_val; /* check to see if we need saving */ if ((ui_study->study_altered == TRUE) && (AMITK_PREFERENCES_PROMPT_FOR_SAVE_ON_EXIT(ui_study->preferences))) { exit_dialog = gtk_message_dialog_new(ui_study->window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, _("There are unsaved changes to the study.\nAre you sure you wish to quit?")); /* and wait for the question to return */ return_val = gtk_dialog_run(GTK_DIALOG(exit_dialog)); gtk_widget_destroy(exit_dialog); if (return_val != GTK_RESPONSE_OK) return TRUE; /* cancel */ } ui_study = ui_study_free(ui_study); /* free our data structure's */ amide_unregister_window((gpointer) window); /* tell the rest of the program this window's gone */ return FALSE; } amide-1.0.6/amide-current/src/ui_study_cb.h000066400000000000000000000127241423227705100206160ustar00rootroot00000000000000/* ui_study_cb.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* external functions */ void ui_study_cb_open_xif_file(GtkAction * action, gpointer ui_study); void ui_study_cb_open_xif_dir(GtkAction * action, gpointer ui_study); void ui_study_cb_import_object_from_xif_file(GtkAction * action, gpointer data); void ui_study_cb_import_object_from_xif_dir(GtkAction * action, gpointer data); void ui_study_cb_recover_xif_file(GtkAction * action, gpointer data); void ui_study_cb_new_study(GtkAction * action, gpointer ui_study); void ui_study_cb_save_as_xif_file(GtkAction * action, gpointer data); void ui_study_cb_save_as_xif_dir(GtkAction * action, gpointer data); void ui_study_cb_import(GtkAction * action, gpointer data); void ui_study_cb_export_view(GtkAction * action, gpointer data); void ui_study_cb_export_data_set(GtkAction * action, gpointer data); gboolean ui_study_cb_update_help_info(GtkWidget * widget, GdkEventCrossing * event, gpointer data); void ui_study_cb_canvas_help_event(GtkWidget * canvas, AmitkHelpInfo help_type, AmitkPoint *location, amide_data_t value, gpointer ui_study); void ui_study_cb_canvas_view_changing(GtkWidget * canvas, AmitkPoint *position, amide_real_t thickness, gpointer ui_study); void ui_study_cb_canvas_view_changed(GtkWidget * canvas, AmitkPoint *position, amide_real_t thickness, gpointer ui_study); void ui_study_cb_canvas_erase_volume(GtkWidget * canvas, AmitkRoi * roi, gboolean outside, gpointer ui_study); void ui_study_cb_canvas_new_object(GtkWidget * canvas, AmitkObject * parent, AmitkObjectType type, AmitkPoint *position, gpointer ui_study); void ui_study_cb_tree_view_activate_object(GtkWidget * tree_view, AmitkObject * object, gpointer ui_study); void ui_study_cb_tree_view_popup_object(GtkWidget * tree_view, AmitkObject * object, gpointer ui_study); void ui_study_cb_tree_view_add_object(GtkWidget * tree_view, AmitkObject * parent, AmitkObjectType object_type, AmitkRoiType roi_type, gpointer ui_study); void ui_study_cb_tree_view_delete_object(GtkWidget * tree_view,AmitkObject * object, gpointer ui_study); void ui_study_cb_tree_view_help_event(GtkWidget * widget, AmitkHelpInfo help_type, gpointer ui_study); void ui_study_cb_zoom(GtkSpinButton * spin_button, gpointer ui_study); void ui_study_cb_fov(GtkSpinButton * spin_button, gpointer ui_study); void ui_study_cb_thickness(GtkSpinButton * spin_button, gpointer ui_study); void ui_study_cb_gate(GtkWidget * button, gpointer data); void ui_study_cb_time(GtkWidget * button, gpointer data); void ui_study_cb_series(GtkAction * action, gpointer ui_study); #if (AMIDE_FFMPEG_SUPPORT || AMIDE_LIBFAME_SUPPORT) void ui_study_cb_fly_through(GtkAction * action, gpointer ui_study); #endif #ifdef AMIDE_LIBVOLPACK_SUPPORT void ui_study_cb_render(GtkAction * action, gpointer data); #endif void ui_study_cb_roi_statistics(GtkAction * action, gpointer data); void ui_study_cb_alignment_selected(GtkAction * action, gpointer data); void ui_study_cb_crop_selected(GtkAction * action, gpointer data); void ui_study_cb_distance_selected(GtkAction * action, gpointer data); void ui_study_cb_fads_selected(GtkAction * action, gpointer data); void ui_study_cb_filter_selected(GtkAction * action, gpointer data); void ui_study_cb_profile_selected(GtkAction * action, gpointer data); void ui_study_cb_data_set_math_selected(GtkAction * action, gpointer data); void ui_study_cb_canvas_target(GtkToggleAction * action, gpointer data); void ui_study_cb_thresholding(GtkAction * action, gpointer data); void ui_study_cb_add_roi(GtkWidget * widget, gpointer data); void ui_study_cb_add_fiducial_mark(GtkAction * action, gpointer data); void ui_study_cb_preferences(GtkAction * action, gpointer data); void ui_study_cb_interpolation(GtkRadioAction * action, GtkRadioAction * current, gpointer data); void ui_study_cb_rendering(GtkWidget * widget, gpointer data); void ui_study_cb_study_changed(AmitkStudy * study, gpointer ui_study); void ui_study_cb_thickness_changed(AmitkStudy * study, gpointer data); void ui_study_cb_canvas_layout_changed(AmitkStudy * study, gpointer ui_study); void ui_study_cb_voxel_dim_or_zoom_changed(AmitkStudy * study, gpointer ui_study); void ui_study_cb_fov_changed(AmitkStudy * study, gpointer ui_study); void ui_study_cb_fuse_type(GtkRadioAction * action, GtkRadioAction * current, gpointer data); void ui_study_cb_canvas_visible(GtkToggleAction * action, gpointer ui_study); void ui_study_cb_view_mode(GtkRadioAction * action, GtkRadioAction * current, gpointer data); void ui_study_cb_quit(GtkAction* action, gpointer data); void ui_study_cb_close(GtkAction* action, gpointer data); gboolean ui_study_cb_delete_event(GtkWidget* widget, GdkEvent * event, gpointer data); amide-1.0.6/amide-current/src/ui_time_dialog.c000066400000000000000000000440201423227705100212440ustar00rootroot00000000000000/* ui_time_dialog.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include #include "amide.h" #include "ui_time_dialog.h" #define SPIN_BUTTON_X_SIZE 100 typedef enum { COLUMN_START, COLUMN_END, COLUMN_FRAME, COLUMN_NAME, COLUMN_DATA_SET, NUM_COLUMNS } column_type_t; static gboolean column_use_my_renderer[NUM_COLUMNS] = { TRUE, TRUE, FALSE, FALSE, FALSE }; enum { ENTRY_START, ENTRY_END, NUM_ENTRIES }; static gchar * column_names[] = { N_("Start (s)"), N_("End (s)"), N_("Frame #"), N_("Data Set"), "error - shouldn't be used" }; typedef struct ui_time_dialog_t { amide_time_t start; amide_time_t end; gboolean valid; AmitkStudy * study; GList * data_sets; GtkWidget * tree_view; GtkWidget * start_spin; GtkWidget * end_spin; } ui_time_dialog_t; static void selection_for_each_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); static void selection_changed_cb (GtkTreeSelection *selection, gpointer data); static gboolean delete_event_cb(GtkWidget* dialog, GdkEvent * event, gpointer data); static void change_spin_cb(GtkSpinButton * spin_button, gpointer data); static void update_model(GtkListStore * store, GtkTreeSelection *selection, GList * data_sets); static void update_selections(GtkTreeModel * model, GtkTreeSelection *selection, GtkWidget * dialog, ui_time_dialog_t * td); static void update_entries(GtkWidget * dialog, ui_time_dialog_t * td); static void data_set_time_changed_cb(AmitkDataSet * ds, gpointer dialog); static void add_data_set(GtkWidget * dialog, AmitkDataSet * ds); static void remove_data_set(GtkWidget * dialog, AmitkDataSet * ds); static void selection_for_each_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { amide_time_t start, end, old_end; ui_time_dialog_t * td = data; gtk_tree_model_get(model, iter, COLUMN_START, &start, COLUMN_END, &end, -1); /* save our new times */ if (td->valid) { old_end = td->end; if (start < td->start) td->start = start+EPSILON*fabs(start); if (end > old_end) td->end = end-EPSILON*fabs(end); else td->end = old_end-EPSILON*fabs(old_end); } else { td->valid = TRUE; td->start = start+EPSILON*fabs(start); td->end = end-EPSILON*fabs(end); } return; } /* reset out start and duration based on what just got selected */ static void selection_changed_cb (GtkTreeSelection *selection, gpointer data) { GtkWidget * dialog = data; GtkTreeView * tree_view; GtkTreeModel * model; ui_time_dialog_t * td; td = g_object_get_data(G_OBJECT(dialog), "td"); td->valid = FALSE; /* run the following function on each selected row */ gtk_tree_selection_selected_foreach(selection, selection_for_each_func, td); if (!td->valid) td->valid = TRUE; /* reset selected rows to old values */ tree_view = gtk_tree_selection_get_tree_view(selection); model = gtk_tree_view_get_model(tree_view); update_selections(model, selection, dialog, td); update_entries(dialog, td); amitk_study_set_view_start_time(td->study, td->start); amitk_study_set_view_duration(td->study, td->end-td->start); return; } /* function called to destroy the time dialog */ static gboolean delete_event_cb(GtkWidget* dialog, GdkEvent * event, gpointer data) { ui_time_dialog_t * td = data; GtkTreeSelection *selection; /* explicitly disconnect signals, sometimes GTK throws some of these on delete (after unref'ing study */ g_signal_handlers_disconnect_by_func(G_OBJECT(td->start_spin), G_CALLBACK(change_spin_cb), dialog); g_signal_handlers_disconnect_by_func(G_OBJECT(td->end_spin), G_CALLBACK(change_spin_cb), dialog); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (td->tree_view)); g_signal_handlers_disconnect_by_func(G_OBJECT(selection), G_CALLBACK(selection_changed_cb), dialog); /* trash collection */ while(td->data_sets != NULL) remove_data_set(dialog, td->data_sets->data); if (td->study != NULL) td->study = amitk_object_unref(td->study); g_free(td); return FALSE; } /* function called when a numerical spin button has been changed */ static void change_spin_cb(GtkSpinButton * spin_button, gpointer data) { gdouble temp_val; gint which_widget; GtkWidget * dialog = data; ui_time_dialog_t * td; GtkTreeSelection *selection; GtkTreeModel * model; which_widget = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spin_button), "type")); td = g_object_get_data(G_OBJECT(dialog), "td"); temp_val = gtk_spin_button_get_value(spin_button); switch(which_widget) { case ENTRY_START: if (temp_val-EPSILON*fabs(temp_val) > td->end) td->start = td->end-EPSILON*fabs(td->end); else td->start = temp_val; break; case ENTRY_END: if (temp_val+EPSILON*fabs(temp_val) < td->start) td->end = td->start+EPSILON*fabs(td->start); else td->end = temp_val; break; } model = gtk_tree_view_get_model(GTK_TREE_VIEW(td->tree_view)); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(td->tree_view)); update_selections(model, selection, dialog, td); update_entries(dialog, td); amitk_study_set_view_start_time(td->study, td->start); amitk_study_set_view_duration(td->study, td->end-td->start); return; } static void update_model(GtkListStore * store, GtkTreeSelection *selection, GList * data_sets) { GList * sets; AmitkDataSet * min_ds; guint num_sets; guint i_ds, min_ds_num; guint * frames; guint total_frames=0; guint current_frames; amide_time_t min, temp; GtkTreeIter iter; gtk_list_store_clear(store); /* make sure the list is clear */ /* count the number of data setss */ sets = data_sets; num_sets=0; while (sets != NULL) { num_sets++; total_frames += AMITK_DATA_SET_NUM_FRAMES(sets->data); sets = sets->next; } /* get space for the array that'll take care of which frame of which data set we're looking at*/ frames = g_try_new(guint,num_sets); if ((frames == NULL) && (num_sets !=0)) { g_warning(_("can't count frames or allocate memory!")); return; } /* initialize */ for (i_ds = 0; i_dsdata) <= frames[i_ds]) { sets = sets->next; /* advancing to a data set that still has frames left */ i_ds++; } min_ds = AMITK_DATA_SET(sets->data); min_ds_num = i_ds; min = amitk_data_set_get_start_time(min_ds,frames[i_ds]); sets = sets->next; i_ds++; while (sets != NULL) { if (frames[i_ds] < AMITK_DATA_SET_NUM_FRAMES(sets->data)) { temp = amitk_data_set_get_start_time(AMITK_DATA_SET(sets->data), frames[i_ds]); if (temp < min) { min_ds = AMITK_DATA_SET(sets->data); min = temp; min_ds_num = i_ds; } } i_ds++; sets = sets->next; } /* we now have the next minimum start time */ /* setup the corresponding list entry */ gtk_list_store_append (store, &iter); /* Acquire an iterator */ gtk_list_store_set (store, &iter, COLUMN_START, min, COLUMN_END, min+amitk_data_set_get_frame_duration(min_ds,frames[min_ds_num]), COLUMN_FRAME,frames[min_ds_num], COLUMN_NAME,AMITK_OBJECT_NAME(min_ds), COLUMN_DATA_SET, min_ds,-1); frames[min_ds_num]++; current_frames++; } /* freeup our allocated data structures */ g_free(frames); return; } static void update_selections(GtkTreeModel * model, GtkTreeSelection *selection, GtkWidget * dialog, ui_time_dialog_t * td) { AmitkDataSet * ds; gboolean ds_used; GtkTreeIter iter; gint iter_frame; amide_time_t iter_start, iter_end; GList * used_sets=NULL;; /* Block signals to this list widget. I need to do this, as I'll be selecting rows, causing the emission of "changed" signals */ g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(selection_changed_cb), dialog); if (gtk_tree_model_get_iter_first(model, &iter)) { do { gtk_tree_model_get(model, &iter, COLUMN_START, &iter_start, COLUMN_END, &iter_end, COLUMN_FRAME, &iter_frame, COLUMN_DATA_SET, &ds,-1); /* see if we've already marked a frame in this data set */ ds_used = (g_list_index(used_sets, ds) >= 0); /* figure out if this row is suppose to be selected */ if (((td->start <= iter_start) && ((td->end) > iter_start)) || ((td->start <= (iter_end)) && ((td->end) > (iter_end))) || ((td->start > (iter_start)) &&((td->end) < (iter_end)))) { gtk_tree_selection_select_iter(selection, &iter); if (!ds_used) used_sets = g_list_append(used_sets, ds); } else if ((!ds_used) && (iter_frame == 0) && (td->start < iter_start)) { /* special case #1 this is the first frame in the data set and it's still behind the time, so select it anyway */ gtk_tree_selection_select_iter(selection, &iter); used_sets = g_list_append(used_sets, ds); } else if ((!ds_used) && (iter_frame == AMITK_DATA_SET_NUM_FRAMES(ds)-1) && (td->start > iter_end)) { /* special case #2 this is the last frame in the data set and no other frame has been selected, so select this one anyway */ gtk_tree_selection_select_iter(selection, &iter); used_sets = g_list_append(used_sets, ds); } else { gtk_tree_selection_unselect_iter(selection, &iter); } } while(gtk_tree_model_iter_next(model, &iter)); } g_list_free(used_sets); /* done updating the list, we can reconnect signals now */ g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(selection_changed_cb), dialog); return; } static void update_entries(GtkWidget * dialog, ui_time_dialog_t * td) { g_signal_handlers_block_by_func(G_OBJECT(td->start_spin), G_CALLBACK(change_spin_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(td->start_spin), td->start); g_signal_handlers_unblock_by_func(G_OBJECT(td->start_spin), G_CALLBACK(change_spin_cb), dialog); g_signal_handlers_block_by_func(G_OBJECT(td->end_spin), G_CALLBACK(change_spin_cb), dialog); gtk_spin_button_set_value(GTK_SPIN_BUTTON(td->end_spin), td->end); g_signal_handlers_unblock_by_func(G_OBJECT(td->end_spin), G_CALLBACK(change_spin_cb), dialog); return; } static void data_set_time_changed_cb(AmitkDataSet * ds, gpointer data) { GtkWidget * dialog = data; ui_time_dialog_set_times(dialog); } static void add_data_set(GtkWidget * dialog, AmitkDataSet * ds) { ui_time_dialog_t * td; td = g_object_get_data(G_OBJECT(dialog), "td"); td->data_sets = g_list_append(td->data_sets, amitk_object_ref(ds)); g_signal_connect(G_OBJECT(ds), "time_changed", G_CALLBACK(data_set_time_changed_cb), dialog); return; } static void remove_data_set(GtkWidget * dialog, AmitkDataSet * ds) { ui_time_dialog_t * td; td = g_object_get_data(G_OBJECT(dialog), "td"); g_return_if_fail(g_list_index(td->data_sets, ds) >= 0); g_signal_handlers_disconnect_by_func(G_OBJECT(ds), G_CALLBACK(data_set_time_changed_cb), dialog); td->data_sets = g_list_remove(td->data_sets, ds); amitk_object_unref(ds); return; } /* function to setup the time combo widget */ void ui_time_dialog_set_times(GtkWidget * dialog) { ui_time_dialog_t * td; GtkTreeSelection *selection; GtkTreeModel * model; GList * selected_sets; GList * temp_sets; g_return_if_fail(dialog != NULL); td = g_object_get_data(G_OBJECT(dialog), "td"); while(td->data_sets != NULL) remove_data_set(dialog, td->data_sets->data); selected_sets = amitk_object_get_selected_children_of_type(AMITK_OBJECT(td->study), AMITK_OBJECT_TYPE_DATA_SET, AMITK_SELECTION_ANY, TRUE); temp_sets = selected_sets; while (temp_sets != NULL) { add_data_set(dialog, temp_sets->data); temp_sets = temp_sets->next; } amitk_objects_unref(selected_sets); model = gtk_tree_view_get_model(GTK_TREE_VIEW(td->tree_view)); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(td->tree_view)); update_model(GTK_LIST_STORE(model), selection,td->data_sets); update_selections(model, selection, dialog, td); update_entries(dialog, td); return; } /* create the time selection dialog */ GtkWidget * ui_time_dialog_create(AmitkStudy * study, GtkWindow * parent) { GtkWidget * dialog; gchar * temp_string = NULL; GtkWidget * packing_table; GtkWidget * label; GtkWidget * scrolled; guint table_row = 0; ui_time_dialog_t * td; GtkListStore * store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; GtkWidget * hseparator; column_type_t i_column; temp_string = g_strdup_printf(_("%s: Time Dialog"),PACKAGE); dialog = gtk_dialog_new_with_buttons(temp_string, parent, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, NULL); g_free(temp_string); gtk_window_set_resizable(GTK_WINDOW(dialog), TRUE); /* make (and save a pointer to) a structure to temporary hold the new time and duration */ td = g_try_new(ui_time_dialog_t, 1); g_return_val_if_fail(td != NULL, NULL); td->start = AMITK_STUDY_VIEW_START_TIME(study); td->end = td->start+AMITK_STUDY_VIEW_DURATION(study); td->valid = TRUE; td->study = amitk_object_ref(study); td->data_sets = NULL; g_object_set_data(G_OBJECT(dialog), "td", td); /* setup the callbacks for the dialog */ g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(delete_event_cb), td); /* start making the widgets for this dialog box */ packing_table = gtk_table_new(4,4,FALSE); table_row=0; gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), packing_table); label = gtk_label_new(_("Start (s)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); td->start_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(td->start_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(td->start_spin), td->start); g_object_set_data(G_OBJECT(td->start_spin), "type", GINT_TO_POINTER(ENTRY_START)); gtk_widget_set_size_request(td->start_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(td->start_spin), "value_changed", G_CALLBACK(change_spin_cb), dialog); g_signal_connect(G_OBJECT(td->start_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), td->start_spin,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; label = gtk_label_new(_("End (s)")); gtk_table_attach(GTK_TABLE(packing_table), label, 0,1, table_row, table_row+1, 0, 0, X_PADDING, Y_PADDING); td->end_spin = gtk_spin_button_new_with_range(-G_MAXDOUBLE, G_MAXDOUBLE, 1.0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(td->end_spin), FALSE); gtk_spin_button_set_value(GTK_SPIN_BUTTON(td->end_spin), td->end); g_object_set_data(G_OBJECT(td->end_spin), "type", GINT_TO_POINTER(ENTRY_END)); gtk_widget_set_size_request(td->end_spin, SPIN_BUTTON_X_SIZE, -1); g_signal_connect(G_OBJECT(td->end_spin), "value_changed", G_CALLBACK(change_spin_cb), dialog); g_signal_connect(G_OBJECT(td->end_spin), "output", G_CALLBACK(amitk_spin_button_scientific_output), NULL); gtk_table_attach(GTK_TABLE(packing_table), td->end_spin,1,2, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* a separator for clarity */ hseparator = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(packing_table), hseparator, 0, 4, table_row, table_row+1, GTK_FILL, 0, X_PADDING, Y_PADDING); table_row++; /* the scroll widget which the list will go into */ scrolled = gtk_scrolled_window_new(NULL,NULL); gtk_widget_set_size_request(scrolled,350,200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_table_attach(GTK_TABLE(packing_table), scrolled, 0,2, table_row, table_row+1, X_PACKING_OPTIONS | GTK_FILL, Y_PACKING_OPTIONS | GTK_FILL, X_PADDING, Y_PADDING); table_row++; /* and the list itself */ store = gtk_list_store_new(NUM_COLUMNS, AMITK_TYPE_TIME, AMITK_TYPE_TIME, G_TYPE_INT, G_TYPE_STRING, G_TYPE_POINTER); td->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref(store); for (i_column=0; i_columntree_view), column); } selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (td->tree_view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (selection_changed_cb), dialog); gtk_container_add(GTK_CONTAINER(scrolled),td->tree_view); /* fill in the list */ ui_time_dialog_set_times(dialog); /* and show all our widgets */ gtk_widget_show_all(dialog); return dialog; } amide-1.0.6/amide-current/src/ui_time_dialog.h000066400000000000000000000021131423227705100212460ustar00rootroot00000000000000/* ui_time_dialog.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2000-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* header files always needed with this */ #include "amitk_study.h" /* external functions */ void ui_time_dialog_set_times(GtkWidget * time_dialog); GtkWidget * ui_time_dialog_create(AmitkStudy * study, GtkWindow * parent); amide-1.0.6/amide-current/src/variable_type.m4000066400000000000000000000060331423227705100212200ustar00rootroot00000000000000m4_dnl variable_type.m4 m4_dnl m4_dnl Part of amide - AMIDE's a Medical Image Data Examiner m4_dnl Copyright (c) 2001-2017 Andy Loening m4_dnl m4_dnl Author: Andy Loening m4_dnl m4_dnl m4_dnl This is an m4 file that specifies functions which are dependent m4_dnl on the internal data type of the data set. m4_dnl m4_dnl Specifying this as an m4 file allows there to exist only m4_dnl one version of the algorithms which can be optimized for m4_dnl each of the internal data formats and scaling modes or roi types. m4_dnl m4_dnl to convert this into a c file, run this file through the m4_dnl m4 process with "m4_SourceFile" defined in the form: m4_dnl *_*.c m4_dnl where the first wildcard is the base file name (roi, volume, data_set) m4_dnl and the second wildwcard specifies the data format (UBYTE, SBYTE, etc.), m4_dnl data format and scaling mode (UBYTE_0D, etc.) or roi type, (ELLIPSOID, m4_dnl BOX, etc.) as appropriate. m4_dnl m4_dnl m4_dnl m4 needs to be ran with the -P option m4_dnl m4_dnl m4_dnl m4_dnl m4_dnl Warning message for the generated file /* Do not edit this file, it is generated automatically from variable_type.m4 */ m4_dnl m4_dnl m4_dnl Figure out what internal data format/roi type we're making m4_ifdef(`m4_SourceFile', ` m4_define(m4_File_Base_Name, `m4_substr(m4_SourceFile, 0, m4_regexp(m4_SourceFile,`_[A-Z]'))') m4_define(m4_Temp_Variable_Type, `m4_substr(m4_SourceFile, m4_eval(m4_regexp(m4_SourceFile,`_[A-Z]')+1), m4_eval(m4_index(m4_SourceFile,`.')-m4_regexp(m4_SourceFile,`_[A-Z]')-1))') m4_define(m4_File_Type, `m4_substr(m4_SourceFile, m4_eval(m4_index(m4_SourceFile, `.')+1), 1)') ',` ``Must Define m4_SourceFile'' m4_m4exit') m4_dnl m4_dnl extract any additional information out of "Temp_Variable_Type" m4_dnl m4_ifelse(m4_regexp(m4_Temp_Variable_Type, `_'), `-1',` m4_dnl [^-]* matches everything but the ldash... using this as a poor man's wild card m4_ifelse(m4_regexp(m4_Temp_Variable_Type, `_[^-]*_'), `-1',` m4_define(m4_Variable_Type, m4_Temp_Variable_Type) m4_define(m4_Scale_Dim, `') ',` m4_ifelse(m4_regexp(m4_Temp_Variable_Type, `_INTERCEPT'), `-1',` m4_define(m4_Scale_Dim, `m4_substr(m4_Temp_Variable_Type, m4_eval(m4_regexp(m4_Temp_Variable_Type, `_')+1))') m4_define(m4_Intercept, `') ',` m4_define(m4_Scale_Dim, `m4_substr(m4_Temp_Variable_Type, m4_eval(m4_regexp(m4_Temp_Variable_Type, `_')+1), m4_eval(m4_regexp(m4_Temp_Variable_Type, `_INTERCEPT')- m4_regexp(m4_Temp_Variable_Type, `_')-1))') m4_define(m4_Intercept, `INTERCEPT_') ') m4_define(m4_Variable_Type, `m4_substr(m4_Temp_Variable_Type, 0, m4_regexp(m4_Temp_Variable_Type, `_'))') ') m4_dnl m4_dnl /* m4_SourceFile * * generated from the following file: */ m4_dnl m4_dnl m4_dnl change the delimiter, so we don't lose pound signs in the files m4_changecom(~,~) m4_dnl m4_ifelse(m4_File_Type, `h', `m4_include(m4_format(`%s_%s', m4_File_Base_Name,`variable_type.h'))', `m4_include(m4_format(`%s_%s', m4_File_Base_Name,`variable_type.c'))') m4_dnl m4_dnl end of m4 file amide-1.0.6/amide-current/src/vistaio_interface.c000066400000000000000000000367461423227705100220100ustar00rootroot00000000000000/* -*- c-basic-offset: 2; -*- * vistaio_interface.c * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2016-2017 Gert Wolny * * Author: Gert Wollny */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "amide_config.h" #ifdef AMIDE_VISTAIO_SUPPORT #include "amitk_data_set.h" #include "amitk_data_set_DOUBLE_0D_SCALING.h" #include "vistaio_interface.h" #include #include #include gboolean vistaio_test_vista(gchar *filename) { return VistaIOIsVistaFile(filename); } static VistaIOBoolean vistaio_get_pixel_signedness(VistaIOImage image); static VistaIOBoolean vistaio_get_3dvector(VistaIOImage image, const gchar* name, AmitkPoint *voxel); static VistaIOBoolean vistaio_get_rotation(VistaIOImage image, AmitkAxes matrix); static VistaIOBoolean vistaio_get_voxelsize_from2d(VistaIOImage image, AmitkPoint *voxel); static AmitkDataSet * do_vistaio_import(const gchar * filename, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data); AmitkDataSet * vistaio_import(const gchar * filename, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { AmitkDataSet *retval = NULL; gchar * saved_time_locale; gchar * saved_numeric_locale; saved_time_locale = g_strdup(setlocale(LC_TIME,NULL)); saved_numeric_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_TIME,"POSIX"); setlocale(LC_NUMERIC,"POSIX"); retval = do_vistaio_import(filename, preferences, update_func, update_data); setlocale(LC_NUMERIC, saved_time_locale); setlocale(LC_NUMERIC, saved_numeric_locale); g_free(saved_time_locale); g_free(saved_numeric_locale); return retval; } typedef struct _IOUpdate IOUpdate; struct _IOUpdate { AmitkUpdateFunc update_func; gpointer update_data; gboolean cont; gchar *message; }; static void AmitkIOShowProgress(int pos, int length, void *data) { IOUpdate *update; g_assert(data); update = (IOUpdate *)data; if (update->update_func) { update->cont = (*update->update_func)(update->update_data, update->message, ((gdouble) pos)/((gdouble) length)); } } AmitkDataSet * do_vistaio_import(const gchar * filename, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data) { AmitkVoxel dim; AmitkFormat format; AmitkPoint voxel = {1, 1, 1}; AmitkPoint origin = {0, 0, 0}; AmitkModality modality = AMITK_MODALITY_MRI; AmitkDataSet * ds=NULL; AmitkAxes new_axes; VistaIOImage *images = NULL; VistaIOAttrList attr_list = NULL; VistaIORepnKind in_pixel_repn = VistaIOUnknownRepn; VistaIOBoolean is_pixel_unsigned = FALSE; VistaIOBoolean origin_found = FALSE; VistaIOBoolean voxelsize_found = FALSE; VistaIOBoolean rotation_found = FALSE; int nimages = 0; gboolean images_good = TRUE; gboolean convert = FALSE; gint format_size; gint bytes_per_image; gint i, t; void *ds_pointer = NULL; IOUpdate update; /* first read the file */ FILE *f = fopen(filename, "rb"); if (!f) { g_warning(_("Can't open file %s "), filename); goto error; } update.update_func = update_func; update.update_data = update_data; update.cont = TRUE; if (update_func != NULL) { update.message = g_strdup_printf(_("Loading file %s"), filename); } VistaIOSetProgressIndicator(AmitkIOShowProgress, AmitkIOShowProgress, &update); nimages = VistaIOReadImages(f, &attr_list, &images); if (update_func != NULL) { g_free(update.message); (*update_func)(update_data, NULL, (gdouble) 2.0); } if (!update.cont) { g_debug("User interrupt"); goto error1; } // a vista file? if (!nimages) { g_warning(_("File %s doesn't contain vista image(s)"), filename); goto error; } /* amide data sets don't seem to support images of different sizes so here we check that all images are of the same type and dimensions */ /* get proto type from first image */ dim.x = VistaIOImageNColumns(images[0]); dim.y = VistaIOImageNRows(images[0]); dim.z = VistaIOImageNBands(images[0]); in_pixel_repn = VistaIOPixelRepn(images[0]); is_pixel_unsigned = vistaio_get_pixel_signedness(images[0]); voxelsize_found = vistaio_get_3dvector(images[0], "voxel", &voxel); if (!voxelsize_found) { voxelsize_found = vistaio_get_voxelsize_from2d(images[0], &voxel); } origin_found = vistaio_get_3dvector(images[0], "origin3d", &origin); if (!origin_found) origin_found = vistaio_get_3dvector(images[0], "position", &origin); rotation_found = vistaio_get_rotation(images[0], new_axes); g_debug("Prototype image is: %dx%dx%d, repn:%d(%d), origin: (%f %f %f), voxelsize (%f %f %f)", dim.x, dim.y, dim.z, in_pixel_repn, is_pixel_unsigned, origin.x, origin.y, origin.z, voxel.x, voxel.y, voxel.z); /* If there are more than one images, compare with the proto type */ images_good = TRUE; for (i = 1; i < nimages && images_good; ++i) { AmitkPoint voxel_i = {1,1,1}; AmitkPoint origin_i = {0,0,0}; VistaIOBoolean origin_found_i = FALSE; images_good &= dim.x == VistaIOImageNColumns(images[i]); images_good &= dim.y == VistaIOImageNRows(images[i]); images_good &= dim.z == VistaIOImageNBands(images[i]); images_good &= in_pixel_repn == VistaIOPixelRepn(images[i]); images_good &= is_pixel_unsigned == vistaio_get_pixel_signedness(images[i]); vistaio_get_3dvector(images[i], "voxel", &voxel_i); origin_found_i = vistaio_get_3dvector(images[i], "origin3d", &origin_i); if (!origin_found_i) origin_found_i = vistaio_get_3dvector(images[i], "position", &origin_i); images_good &= voxel.x == voxel_i.x; images_good &= voxel.y == voxel_i.y; images_good &= voxel.z == voxel_i.z; images_good &= origin.x == origin_i.x; images_good &= origin.y == origin_i.y; images_good &= origin.z == origin_i.z; } if (!images_good) { g_warning("File %s containes more than one image of different type, scaling, or dimensions, only reading first", filename); dim.t = 1; } else { dim.t = nimages; } dim.g = 1; /* the origin is read directly from DICOM therefore we emulate what the dcmtk reader is doing */ origin.y *= -1.0; /* DICOM specifies y axis in wrong direction */ origin.z *= -1.0; /* DICOM specifies z axis in wrong direction */ /* Now we can create the images */ /* pick our internal data format */ switch(in_pixel_repn) { case VistaIOSByteRepn: format = AMITK_FORMAT_SBYTE; break; case VistaIOUByteRepn: format = AMITK_FORMAT_UBYTE; break; case VistaIOShortRepn: format = is_pixel_unsigned ? AMITK_FORMAT_USHORT : AMITK_FORMAT_SSHORT; break; case VistaIOLongRepn: /* 7 */ format = is_pixel_unsigned ? AMITK_FORMAT_UINT : AMITK_FORMAT_SINT; break; case VistaIOFloatRepn: format = AMITK_FORMAT_FLOAT; break; /* Double valued images need to be converted to plain float*/ case VistaIODoubleRepn: format = AMITK_FORMAT_FLOAT; convert = TRUE; break; /* Binary images are read as ubyte, since vista also stores them like this in memory */ case VistaIOBitRepn: format = AMITK_FORMAT_UBYTE; break; default: g_warning(_("Importing data type %d file through VistaIO unsupported in AMIDE, discarding"), in_pixel_repn); goto error1; } format_size = amitk_format_sizes[format]; ds = amitk_data_set_new_with_data(preferences, modality, format, dim, AMITK_SCALING_TYPE_2D_WITH_INTERCEPT); if (ds == NULL) { g_warning(_("Couldn't allocate memory space for the data set structure to hold Vista data")); goto error; } bytes_per_image = format_size * dim.x * dim.y * dim.z; /* Just use the file name, we can figure out somethink more sophisticated later*/ amitk_object_set_name(AMITK_OBJECT(ds),filename); if (rotation_found) amitk_space_set_axes(AMITK_SPACE(ds), new_axes, zero_point); /* This is just informal information */ amitk_data_set_set_subject_orientation(ds, AMITK_SUBJECT_ORIENTATION_UNKNOWN); amitk_data_set_set_scan_date(ds, "Unknown"); amitk_space_set_offset(AMITK_SPACE(ds), origin); amitk_data_set_set_voxel_size(ds, voxel); ds->scan_start = 0.0; g_debug("Now copying data: %d bytes per %d image(s)", bytes_per_image, dim.t); /* now load the data */ if (!convert) { ds_pointer = (char*)amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), zero_voxel); for (t = 0; t < dim.t; ++t, ds_pointer += bytes_per_image) { memcpy(ds_pointer, VistaIOPixelPtr(images[t],0,0,0), bytes_per_image); amitk_data_set_set_frame_duration(ds, t, 1.0); g_debug("Copied image %d", t); } } else { // conversion is always from double to float int pixel_per_image = dim.x * dim.y * dim.z; int p; float * ds_float = (float*)amitk_raw_data_get_pointer(AMITK_DATA_SET_RAW_DATA(ds), zero_voxel); for (t = 0; t < dim.t; ++t) { double *in_ptr = (double* )VistaIOPixelPtr(images[t],0,0,0); for (p = 0; p < pixel_per_image; ++p, ++ds_float, ++in_ptr) *ds_float = *in_ptr; amitk_data_set_set_frame_duration(ds, t, 1.0); } } amitk_data_set_set_scale_factor(ds, 1.0); /* set the external scaling factor */ amitk_data_set_calc_far_corner(ds); /* set the far corner of the volume */ amitk_data_set_calc_min_max(ds, update_func, update_data); error1: for (i = 0; i < nimages; ++i) { VistaIODestroyImage(images[i]); } VistaIOFree(images); VistaIODestroyAttrList (attr_list); error: if (f) fclose(f); return ds; } static VistaIOBoolean vistaio_get_pixel_signedness(VistaIOImage image) { VistaIOBoolean result = 0; if (VistaIOAttrFound == VistaIOGetAttr (VistaIOImageAttrList(image), "repn-unsigned", NULL, VistaIOBitRepn, &result)) return result; else return 0; } static VistaIOBoolean vistaio_get_3dvector(VistaIOImage image, const gchar* attribute_name, AmitkPoint *voxel) { VistaIOString voxel_string; float x,y,z; if (VistaIOGetAttr (VistaIOImageAttrList(image), attribute_name, NULL, VistaIOStringRepn, &voxel_string) != VistaIOAttrFound) { g_debug("VistaIO: Attribute '%s' not found in image", attribute_name); return FALSE; } if (sscanf(voxel_string, "%f %f %f", &x, &y, &z) != 3) { g_debug("VistaIO: The string '%s' could not be parsed properly to obtain three float values", voxel_string); return FALSE; }else { voxel->x = x; voxel->y = y; voxel->z = z; } return TRUE; } static VistaIOBoolean vistaio_get_voxelsize_from2d(VistaIOImage image, AmitkPoint *voxel) { VistaIOString pixel_string; float x, y; VistaIOFloat slice_thickness, spacing; VistaIOBoolean thickness_found = FALSE; VistaIOBoolean spacing_found = FALSE; if (VistaIOGetAttr (VistaIOImageAttrList(image), "pixel", NULL, VistaIOStringRepn, &pixel_string) != VistaIOAttrFound) { g_debug("VistaIO: Attribute 'pixel' not found in image"); return FALSE; } if (sscanf(pixel_string, "%f %f", &x, &y) != 2) { g_debug("VistaIO: The string '%s' could not be parsed properly to obtain two float values", pixel_string); return FALSE; }else { voxel->x = x; voxel->y = y; } thickness_found = VistaIOGetAttr (VistaIOImageAttrList(image), "SliceThickness", NULL, VistaIOFloatRepn, &slice_thickness); spacing_found = VistaIOGetAttr (VistaIOImageAttrList(image), "SpacingBetweenSlices", NULL, VistaIOFloatRepn, &spacing); if (spacing_found) { voxel->z = spacing; if (thickness_found) { if (slice_thickness != spacing) g_debug("Slice thickness %f != slice spacing %f, use spacing", slice_thickness, spacing); } } else if (thickness_found) { voxel->z = slice_thickness; } else { return FALSE; } return TRUE; } static VistaIOBoolean vistaio_get_rotation(VistaIOImage image, AmitkAxes matrix) { int name_length = 0; char *splitname = NULL; VistaIOString voxel_string; if (VistaIOGetAttr (VistaIOImageAttrList(image), "rotation3d", NULL, VistaIOStringRepn, &voxel_string) != VistaIOAttrFound) { g_debug("VistaIO: Attribute 'rotation3d' not found in image"); return FALSE; } /* Split the input data */ splitname = strchr(voxel_string, '='); if (!splitname) { if (strcmp(voxel_string, "rot-identity")) { matrix[AMITK_AXIS_X].x = 1; matrix[AMITK_AXIS_X].y = 0; matrix[AMITK_AXIS_X].z = 0; matrix[AMITK_AXIS_Y].x = 0; matrix[AMITK_AXIS_Y].y = 1; matrix[AMITK_AXIS_Y].z = 0; matrix[AMITK_AXIS_Z].x = 0; matrix[AMITK_AXIS_Z].y = 0; matrix[AMITK_AXIS_Z].z = 1; return TRUE; }else{ g_debug("VistaIO: Unexpected 'rotation3d' attribute '%s'", voxel_string); return FALSE; } } name_length = splitname - voxel_string; ++splitname; g_debug("Found 'rotation3d' as '%s' witgh indicator length %d", voxel_string, name_length); if (!strncmp(voxel_string, "rot-matrix", name_length)) { float xx, xy,xz, yx, yy, yz, zx, zy, zz; if (sscanf(splitname,"%f,%f,%f;%f,%f,%f;%f,%f,%f", &xx, &xy, &xz, &yx, &yy, &yz, &zx, &zy, &zz) != 9) { g_debug("VistaIO: The string '%s' could not be parsed properly " "to obtain nine float values for the 'rotation3d' matrix", splitname); return FALSE; } matrix[AMITK_AXIS_X].x = xx; matrix[AMITK_AXIS_X].y = xy; matrix[AMITK_AXIS_X].z = -xz; matrix[AMITK_AXIS_Y].x = -yx; matrix[AMITK_AXIS_Y].y = -yy; matrix[AMITK_AXIS_Y].z = -yz; matrix[AMITK_AXIS_Z].x = -zx; matrix[AMITK_AXIS_Z].y = -zy; matrix[AMITK_AXIS_Z].z = -zz; return TRUE; } else if (!strncmp(voxel_string, "rot-quaternion", name_length)) { float x, y, z, w; double a2, b2, c2, d2, bc, ad, bd, ac, cd, ab; if (sscanf(splitname,"%f,%f,%f,%f", &w, &x, &y, &z) != 4) { g_debug("VistaIO: The string '%s' could not be parsed properly " "to obtain four float values for the 'rotation3d' quaternion", splitname); return FALSE; } /* Evaluate the matrix from the quaternion */ a2 = w * w; b2 = x * x; c2 = y * y; d2 = z * z; bc = 2.0 * x * y; ad = 2.0 * w * z; bd = 2.0 * x * z; ac = 2.0 * w * y; cd = 2.0 * y * z; ab = 2.0 * w * x; matrix[AMITK_AXIS_X].x = a2 + b2 - c2 - d2; matrix[AMITK_AXIS_X].y = -(bc - ad); matrix[AMITK_AXIS_X].z = -(bd + ac); matrix[AMITK_AXIS_Y].x = bc + ad; matrix[AMITK_AXIS_Y].y = -(a2 - b2 + c2 - d2); matrix[AMITK_AXIS_Y].z = -(cd - ab); matrix[AMITK_AXIS_Z].x = bd - ac; matrix[AMITK_AXIS_Z].y = -(cd + ab); matrix[AMITK_AXIS_Z].z = -(a2 - b2 - c2 + d2); return TRUE; } else { g_debug("VistaIO: Unexpected 'rotation3d' attribute '%s'", voxel_string); return FALSE; } } #endif /* AMIDE_VISTAIO_SUPPORT */ amide-1.0.6/amide-current/src/vistaio_interface.h000066400000000000000000000032151423227705100217760ustar00rootroot00000000000000/* vistaio_interface.h * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2016-2017 Gert Wollny * * Author: Gert Wollny */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef AMIDE_VISTAIO_SUPPORT #ifndef __VISTAIO_INTERFACE_H__ #define __VISTAIO_INTERFACE_H__ /* includes always needed with this file */ #include "amitk_data_set.h" gboolean vistaio_test_vista(gchar *filename); /* external functions */ AmitkDataSet * vistaio_import(const gchar * filename, AmitkPreferences * preferences, AmitkUpdateFunc update_func, gpointer update_data); /* voxel_size only used if resliced=TRUE */ /* if bounding_box == NULL, will create its own using the minimal necessary */ gboolean vistaio_export(AmitkDataSet * ds, const gchar * filename, const gboolean resliced, const AmitkPoint voxel_size, const AmitkVolume * bounding_box, AmitkUpdateFunc update_func, gpointer update_data); #endif #endif /*AMIDE_VISTAIO_SUPPORT*/ amide-1.0.6/amide-current/src/xml.c000066400000000000000000000442261423227705100171020ustar00rootroot00000000000000/* xml.c - convience functions for working with xml files * * Part of amide - Amide's a Medical Image Dataset Examiner * Copyright (C) 2001-2017 Andy Loening * * Author: Andy Loening */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "amide_config.h" #include "xml.h" #include #include #include #include "amitk_common.h" #define BOOLEAN_STRING_MAX_LENGTH 10 /* when we stop checking */ static char * true_string = "true"; static char * false_string = "false"; /* automagically converts the string to having the right radix for the current locale */ /* this crap needs to be used because on windows, setlocale isn't implemented on mingw */ void xml_convert_radix_to_local(gchar * conv_str) { gboolean period=TRUE; gdouble temp_float; gchar * radix_ptr; /* mingw doesn't really support setlocale, so use the following to figure out if we're using a period or comma for the radix */ sscanf("1,9", "%lf", &temp_float); if (temp_float > 1.1) period=FALSE; if (period == FALSE) { /* using comma's */ while ((radix_ptr = strchr(conv_str, '.')) != NULL) *radix_ptr = ','; } else { /* using period */ while ((radix_ptr = strchr(conv_str, ',')) != NULL) *radix_ptr = '.'; } return; } /* returns FALSE if we'll have problems reading this file on a 32bit system */ gboolean xml_check_file_32bit_okay(guint64 value) { #if !defined (G_PLATFORM_WIN32) /* for some reason, 64bit calculations on windows returns garbage */ if (sizeof(long) < sizeof(guint64)) { guint64 check = ((guint64) value) >> ((guint64) 31); /* long is signed, so 31 bits */ if (check > 0) return FALSE; } #endif // the following doesn't work on win32 either // if (sizeof(long) < sizeof(guint64)) { // guint32 * value32; // value32 = (guint32 *) &value; // //#if (G_BYTE_ORDER == G_BIG_ENDIAN) // if (value32[0] > 0) // return FALSE; //#else /* little endian */ // if (value32[1] > 0) // return FALSE; //#endif // } return TRUE; } /* utility functions */ gboolean xml_node_exists(xmlNodePtr nodes, const gchar * descriptor) { if (xml_get_node(nodes, descriptor) != NULL) return TRUE; else return FALSE; } /* ----------------- the load functions ------------------ */ /* go through a list of nodes, and return a pointer to the node matching the descriptor */ xmlNodePtr xml_get_node(xmlNodePtr nodes, const gchar * descriptor) { if (nodes == NULL) return NULL; else { if (xmlStrcmp(nodes->name, (const xmlChar *) descriptor) == 0) return nodes; else return xml_get_node(nodes->next, descriptor); } } /* go through a list of nodes, and return the text which matches the descriptor */ gchar * xml_get_string(xmlNodePtr nodes, const gchar * descriptor) { gchar * xml_str; gchar * return_str; xml_str = (gchar *) xmlNodeGetContent(xml_get_node(nodes, descriptor)); if (xml_str != NULL) return_str = g_strdup_printf("%s", xml_str); else return_str = NULL; free(xml_str); return return_str; } amide_time_t xml_get_time(xmlNodePtr nodes, const gchar * descriptor, gchar ** perror_buf) { gchar * temp_str; amide_time_t return_time; gint error=0; gchar * saved_locale; saved_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_NUMERIC,"POSIX"); temp_str = xml_get_string(nodes, descriptor); if (temp_str != NULL) { xml_convert_radix_to_local(temp_str); #if (SIZE_OF_AMIDE_TIME_T == 8) /* convert to double */ error = sscanf(temp_str, "%lf", &return_time); #elif (SIZE_OF_AMIDE_TIME_T == 4) /* convert to float */ error = sscanf(temp_str, "%f", &return_time); #else #error "Unknown size for SIZE_OF_AMIDE_TIME_T" #endif g_free(temp_str); } if ((temp_str == NULL) || (error == EOF)) { return_time = 0.0; amitk_append_str_with_newline(perror_buf,_("Couldn't read time value for %s, substituting %5.3f"), descriptor, return_time); } setlocale(LC_NUMERIC, saved_locale); g_free(saved_locale); return return_time; } amide_time_t * xml_get_times(xmlNodePtr nodes, const gchar * descriptor, guint num_times, gchar ** perror_buf) { gchar * temp_str; gchar ** string_chunks; amide_time_t * return_times=NULL; gint error; guint i; gchar * saved_locale; gboolean corrupted=FALSE; saved_locale = g_strdup(setlocale(LC_NUMERIC,NULL)); setlocale(LC_NUMERIC,"POSIX"); temp_str = xml_get_string(nodes, descriptor); if ((return_times = g_try_new(amide_time_t,num_times)) == NULL) { amitk_append_str_with_newline(perror_buf, _("Couldn't allocate memory space for time data")); return return_times; } if (temp_str != NULL) { /* split-up the string so we can process it */ string_chunks = g_strsplit(temp_str, "\t", num_times); g_free(temp_str); for (i=0; (i */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __XML_H__ #define __XML_H__ /* header files that are always associated with this header file */ #include "amitk_type.h" #include #include G_BEGIN_DECLS /* functions */ void xml_convert_radix_to_local(gchar * string); gboolean xml_check_file_32bit_okay(guint64 value); gboolean xml_node_exists(xmlNodePtr nodes, const gchar * descriptor); xmlNodePtr xml_get_node(xmlNodePtr nodes, const gchar * descriptor); gchar * xml_get_string(xmlNodePtr nodes, const gchar * descriptor); amide_time_t xml_get_time(xmlNodePtr nodes, const gchar * descriptor, gchar **perror_buf); amide_time_t * xml_get_times(xmlNodePtr nodes, const gchar * descriptor, guint num_times, gchar **perror_buf); amide_data_t xml_get_data(xmlNodePtr nodes, const gchar * descriptor, gchar **perror_buf); amide_data_t xml_get_data_with_default(xmlNodePtr nodes, const gchar * descriptor, amide_data_t default_data); amide_real_t xml_get_real(xmlNodePtr node, const gchar * descriptor, gchar **perror_buf); amide_real_t xml_get_real_with_default(xmlNodePtr node, const gchar * descriptor, amide_real_t default_real); gboolean xml_get_boolean(xmlNodePtr nodes, const gchar * descriptor, gchar **perror_buf); gboolean xml_get_boolean_with_default(xmlNodePtr nodes, const gchar * descriptor, gboolean default_boolean); gint xml_get_int(xmlNodePtr nodes, const gchar * descriptor, gchar **perror_buf); gint xml_get_int_with_default(xmlNodePtr nodes, const gchar * descriptor, gint default_int); guint xml_get_uint(xmlNodePtr nodes, const gchar * descriptor, gchar **perror_buf); guint xml_get_uint_with_default(xmlNodePtr nodes, const gchar * descriptor, guint default_uint); void xml_get_location_and_size(xmlNodePtr nodes, const gchar * descriptor, guint64 * location, guint64 * size, gchar **perror_buf); void xml_save_string(xmlNodePtr node, const gchar * descriptor, const gchar * string); void xml_save_time(xmlNodePtr node, const gchar * descriptor, const amide_time_t num); void xml_save_times(xmlNodePtr node, const gchar * descriptor, const amide_time_t * numbers, const int num); void xml_save_data(xmlNodePtr node, const gchar * descriptor, const amide_data_t num); void xml_save_real(xmlNodePtr node, const gchar * descriptor, const amide_real_t num); void xml_save_boolean(xmlNodePtr node, const gchar * descriptor, const gboolean value); void xml_save_int(xmlNodePtr node, const gchar * descriptor, const gint num); void xml_save_uint(xmlNodePtr node, const gchar * descriptor, const guint num); void xml_save_location_and_size(xmlNodePtr node, const gchar * descriptor, const guint64 location, const guint64 size); xmlDocPtr xml_open_doc(gchar * filename, FILE * study_file, guint64 location, guint64 size, gchar ** perror_buf); G_END_DECLS #endif /* __XML_H__ */ amide-1.0.6/amide-current/stamp-h.in000066400000000000000000000000121423227705100172310ustar00rootroot00000000000000timestamp amide-1.0.6/amide-current/todo000066400000000000000000000313411423227705100162310ustar00rootroot00000000000000misc list of things todo: for next release? ----------------- * gnome_canvas font looks bad on windows, switched to Tahoma looks a little better but not true type'd. Figure out what font gtk's using. * calling help on win32 creates coredump * exporting gated studies via DICOM and reloading doesn't work. May be an error in exporting, or an error in importing gated DICOM * change wait cursor to be whole dialog, not just canvas * revert on dialogs doesn't work correctly... children get readded * freehand/isocontour roi's - draw them at high mag - will see they're shifted just slightly off voxel lines [2] [x] noticed by Mark Huisman * Gate picker -> multiple selection still screwed up Mac OS X -------- * clicking on a .xif study loads up AMIDE, but without the file. [x] noticed by Eric Wolsztynski Win32 ---------------- * XIF files appar to be limited to 2 GB even on 64bit windows 7 [noticed by Michael Braden] * g_win32_get_package_installation_subdirectoy in amide_gnome is deprecated, currently commented out. Need to fix starting up help * help works in cygwin setup, but not in installed package. Seems to know the right place to look, just isn't doing something correctly.... * Copy to clipboard function in roi analysis widget doesn't work on Windows 7, although it does work on Windows XP, likely a win32 bug in gtk_clipboard on win32... (noticed by Arutselvan Natarajan) * export pixel size text boxes get ignored - likely using wrong "update" event (noticed by Priti Madhav and Ian Miller) * zdial on rendering doesn't work big things: ----------- * figuring out orientation from files loaded from xmedcon isn't strictly correct, and screws up with NIFTI format look at notes in libmdc_interface.c. Also would likely need fixes in libmdc itself (see 0.10.3_nifti_unsubmitted changes) * polygonal ROI's (requested by A.Mehranian) * add drag-n-drop capabilities between study windows don't use treeview reorderable stuff, too limited, * toolbox dialog for generating polar maps (requested by Jeff Arkles and others) * should be able to specify units the image/display info is in, and request different output units. -allow changing of displayed units (mm, cm, m, s, min, uCi, Beq, etc.) -study would have an output units variable -each data set, can specify it's original units, and (if needed), a scaling factor to output unit -ui_preferences would change default units -need gobject based approach, so widgets can listen for change -> start with mm/cm/m * add a data sets list item, -would allow reading in multi-bed data sets -raw_data type could have amitk_space made its parent, so it has its own space... * calculating PV correction. Correction factors could be calculated for each volume's resolution and then cached. * multi-step undo/redo, look into how other GTK apps do it -once this is done, drop the enact/cancel bit of shifting data sets and study's as we can now just undo such a change * create an AmitkAnalysis type, holding voxel statistics -when created, passed a study -use callbacks, so that stats are marked as current or obsolete, stats also marked as obsolete if a AmitkAnalysis calculation type changed from "fast" to "accurate" or back -stats are only (re)calculated as needed (i.e. when stat values/raw values are requested) -has a callback "amitk_analysis_changed", so that the roi_analysis_widget knows to update it's table. -function to request stats as an array of structs -function to request raw values as array of structs * ability to import and export AIR .air files -probably from rotate axis page -need object list widget: should update automatically when something is removed somewhere else small things: ------------- * XIF directory format doesn't handle characters in study/data set names that are inconsistent with the file system [noticed by Michael Braden] * boolean operators between ROI's, would allow subtracting one from another (requested by A. Mehranian) * be able to export the color scale (with appropriate numerical values) to an image file (requested by Frezghi Habte) * pop-up widget allowing value underneath cursor to be shown for all data sets (not just active). (requested by Axel Moeller) * hot key to cycle through time frames (requested by Michael Braden) * allow direct entry of transformation matrix in amitk_space_edit * data set icons in amitk_tree could be generated from the actual respective data sets * .xif files should try to compress data. * amitk_preferences.c : default color table, panel layout, layout should be saved in gsettings as they associated strings for these values, not as the enumerated numbers * change tb_filter, tb_crop, tb_fads, so that an amitk_tree is used for the initial popup letting you change which data set will be used * export ROI's to external file? and allow import? * continue implementing progress bars for various functions: -roi analysis -loading in data sets * could probably subclass isocontour's from AmitkRoi -> AimtkIsocontourRoi would allow simplification of amitk_canvas event cruft also probably get rid of amitk_roi_variable_types.c... not worth the performance improvement * add sqrt and log abilities into color table lookup? * should have option to use rigid body registration with scaling * try to work in the max/min/distribution calculations into the loading loop * fix zooming of off angle roi's on the canvas * roi analysis dialog should probably be updated for any change of the roi's * add key combination that sets current pixel value to max/min threshold * rendered movies aren't smooth when looping in an external player, this happened when switching to ffmpeg small short range things -------------- * try to change all dialog box buttons to verbs * add tooltips to everything.... * add more help buttons to the dialogs longer range things ---------------- * add report generation. This would add colormaps, location, thickness study name, volume name, scan date, etc. to the export function. Would handle multiple images. * rendering alterations -> 3D red/green imaging allow rotation of light source and view in addition to object allow changing of material properties transformation to rendering structure is inefficient when doing multiple volumes, each volume should be transfered using it's minimal voxel size, not the group's maximum minimal voxel size. the rendered images should then be scaled and overlapped. MIP rendering would be nice.... More likely, will switch to using VTK at some point * aligning of data using automated registration? libgnomecanvas/pixbuf issues --------------------- These problems will probably never be rectified, as libgnomecanvas is now deprecated. More likely course of action will be likely to rewrite the parts that use libgnomecanvas to use a new canvas system. A new canvas system has not yet been agreed on for gtk (as of 3.0 at least). Goocanvas would have seemed to be the obvious choice, as it's similar to libgnomecanvas but with cairo as the backend rather than libart, but development of this seems to have stalled. May need to go directly to cairo as the canvas. * antialiased canvases have been unstable in the past, due to instabilities with ROI resizing starts spewing "*** attempt to put segment in horiz list twice" errors and eventually core dumps. Either a libart or libgnomecanvas bug. At the current time (amide 1.0.3) things seem to be working, so the appropriate lines in configure.in have been reenabled to allow building in support for antialiased canvases. To disable antialiasing, disable these lines again. last tested versions: libart_lgpl-2.3.21 libgnomecanvas-2.30.3 -make sure to check that lines in tb_crop are placed correctly -need to check that the export jpeg functions work, they have not been tested * anti-aliased canvases doesn't support GDK line styles (as of libgnomecanvas 2.2.0) -ui_preferences_dialog, and amitk_object_dialog define out the appropriate code when antialiasing support is compiled in. Add back in once (if ever) anti-aliased canvases support line styles. * currently, alpha blending is done inside of image.c, a single pixbuf is generated, and this is handed to gnome_canvas. It'd be nice to use separate pixbuf's but each data set, and throwing them on the canvas. The single biggest problem with this is that the background buffer in gnome_canvas is RGB, not RGBA, so the buffer has an effective alpha of 0xFF, and you're just blending the image with whatever that background is, screwing up the color levels. may have to rewrite libgnomecanvas to use a 32bit buffer -would allow the use of cursor keys for moving data sets around each other * using the gdk_pixbuf_scale functions Slicing from all data sets at zoom=1.0, and then scaling using the gdk_pixbuf_scale type functions doesn't work well, as the scale functions don't do a great job of interpolation (circa gdk-pixbuf-0.18.0). things dependent on other things: -------------- * dependent on gtk fixing the GTK_FILE_CHOOSER_CREATE_FOLDER properties of gtkfilechooser. Currently, the gtkfilechooser widget puts out an error if you try to select a folder that's currently a filename (rather than allowing overwriting). This comes up really only when trying to overwrite a .xif file as a .xif directory using the same name. * dependent on gtk > 2.14: -gtk (as of 2.14) doesn't have any version of gnome_help_display. As such, the relevant code from libgnome has been copied into amide_gnome.c. When gtk has this capability, the code in amide_gnome.c can be deleted. * not currently implemented in gtk (at least as of 2.12): handle_box's don't get minimized with the main window... but no way to minimize them independently... * amide_gconf.c is used to encapsulate configuration support (gconf for unix, registry entries based on code stolen from gnumeric for win32, and g_key_file (flat file) for mac os x). GConf is likely to be deprecated at some point in the future. GSettings doesn't seem appropriate, as it absolutely requires a schema to be in place (as of glib 2.30) or the program aborts... If GSettings ever becomes more user friendly will switch the GConf support to GSettings, otherwise will go with the g_key_file in place of gconf. * setlocale is disabled on win32, this is because further setlocale commands seem to be ignored, and so reading in text hdr files (e.g. Concorde format ) gets screwed up for locales that use the comma for the radix. This is as of mingw 3.13 at least. * in xml.c and amitk_point.c, have a bunch of G_PLATFORM_WIN32 ifdef's, because g_strdup_printf wasn't obeying the setlocale command on windows as of glib 2.2 This was causing errors in locales that use a comma as the radix sign. Need to test if g_strdup_printf will work with later versions of glib. * ui_time_dialog specifies AmitkDataSet as G_TYPE_POINTER instead of AMITK_TYPE_OBJECT when setting up gtk_list_store - this is due to a gtk bug, adds a reference with G_TYPE_OBJECT but doesn't remove it - also in amitk_tree.c, ui_alignment_dialog.c * at some point, GtkGammaCurve will probably be deprecated from Gtk, can either copy the code into amide, or come up with something more fitting * when bug-buddy supports sourceforge bug reporting, delete the following line from amide.c so we can have bug reporting "signal(SIGSEGV, SIG_DFL);" * remove no-ops in raw_data.c I've needed this (at least) for gcc <= 3.0.3. Left in for the moment as I haven't tested gcc 3.1 for this bug, and other people may be using old versions of gcc. * Current implementation is cooperative multitasking, if that. Should turn program into a true, multi-threaded design. Note that gtk for windows (as of 2003.04.30) does not handle multi-threaded program.... so will have to wait for that. * amitk_data_sets_export_to_file is very wasteful of memory. It reslices the requisite data sets into a new data set, and then an additional copy data set is made inside of libmdc. If medcon/libmdc ever supports slice-by-slice saving of data sets (instead of as an entire volume at once), we would only need to allocate one slice in amide, and one slice in libmdc, rather than one volume in amide, and one volume in libmdc. factor analysis things: ----------------------- * factor analysis -> should be able to do from ROI's too. should be simple. 1 iteration to find the # of voxels, second iteration to fill in probable use weight >=0.5 as cutoff * need to add orthogonality component back into PLS * principle component analysis should probably be demeaned * need to extend 2 comp to 3 comp (or n-comp) * should be able to combine main function for fads and comp models amide-1.0.6/amide-current/win32/000077500000000000000000000000001423227705100163015ustar00rootroot00000000000000amide-1.0.6/amide-current/win32/Makefile.am000066400000000000000000000013071423227705100203360ustar00rootroot00000000000000if AMIDE_OS_WIN32 BUILT_SOURCES = \ amide.ico \ amide_file.ico \ amiderc.o amide.ico: amide_logo16x16.png amide_logo32x32.png amide_logo64x64.png amide_logo128x128.png png2ico.exe amide.ico amide_logo16x16.png amide_logo32x32.png amide_logo64x64.png amide_logo128x128.png amide_file.ico: amide_file_logo16x16.png amide_file_logo32x32.png amide_file_logo64x64.png amide_file_logo128x128.png png2ico.exe amide_file.ico amide_file_logo16x16.png amide_file_logo32x32.png amide_file_logo64x64.png amide_file_logo128x128.png amiderc.o: amiderc.rc amide.ico amide_file.ico windres -i amiderc.rc -o amiderc.o endif CLEANFILES = amiderc.o amide.ico amide_file.ico DISTCLEANFILES = *~ amide-1.0.6/amide-current/win32/README000066400000000000000000000004671423227705100171700ustar00rootroot00000000000000 The .iss file is for the Inno Setup Compiler (version 3.0.7) 1. to generate amide.ico, download png2ico.exe, and run png2ico.exe amide.ico amide_logo* png2ico.exe amide_file.ico amide_file* 2. make amiderc.o windres amiderc.rc amiderc.o cp amiderc.o ../src and then include amiderc.o in src/Makefile amide-1.0.6/amide-current/win32/amide_file_logo128x128.png000066400000000000000000000276271423227705100230010ustar00rootroot00000000000000PNG  IHDR>abKGD pHYs  ~tIME5z-^ IDATxyy?=!BX ccVLB1EQNU.z.[>EJlN5&6q %$EVZjc_OwOLJ@^}Uy~[ 5#esZZ.)^Yh2|+wY]Z􍀻9 i#ƀRjW}Σd25k&G\p7~<ΏJe*-e@} :P U*ēwZ“4pvd˾\.IH3Y$i_^Q<): q7秞ްkW˥Lfq #VW, &xAtt]U#x~ +'̀AL0!J /e1Zۿ*@j%go`s Hʥ'd`AN\+$BrTkͲN@,^X~/=^S3 0c<"GJm;+_[u|Ta=WxlDL&#?`%p@J_:42 G.U~b_aY`9Fx"kO3::}R`hV/Oȱr8 8#@ʳ;:: Xr NzaXfj. 8Ve:Q/KC:t uttl0$,Rsݔ-ONO|,!Iӆ1>Ѵh04$bd 1/Ptne 1H濂TUfg0S,##hC $q AB }k*|0k0>Y0 taH`mPAl.R]Ճdnnv/pxv% j' ZSUmNӴ ]׆5M;RT3S;:"wwAJ+VSQN?L6px2$K@BSlT- (gRUU=i꼦UUgTUWUulpb_Γ eN(ƨ/>`  d1ˊdrSG*Jl8FXFrPS?F멏!H((Gu]˾ 1[i) t @-dP#~Űfg54w/pZ\Hb]B2dTU9q䰢deJ5,D7>5H@H0 v`h+0?T1ܲrg{.\H|j󷊡UAFSGjz\Ӵ9MW`&~1Ӈ1DPRGxŪX,֏arlX;Aé ɳ%j+/33w$iIjQ;Rjl/F!L .fN]$ŀN I$8mbdd8\F%etdTd4dЪ2TfndRROJM&kl%Xq ລ3 &VRo%:fO,k6i0ry.W(+15b7DXca$DF"843 җR53[YFt:诐MWa1 L.PԜ\/p wGVu/Yy$I _{z#3~?}4Rݳ骪8ikNTUT*,׬>_wCG8Q^udiu](J3Nv+(_Jt5qx-*Lٙϡ$jFA&L:$+0ˁb8Mx]h`U5(J,ٱx` }jE!Nbc؎}z ">9ɲiرul"nsYQLKU/. sTE4M吟"®\2 &(HIN*J#V=X &T#ff7M n:2###[W#G׳|6nj^'!كi|h4Gb;BJ]MƌyJbD7}u]Ν8Vc %[a˖-xꩧ|xffuֱsN.R=;O[@r{ݵkW1۫+srXw7CHQ HzBxIi]  x(˞;OS*(˄B]/Єqn@@X(V$|DxlǞ=tȚ&$IjO]Q !K`YS3L88k6I|7$,fZ;D{ I}]xb5S 騷s=>JWW]D"a!P,br9Jja-JF|_fv拓CA,H(D"dY榛n"q06 (Ӏp&Q bѕ=Vt 4p׍;p%o7ʕlvIeQX٣~u8!jY?Vxi&'߫[o$%$"E<ػ" 1tJ{W*Fd3m^@?8@(= 1,(Qa?Fd2ȲL<'N7Bdcu_g's {=+fggh0 'ڽ6{U> __>IGG+Wd߾}!P&H$BR1ÉpsrMV;C.ٹIdn0jL!6i%*(JMPwag( iհkѳN;NX}g_h|Ic@]0vӳ'w]wb:UXnV/_~tbP(cqoS!S j P*/҆u7of׮]Ю)ڕ@Ҹ=n_cZdazhܗ8;;{ç싶K [ mT*Mcꉷ+Vg g<<,F]wFɡ6]ҊuP @լ Q"J`{D*g6Qeua7nRdX~=6x=4;66\s5m݈j1~B(}eH1"e}C0&1,ͫR-pqxN .;+F$>DnA6NGhY犞sssCr9[ps`ttW^y0l6kzOʷ->Ϛ9}"455eoL˔rM+{y3fppN.G}r,˔kz] U StHE# Fl1ćFoOSsJ|[裏xiON?"um_8g4L3[c~ʆ`5l!Wa=RNE>aXIz;Wҝ]fFt]Nぅ2V/"Hc%|3XuB vNRAuCKU15 K%JQ3l޼d26xdYFQE3yDZc8YfU(5߿SøzBоRԃ: `[o%417mt5#=BuN9[EvUu3׊ 6pg7 <;Xf zUbђSoAzF8;x.sq=wpОiN2(; Cݱ$@7KrH2+'׵L >Kk299:*dIXF5πPU&_PV(J *Җ1CѓmzHv4*eL10:#ips ~mEd1Ќؖ BV(1èJ<7}$j`0hS8x9֦|nPcO躖'V7i@|]n˿uH$mo߾7LSP)g(MvEBqF CL&Q N&nJ3E`]tpj;e9\}/ڏJ[ }f`/|5;;;5t׮]l޼GUn1H^x!gַ-Y<1P"8ܱ7(S 3> yFh$I .:!#$cˉ'H&ځV_<$'94yJDZ`; b;ӓ ٬ݞv"o޽ i/B?'ME FXG[MeNΜd2C&c{b&wyFFF`kEEu^9IK,DlyfTebϷ%* ;wz7[nn[RA&&&Xl~ۘy~g0 ꉵnIt3f T_tE Z}~{6Q7nȊ+6@(Zq F_fdY3C1`CuQ-[f Vh+/_ݻYv-7YYj[pS="U[T*6m"N mٞ|IZ0x׻k1 B8Gcjj M8q`p1&~zY,صk, Yj[q6m⥗^Z2>>N>7} 34|]f;&ӟ#8N\.ַuAӾoU{088h^TU%JQ(f 2hzׯoXo>a3>n Ie uYٳ`0lzgy'>@Db):zYa}P{~aOK.T*>ɘLivvD"a ] [Q*ü- afm:<.Z:.R*|[wÉHN$M3EYf,WH Stuu p 745q҆M%8 }}{:::dZPBS|hb þ 8cDw2v5IDAT>ѲT*M `*q|O~:1'IBKhU 4v De0tu|xMNŲbU(^fݟ韺7t fhXae`q~UUe9>td|)|_m:hdť^ʖ-[\ l=v;e`˖-3m`0E$1tT4r6d2*ι>HR{ndYnSn駟6]|ž%jSp/ j@׍B II7zp&,OMMٜU 4sd57L"h&''mfu+8'Eq;Fx3xPT"L$iĉI.PebHQ +VX0~&&&̶~m%]zmp月b7}ek;B B.4*wdzzu]333.[o0|3)pkn27Wsk\J!Ŭ#wÆ K/y#V^\f\.MOv,dpKO~`6|Z,:#)ax*J/6nȏ~-K/y{mضx{?|>V= ~ F_O+}ӝ ,[8yYOuvvLP(Y bͭfFȯVUK޿{'ЪOduy'+3ܔ-7[E(MG 9|rqmPU| J?<Cl6K$TNnƆ> 7tSkh$5y9mS 4R!!˲7Jrgr (fUlL 6pViZ[hjVֵHd9~gOvnq;n? 8[<@'gq=Q,䡇j2F+$I4sVunk Z6_Q{\FsrÇ1>nS!ٹs+K B(4BaZaڴ_&h8npuwwWF+/N47ǓiB!v<^XUr_rH[uS86 BOy{[Z@aer3!#HFez^-L@,i`[=h/B!I.rSaz-V8R)/ /drrI[R0Œ tjVX fW\o~sdͱ|rt]oj։e +FH1_yh|h}k(2תJߝp6]2Zr>P(9v~>X,Jd2i uE^.JL1?뜧J/b{~+F򑏘B wpPB\~L7q^k *̭[^V guq,?9BL`5 f!"IӓiH6o EQ|VW\E%!aVW04N&Nb*4?`H^s`Quh^;7 СCLOO-~k;ԕ1ӢtȡἈm{ 5 j}99e[}ժMG>bzD"?m9/N"ĶFO@%>66Fww7H$~Xd֭dYpr9OQl!M\|Bٳ> (7tb:/ӷ$^ ` u]|5iAB9x<CD/>3,Nw~΋ z9 inR+37+sfuxFRد`r]TǴ+ hU*ݺvwo~3>V&8x rJӑZSy¶Si6ڽ +Y"v@@X-=?' ܹb𪪺&R,5]1e]kB|8o<k0߆ᅥ(~-z$d'7 }{֌7z`ַ-^ćV4eo$4!:N/z)Z8xC[E-Rtb_NkO^Ն7ʅ ]Fb7/<? ^ w.ѸIENDB`amide-1.0.6/amide-current/win32/amide_file_logo16x16.png000066400000000000000000000047011423227705100226150ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  ~tIME NIDATx]T9gΜeuY`w%ÊdMV[ 4ֽ)~WXjՋ^5چ4&&JLDX5`, Z@RdQ؏) Ų+P5Iޜ7<[`[FS!'?x=*@rwe T"`^+ Qup@28|+䋧޽xou˺dG»z\yM]"!*r\==U?0PUf+|ۇS*(Ph~6^Ib[uJ+|m,mwc LNNR.i4D"\%a`aɲnG w.A*}(`-j ixxvD"(B>q|>PEQB#N\g }MK//4OY(REK&1 |!z@ @$A$4MCulFB(ԨZG y;^ǡu%w}Zyr!Iw9Ű,zN0$X|9`0H&9OEBB* &}D3~Vrnz3^غuP8& # "Iiix1~ HHWF.$jBAB#)x%p83dؼy3333+>}MӰ, !Z{uW/4![RHے6 UZ*{Iu85_dY`;ci,Y{Y݋$IȲiDQ2t_@cp .U>'qGȚIlA$!:MWS8[8ɩg0 cr6lSO,j:_麎eYdYLDeN81W惪d&JaY楗^X,fhfhD"cСCaضr'efIGGWfff\.,ضeYݻ8@I>P* .]wappY,Bep]I|4M!pF\|IJ^GQ֭[Eut]uvVj2<<0Ǐ#˲D"-4rLX?\..l6R).^H6t ʅ:s .嘛Zb&ea.Ng}$Ii\QD΢:grrO?֭[Y|9Xv|>( ===]-[Pב$ u˲̺uصkD0 `/nUU7ʲx? 222!PU^^7ȲL(bnnt:u]^/>_~QDQΜ9iO/bqp]!NaժULNNR,q]we*i"Ik֬X,R*pRʕ+#Q,T*S Ly>eY;wT*Źs&J-m.fgg1 0 IFZFZlb6FO>B@(bӦM(#LFpb׊IENDB`amide-1.0.6/amide-current/win32/amide_file_logo32x32.png000066400000000000000000000047011423227705100226110ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  ~tIMEjn- NIDATx]T9gΜeuY`w%ÊdMV[ 4ֽ)~WXjՋ^5چ4&&JLDX5`, Z@RdQ؏) Ų+P5Iޜ7<[`[FS!'?x=*@rwe T"`^+ Qup@28|+䋧޽xou˺dG»z\yM]"!*r\==U?0PUf+|ۇS*(Ph~6^Ib[uJ+|m,mwc LNNR.i4D"\%a`aɲnG w.A*}(`-j ixxvD"(B>q|>PEQB#N\g }MK//4OY(REK&1 |!z@ @$A$4MCulFB(ԨZG y;^ǡu%w}Zyr!Iw9Ű,zN0$X|9`0H&9OEBB* &}D3~Vrnz3^غuP8& # "Iiix1~ HHWF.$jBAB#)x%p83dؼy3333+>}MӰ, !Z{uW/4![RHے6 UZ*{Iu85_dY`;ci,Y{Y݋$IȲiDQ2t_@cp .U>'qGȚIlA$!:MWS8[8ɩg0 cr6lSO,j:_麎eYdYLDeN81W惪d&JaY楗^X,fhfhD"cСCaضr'efIGGWfff\.,ضeYݻ8@I>P* .]wappY,Bep]I|4M!pF\|IJ^GQ֭[Eut]uvVj2<<0Ǐ#˲D"-4rLX?\..l6R).^H6t ʅ:s .嘛Zb&ea.Ng}$Ii\QD΢:grrO?֭[Y|9Xv|>( ===]-[Pב$ u˲̺uصkD0 `/nUU7ʲx? 222!PU^^7ȲL(bnnt:u]^/>_~QDQΜ9iO/bqp]!NaժULNNR,q]we*i"Ik֬X,R*pRʕ+#Q,T*S Ly>eY;wT*Źs&J-m.fgg1 0 IFZFZlb6FO>B@(bӦM(#LFpb׊IENDB`amide-1.0.6/amide-current/win32/amide_file_logo64x64.png000066400000000000000000000140471423227705100226270ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs  ~tIME hAIDATx͛yl\ǝ?^_l6&٤(xEіqͥ,$pAbf0@ c׀$Op"z'%)D:x5f7|uIʖNO#˩ 粷nFV8/ě_|~}?沩;P4@/pt |.?sǮGGXӯv87eoˀ0)5եAwn8GҧW>K.럍eͿ13uZlg>AB~N\0 c ~?5Xy޲eeLӼߚt-~dyL7#hAEFB>J~qi2pKyU؀2ܼ{,.@!HL͞DvI'FOt4ji۶3l6\KgF\_2nFO-4,k\)f2gN L4h# ;^Z:4+)K8cca\~hHOGGbCCnϥ|(}R.9vZLfEH.7oYVpɳׯ {DQMCͶ]`p3z##qH^hoo!333/f a4,EP4D"yeStf|W +s(EZ*+khijfBK7Ô1 `qq|>O&b^0 "bӴ!%SWWϧd2Nžp`#!blj~ ^TIp۶I&LNN299k˲8w74`dzX&YLMu!F{U$-h okDvf2N7OhOLL`6:CӴ t&L;F pv5TWWΝ;b6M7'hcOh#[n塇12 BA=@" LRUUEP@ \4bٹ3{+e{`:a),..sN¡/̀ Ao:m,+,#۶m'$ϓL&d2Nuu5UUUDA]KR:ϟB lAKw4:"u՛m]ӈD"D"4Mu5(,bI.R_5w#]]]8p|>y0u]"La4e۶mvm躎w{Kq_+$tCYpEp]p,ئƌb;>Iou'xj`|\(g?YP:4b۶ٳgV4MP(`B刺Z"&r@NQ4q("(lV @OOڶ݂WmXַE,cjje [nE5t]/nPGMM ;vPϽsdlyHˌw̒]ͭxŚngOU\*k00pHLNN <=ݻwW4.7zuuuR[[[q}tY4L5^l'YtJ1MY,4Xo<>*5uuu~\ell M[^4LӤ @?I dY6ntNLTƤA8Jƙq &# зxSRpdG.ƮX\\$L穪"G4e߾}q|>i@8ƶmLX,rwɹehJv16Du0lO , A%sC6y|@6EuvWUn&Ν… R)Ű8ضgu\ysΕ>hX,GB4(qq N+"F[}m;ǩC 8vO~5fI$ &''W6j*rؿ&ټf06mbǎ BSSvFl:A6T6CxGMM Pt]'ˑJ8z(åi)%4B.ZyoC.+0X'I&iBKh[*ȣl$-[,laN8ih"r2 Cy9rM+2F}ڻb+\&\bviχ뺄B!t],w*7 Xj"Cƹxz( ``޽8Õ+W/cۺu+XCu/\-[Hʀg x~v.Y/D Jn9i8C]kǙUHMMKfU{wux_4I&355E8&TPS>wTi{=ffBຮRy.dZFgKƥݐ@ m{=iadDHz駹{hkk`ӦM<BaH:::fLMy_Z36eeU$I{y8bt:M}}u]|>aP(*$ Xlir9e7퇤Q0 x<\!2z:``0&ZfVWWG0Dܜ}XR<ӤR)kkkhٳgٻw/<`P͖Lsr'V2!O'&&*$E>{5BK/SOQ[[%$jOR0$ϓNSy)9(JʚW 8sssaA6l(x{lƲ,.\P_=pq5RF nΞ=&( W3\\"miK!cUb&aN9~8@I0Nos0j)8@&|>|D"AP!###}*W",#LMF/=3gp̙5._WS!LuIodff<Ha}iinn477ԎIlVm}+7zdŧQFyEQ۶蠳" mxvAr0R-q<*T^7Xu{]T,'ew}݈OgS~_n+ɓabKGD pHYs  #utIME IDATx}yeY߯wyׯez==cĀ VD 1QHQ K"e!#FaR6PgP"1811w={U}ns޷p׺}uVWV_}<<<<<<<<<<7?i^a(+RuTRBضiQDg~wAbys:iW_=Źj T:fD@C,K^ӶԻpmYjѩ>5< |,sq@.6xکD$g~ @WOWreGh7X ; "(g:|ğ3*8 ۣ|OuJ npϻ{/y4ߛq30t-w&$-3Pue;T Cx.g0c,h)0n-yOK%m)5Z{v)%ߤ71ϳ$~$@ݨt|Hf`u0>\|V&R@xΜ=u?P"F1=/ įc`o0Ujye۠jxg yU0\w]t8H"ljt^ݨu~,+Yf|XVK7\BDR@"!{&a_"JVD>| %;댾cyLcaԨ#j~SEyrp<ˣ$NDK@7HZ@ zrǴ6eBD6(*q7Ǖa_`|cqeY[4~3cgۄy7ڹm-X ƚLAKʄ/Dm0.&$y|C$q8`۶\mxno:șR/Fv+MWR=dIم; )As*3⿬!yY6fW lנS@R̸(/CG%6)(Q$&ɏ&N4%,M mԋJ0n4%8c`4hY"R7<8 H"nĽԵF)νs/t8v53]X3.1,[\*cD@XgN tN.$y:J:c Ne}MƞwF} uptos֍=pZK1u$_ Eqh29h;\ND`zVi?{S,&vVд)(1=@Vfa[-ת56MB.c%0pAR%JTJi||###±' g1SApYӖu.Т߀Vo@$CH$D4PRni鎖4&x}T͜0j߶mB?ti3;TO[Ҳ.Jݸ U?~:2GRlb8| cЃeBB~Z1{*8+ BK3]4~y׮|'nrO' J j|@H) TJn!rTm,JR˳>1Y֢9s7Xl۽yOtNgET~_w5M"i??@n#D)ènoӲCƔ)k"0^ fUvs-ǂ3q,r|k);mWG{UBH0 lA)ΘꠄȒ흇k emn06kY {W<[B^ *$O%Qg|7s=PgHk=S` } L-eYK( MbL2S%9#(Է)0 ͱ_7\Cs@/?frrHM oKFkŶmB *5+3(Z^nue H S f_$DŽ}8N&a [.%7|M9ne;3t1hh7k~WmQUDnIZdtQwm"PR5] &LA($X;R l1 N 5pK΄؈cLrϊ(0\dJJ[QкQ,e-˲ێ}8K&2i =30he ޲mtЉgy)]+# ]DP(SJm* 0O7ˉl)0?3c@ :`hB}L n< ]DޏnlA@HDjb˵m7|d/3lF1+}qbF=yj_7(lBDp6?iWr%ϩ=RkVJDTGx4<2> 1kc/3ÔKKK70|eY-n@3飹'>"XKm'EҌ^?&EҴ$C)( =-a="-v󼧵Ī5Lu*87ܶm N0_Tߓ=)0uq^@HIr,0)gl?<{=?qK9Om:sǶmN6hysSd|_-DIJDvM,*f (3CمնmnY mۦY@r'@Scۯ\n4q[D~ԩ'7{${c/G`J hb]]Y'b_݆\q]wEqE|3h(ute)4=BC4MhR.r}_/|so3󆀤j٢V\,C@37/l/exJX=/1hc,VjKJ9L_ \ l:X*=$ʘ e?m5#h8?-~Kvs2\ӯMݹ|缸|}_ wRhz} MBuZǢOU6#4݅N+`1IA:R'(ܒҿ.r6΋7l*q:Aehñ <؉V,^-c$vl~+ݫ?]\y" 40 " ̒!<짠]o2Kz Vo8%.fY)+8Z'i">bYR}t'՟YE3;N+@ϻ ƭ^亭m)1 C` oŎ'Yn3-8,hٶssK[g~7nR%fLf6f۲iilbǓ2ȿqݵӔ$VhZ6~iO/-i8#m%aCRFu>Cm9v7,;,!`÷x8ƹeрB|He`ɌfMr=*Tn2ʑ21e7ڊ,|h]EF4X1d  )@HFu&m2˟&G$KGt*s|!X\x[Y1{Q̭%L}='r'F_&x]VI?rV5m81"[p ?RezG8`Û̬2WL-0:_*|ܬ+oޅ^CqQ@/y23p8lJ}+eߴ26 ^? }>panm{J)waSJHp #كh>g+?#l ^/>?0_T|n?mE(ic,2Bc2|8IH+m%-[u.3Zu˴1tL5%#y͠y-H1VKv  2W/34lWo5ZWFA?Wխڦqpӌ'>c5}nI&%dace_J˳~cu'/3;'[jU а|/7gj8EP!B ^V} a\,.&74h6m+ЙL=;C2@3FLo\O|+5H#F t7 ey6{ =R`6tPȇ&\ۿy%`P#cnFy I)_5ʝlDwwOh4p3MuϢ7|x^pjln5yM4Ž?7~UvKI/3l](/M 6IE^#:{;qIRs;n|o-iuXFkayClxT㊒Ve?4aANj>$#yN,.KF_214R @x4My;:PF}Cre^ñeE1E0~/o`t`  vy"_/"a]3D}z3"a ̥#mƅ78Rvt޿֣_Ld9@}"zND&hKՠ/>Y6mִN5{A` %<ԑK<-~F"@N1+ǖ=0{TIB><վʽ_^}D6k{sѱRm:&ࠁ̳A~#ۛGI"b/8A*fMh@H!AYn,CnjzX'\zއ_Qm4 ,x2~1nJΛMܑ3@zjl&2\UYIa]04.2ȗvt\e4:D Sҧ\Y<7 \*\<Ϫվ2%J7^~-Ou,*v\u?h/*}6n}y>P/W8_dY*%3O?tmO--  +Ho +~0ϲRbip~>5jӤL ĸRyYn4ዌwo5b Y_&vV^E4;9dU\w.9Y{֥}'[nxRKz7/sa#u~KOΊ8Y= /+7Wߪ&@?[a/hB$EH}TD~/&G1umӅ_k4 1D_{oTG(8p_ɜɹ ljl ;>߇:@Ae&dW d UB.JDt^zh]0˛JuNTEtx5Zt_Jݖ Kz3w(S} kZRiEqwؼN1ZoN .*@IBJsnc %> F R덾·cS"!1ƌtmtьbeϔw`۪QL_@'r^&7n|}ӜQ u~}V۬oV5;dLK.ʻj7W/Ŭah"0Fx9Ȳ]ӦR#dw67R7 Giih ƇO*=FV_@$(_h AGހ5itr-Ìڃs{oJ:I_K% t_aUޞ PLᎍ>V|U^;@Ȑ#+XpŪEh볊EϨBf6>$]'&> !)C"%-"2iSt04/_>m/8([|L(I 7U^o8u6鎇SH%!)̯Nу5'Wb->zMvM_9=ʊ]4t2l:zRDe} υ CD BB30ELQIO@i "$ mPrn4&0K ^l{ysgRԜ!DiC"QP,˭`V6C(r铙úlG B;XbP !z|/  I,/`ꗽQg(d mlb H))YD#C֬ˮkfeGJѫ-XM0($i9HU?~r9%c+{v\)^@A?\|[^$h_qEKյJę ^Y3nm㑼C }AD#"JDҩ>+WOmJшF/^dKp?{! h Ub#EtCo@)MDҁ ߓi7F7"K6|ր Zz`hȑ!AD#Q(u_7TОPPDYJ?wl+͠ i xh 6Լq2AAAB Cqx0 P)zHDcuX1 FwnK)T/ Š8sM `YX 8 <(!B0Ei*h*ܸ}Sw/ y>ekZgvҦg5Q@$g"!d0DZ""z@&f=ؾ;uk< Mo6N]t~F nna4^;ح9)L4Or~4ceYVA0u RRc@TVRR*:ƺ ` ^p`,8,nM#~]&B:.fQ~ox w]wy@/xֲ쫖q~_ 99$DiFfm[gI6\}E"Z2: H"Q %܌ c9jM}e;k}="ڔR^@Df̌13=-te6[gƟ'뢜 TBXV,?>k:@RXgfQ '3yp\3o #M#<12hf @ݬI2Ŭ` {3ʬPf^䕍wXf(;)削x@S=pq%gO,FIqR_F%к{*nmPQiQL@4TB5RdTZea?A{@Awj=nv4*O-\CCOR༻`%*Tsx '{U{EYkw_!1ydJꡈ|Itw=Z0(!_j#K/ZvsaFDWXsɗ-8/R3m9L(V+ pr6ͅ_X(Wtwg7)GIENDB`amide-1.0.6/amide-current/win32/amide_logo32x32.png000066400000000000000000000033171423227705100216140ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  #utIME1Ov\IDATx]lW쇽^qj;mFBB-U*QT(P!'$x^PT $D_*/дPPR僘IkZ{zfgg̚Mdiwus͙s^:rKiCTki47Rzohio^ nltzGxS?en h' &FS@^0lYM6jc]z^5{JY~7%k-zd 8@|~8[p6ZdsTjpv:9(Jm`DEp,BDJI4Uo~b˯~08Xq76Ƙ[J: I5*իf~d/bߓw zr""ER5ou[pdnA(4ZW sgBQOzrMGVj ! E[wƦ/~T}V=y /Z_8v'Щ)z2\nz[f{_#cL hXk8_*(,J,J ll-ҢX*"m6w8@ziQ+A}|1@@{ˏ=:< lOPr~@PpǷŏ# jЁXzƻƘ:q8vr̯ā2?ʻ}r+N!ϥZk\3(dZT(N[XxaIE%9.?LWR&!@QHo\.2eƻCQ%)A/NɎXh7^鶳n |Q:~8*((VQZ(a׌L$`~lO6䁥N3+ZD'u5۰73a()|2Ըّz=MV]TDELo^įdHa!:F&Js{SQ>rNQ_UoߜU`y#s?DhowެoIHÇ~;٬/aW .v( Wt=wcG3Ͻ\XoDl9!`0q؎lD.&$~ A1@1LB^Dcb;q"y9^;;;sVUӳ3XP3OUk5G{ 8HuWV*88т&>l$ F]nO~нil>dipw_hq D(@'U&Eɫ!!9vx~csUs U0 n ֑t>/Ws46ͭ:1̃aJ`i{I駵v ])q_=ul!N줏d@S;zwٻ1-J1eJ߉lLRAr˕q]w) ßai4>:ˆ}UlYb X=P* Ɲ^4Pjs"BR)I]ggYQĶ&˵=mǁXݝ2LǎkDGj/XĀc$3Lm̥@a`!J5Nw㼔`M;օ~;Kf t{L*+a4p*N)=a~= 5y {{F6}o}VUyCU-YUK%&l@`e@# %Xvq6a| VAy` cO=41P2++J%B9fA! JiYp+P+%HM$7-y֓R.bL"`69` jщQbmU fI < Y/?VbqGr(8^Li 6Fvo}뾛߶ ^NH\9 rY?{VkHg`[aR2+1:^xyf-,QgKG;`f\ ;JmL86ޟP"v>cZWvReGp̒n t< c+u L3O+h_fg>9sTmnFZ+(-A)Њ0s~) b誁<{0Yg8+W;iz >_Y ?!$6 4~βnBB'.iTAdBk4ZE&9K׸Dy|P{S֖7O)˂.ft_σ%P":LkZ0Is>;bPBut~܆IS}K%3I&2;Wdd+rخlta=YgR*M Yжd4Gb"3MqJ a?^-U1?:|nmG'c[57xΘ"?1f?ꐱ>Ɩf>;f 2j<ۧcOT*q!D5ޗg86i,n19'_ʰb< }6IaN&+]6'_]:c@Mhdfi9z}RS+~#YLP)L*A\0%hox1-=Ôy4B#5A9#f.z!@͞s=[g19R}7կwRwGTOr iЍq#wM<߱")c'5C"1AklUJjuLmGC[(@C:}ZZءI)y;1WL]}=Y/l6߈x*7prIV~z~j-DRj5ya;?64NR3o0g 9nOq]w6Yn}T,50t˳Ѽ9q Iy=\s`QH%?;9S=]:9P6|oVP:a9 ba_/p;(j aהj7&:}U KlςcgSF.eqºk2z@%q"˫v=q:boK罙ӟ4, #u\d (VyB0?*Vn(ɿ@?} -&ǡ9B$Dr(e١#rofP+/m?"ז{ SJU]"2RZ= JƙO}|r@k7˟ًy/Zg*Vk]aJ5Yw:cn./rGz*[@FG\ ZES`6d3"|Zo q牎܃>X |(#y. 2R &TJ9"9vQ$y] $̄\܆wΚW Z9O rɘYeI\ $&K~IǻCf!F ;>˞h$m}g|x cF ;WpԖ&R dSN|(p/Pt1=ARJ-Ä? C\lE EU89q@ephi4U[@k1%Pᣝ 8P~I#쿥bv1Gf ź׍zqݹ1ݟ+/qqNGQtUk&?@[GEJ Rk?㠐tܵ3Q]`~ zǦs3cNo{%Fj;W3p-H4]\8pTUki<|ZqZQ(.fMq]. -n'КꢔLJ$iwn<{Ɂy.1?7=?/O`F"uZuc0 d@ke'dŽ^0T*0pmE R}QxtHUw z{uJ2FW(U~)].ogA!i9DS!=oa?c$ES/͞Ÿ _]FOIENDB`amide-1.0.6/amide-current/win32/amiderc.rc000066400000000000000000000001331423227705100202300ustar00rootroot00000000000000#include "resource.h" AMIDE_ICON ICON "amide.ico" AMIDE_FILE_ICON ICON "amide_file.ico" amide-1.0.6/amide-current/win32/resource.h000066400000000000000000000000631423227705100203000ustar00rootroot00000000000000#define AMIDE_ICON 104 #define AMIDE_FILE_ICON 105